dandi
Version:
A JavaScript API for the Distributed Archives for Neurophysiology Data Integration (DANDI)
222 lines (221 loc) • 7.96 kB
JavaScript
var L = (s, t, e) => {
if (!t.has(s))
throw TypeError("Cannot " + e);
};
var a = (s, t, e) => (L(s, t, "read from private field"), e ? e.call(s) : t.get(s)), c = (s, t, e) => {
if (t.has(s))
throw TypeError("Cannot add the same private member more than once");
t instanceof WeakSet ? t.add(s) : t.set(s, e);
}, h = (s, t, e, i) => (L(s, t, "write to private field"), i ? i.call(s, e) : t.set(s, e), e);
const D = {
main: "api.dandiarchive.org",
staging: "api-staging.dandiarchive.org"
}, S = async (s, t) => {
var i, n, r;
const e = await k(s, t);
if (e) {
const o = (i = e.most_recent_published_version) == null ? void 0 : i.version;
if (o)
return o;
if (((n = e.draft_version) == null ? void 0 : n.status) === "Valid")
return (r = e.draft_version) == null ? void 0 : r.version;
} else
return null;
}, z = (s) => typeof s == "string" ? D[s] : D.main, N = (s, t) => (s.startsWith("http") && new URL(s), new URL(s, `https://${z(t)}/api/`)), p = (s, t) => b(s, { options: t }), P = (s) => `dandisets/${s}`, U = (s) => {
var t;
return `dandisets/${s.dandiset}/versions/${((t = s.options) == null ? void 0 : t.version) || "draft"}/assets/${s.id}`;
}, k = (s, t) => p(P(s), t), R = (s, t = {}) => `${P(s)}/versions/${t != null && t.version ? t.version : "draft"}`, q = async (s, t = {}) => {
const e = t.version ?? await S(s, t);
if (e)
return p(R(s, { ...t, version: e }), t);
}, O = async (s, t) => {
const e = [];
if (s.results && e.push(...s.results), s.next) {
const i = await p(s.next, t);
e.push(...await O(i, t));
}
return e;
}, H = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
getAssetUrl: U,
getBase: k,
getDandisetURL: P,
getInfo: q,
getInfoURL: R,
getInstance: z,
getJSON: p,
getLatestVersion: S,
getURL: N,
paginate: O
}, Symbol.toStringTag, { value: "Module" })), C = (s) => {
const t = {
accept: "application/json",
"Content-Type": "application/json"
};
return s && (t.Authorization = `token ${s}`), t;
}, b = async (s, t) => {
const { options: e = {} } = t, i = N(s, e.type), n = { ...C(e.token), ...t.headers ?? {} };
if (t.method && t.method !== "GET") {
const r = t.body || JSON.stringify(t.json ?? {});
if (!e.token)
throw new Error("No DANDI API token provided.");
return await fetch(i, {
method: t.method,
headers: n,
body: r
}).then((o) => {
if (o.ok)
return o.json();
throw new Error(`Request failed with status code ${o.status}`);
}).catch((o) => (o instanceof TypeError && console.error("[dandi]: Backend does not have CORS enabled for POST / PUT requests..."), null));
} else
return await fetch(i, { headers: n }).then((r) => r.json());
};
var l, f, m, w;
class V {
constructor(t, e, i = {}) {
// WE ASSUME THIS IS ALREADY HERE, THOUGH IT ISN'T WITH POINTERS
c(this, l, void 0);
c(this, f, void 0);
c(this, m, void 0);
c(this, w, void 0);
h(this, m, (r) => {
Object.assign(this, r), this.asset_id = r.asset_id;
}), h(this, w, () => ({
id: this.asset_id,
dandiset: a(this, f),
options: a(this, l)
})), this.update = async (r = {}) => {
const o = Object.assign(Object.assign({}, this.metadata), r), y = a(this, w).call(this), E = this.zarr ? { zarr_id: this.zarr } : { blob_id: this.blob }, A = await b(
U(y),
{
options: a(this, l),
method: "PUT",
body: JSON.stringify({ metadata: o, ...E })
}
);
return Object.assign(this, A), A;
};
const n = e && typeof e == "object" && !(e instanceof String);
n && a(this, m).call(this, e), this.asset_id = n ? this.asset_id = e.asset_id : e, h(this, l, i), h(this, f, t);
}
async get(t = a(this, f), e = this.asset_id, i = a(this, l)) {
h(this, f, t), h(this, l, i), this.asset_id = e;
const n = await T(a(this, w).call(this));
return n && Object.assign(this, n), n;
}
}
l = new WeakMap(), f = new WeakMap(), m = new WeakMap(), w = new WeakMap();
const T = async (s) => {
const t = await b(`${U(s)}/info`, { options: s.options });
return new V(s.dandiset, t, s.options);
};
var v, g, u, _, d, $;
class I {
constructor(t, e) {
// Hidden properties fetched asynchronously
c(this, v, {});
c(this, g, {});
c(this, u, {});
c(this, _, !1);
c(this, d, {});
c(this, $, (t) => {
h(this, v, t), Object.assign(this, t), this.identifier = t.identifier;
});
const i = t && typeof t == "object" && !(t instanceof String);
i && a(this, $).call(this, t), this.identifier = i ? t.identifier : t, h(this, d, e);
}
// GET Fetch Calls
async get(t = this.identifier) {
if (t !== this.identifier) {
this.identifier = t, h(this, g, {}), h(this, u, {});
const e = await k(this.identifier, a(this, d));
e && Object.assign(this, e);
}
return a(this, v);
}
async getInfo(t = a(this, d)) {
return t = { ...a(this, d), ...t }, Object.keys(a(this, g)).length === 0 && h(this, g, await q(this.identifier, t)), a(this, g);
}
async getAsset(t, e = a(this, d)) {
return e = { ...a(this, d), ...e }, a(this, u)[t] || (a(this, u)[t] = await T({
dandiset: this.identifier,
id: t,
options: e
})), a(this, u)[t];
}
async getAssets(t = a(this, d)) {
if (!a(this, _)) {
const e = await B({
dandiset: this.identifier,
options: t
});
e == null || e.forEach((i) => a(this, u)[i.asset_id] = i), h(this, _, !0);
}
return a(this, u);
}
}
v = new WeakMap(), g = new WeakMap(), u = new WeakMap(), _ = new WeakMap(), d = new WeakMap(), $ = new WeakMap();
const x = (s, t = {}) => `${R(s, t)}/assets`, B = async (s) => {
const t = typeof s == "string" ? { dandiset: s } : s;
let e;
const i = t.dandiset;
"options" in t ? e = t.options : e = {};
const n = e.version ?? await S(i, e);
if (n) {
const r = `${x(i, { ...e, version: n })}`, o = await p(r, e);
return await Promise.all((await O(o, e)).map(async (y) => T({ dandiset: i, options: e, id: y.asset_id })));
}
}, W = async (s = {}) => {
const t = `https://${z(s.type)}/api/dandisets`, e = await p(t, s);
return (await O(e, s)).map((n) => new I(n, s));
}, J = async (s, t = {}) => {
const e = await k(s, t);
return e ? new I(e, t) : null;
}, F = async (s = {}, t = {}) => {
const { draft: e = !0, empty: i = !0, embargoed: n = !1 } = t, r = new URLSearchParams();
r.append("user", "me"), r.append("draft", e ? "true" : "false"), r.append("empty", i ? "true" : "false"), r.append("embargoed", n ? "true" : "false");
const o = `dandisets?${r.toString()}`, y = await b(o, { options: s });
return (await O(y, s)).map((A) => new I(A, s));
};
var j;
class K {
constructor({ token: t, type: e = "main" }) {
c(this, j, void 0);
this.authorized = !1, h(this, j, () => {
if (!this.authorized)
throw new Error("API is not authorized. Please provide a valid token.");
}), this.get = async (i, n = {}) => J(i, { ...n, ...this }), this.create = async (i, n = {}, r = !1) => {
a(this, j).call(this);
const o = await b(`dandisets/?embargo=${r}`, {
options: this,
method: "POST",
json: { name: i, metadata: n }
});
if (o.detail)
throw new Error(o.detail);
return this.get(o.identifier);
}, this.authorize = async (i = this.token) => {
const n = await M({
token: i,
type: this.type
}).catch((r) => (console.error(r), !1));
return this.token = i, this.authorized = n;
}, this.token = t, this.type = e;
}
}
j = new WeakMap();
const M = async (s) => b("auth/token", { options: s });
export {
K as API,
V as Asset,
I as Dandiset,
J as get,
W as getAll,
T as getAsset,
B as getAssets,
x as getAssetsUrl,
F as getMine,
H as utils,
M as validateToken
};