@aiquants/markdown-explorer 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/README.md +53 -16
  3. package/dist/{ExplorerSplit-DwEFmvQM.js → ExplorerSplit-B7pmzR8t.js} +3 -3
  4. package/dist/{ExplorerSplit-BESGFcu6.cjs → ExplorerSplit-Bi3yU6NG.cjs} +1 -1
  5. package/dist/MultiLayout-BxeXOLX1.js +909 -0
  6. package/dist/MultiLayout-DtFrFRmS.cjs +1 -0
  7. package/dist/TreeLayout-BQUfVNlA.cjs +1 -0
  8. package/dist/TreeLayout-D6hCSihW.js +22 -0
  9. package/dist/core/config.d.cts +8 -0
  10. package/dist/core/config.d.ts +8 -0
  11. package/dist/core/labels.d.cts +6 -1
  12. package/dist/core/labels.d.ts +6 -1
  13. package/dist/{dataRoute-CKbdwkQ7.cjs → dataRoute-B9Wk-G7A.cjs} +1 -1
  14. package/dist/{dataRoute-Bkfwfp1R.js → dataRoute-zUX-oR9j.js} +39 -38
  15. package/dist/{index-BgkZ9ATV.js → index-BJTmp0lR.js} +947 -901
  16. package/dist/index-DkiGlM7C.cjs +3 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.js +13 -13
  19. package/dist/location-DfYTzfFS.cjs +1 -0
  20. package/dist/{location-Cb2Ak55B.js → location-V5BKeWNs.js} +189 -162
  21. package/dist/sanitizeWorker.cjs +1 -1
  22. package/dist/sanitizeWorker.js +196 -206
  23. package/dist/server/anonymous.d.cts +2 -2
  24. package/dist/server/anonymous.d.ts +2 -2
  25. package/dist/server/ports.d.cts +4 -1
  26. package/dist/server/ports.d.ts +4 -1
  27. package/dist/server.cjs +1 -1
  28. package/dist/server.d.cts +1 -1
  29. package/dist/server.d.ts +1 -1
  30. package/dist/server.js +631 -603
  31. package/dist/styles/markdown-explorer.css +1 -1
  32. package/docs/behavior/dom-hooks.md +4 -4
  33. package/docs/behavior/layout.md +21 -9
  34. package/docs/behavior/localization.md +4 -3
  35. package/docs/behavior/security.md +23 -5
  36. package/docs/behavior/url-contract.md +8 -2
  37. package/package.json +5 -5
  38. package/dist/MultiLayout-DxPiARsv.js +0 -896
  39. package/dist/MultiLayout-r_qx1Mfz.cjs +0 -1
  40. package/dist/TreeLayout-9-20bbSM.cjs +0 -1
  41. package/dist/TreeLayout-CW7lgV_e.js +0 -19
  42. package/dist/index-y9tVvDW7.cjs +0 -3
  43. package/dist/location-DWHQYntR.cjs +0 -1
package/dist/server.js CHANGED
@@ -1,19 +1,20 @@
1
- import { a as et, b as Et, f as Re, c as yt, d as bt, g as St, h as Tt, E as xt, j as Ot, i as te, k as kt, r as tt, l as Rt, m as _t, n as rt, o as Nt, p as At, q as de, s as ee, e as It } from "./dataRoute-Bkfwfp1R.js";
2
- import { D as Qn, M as qn, t as eo } from "./dataRoute-Bkfwfp1R.js";
3
- import { createHash as Mt, createHmac as Pt } from "node:crypto";
4
- import { data as Ie, redirect as vt } from "react-router";
5
- import { w as $t, d as jt, a as Lt, i as zt, r as Dt, p as Ct, b as Ht, f as Bt, N as Ft } from "./location-Cb2Ak55B.js";
6
- import { existsSync as Ut, statSync as Gt, realpathSync as Xt, constants as ce } from "node:fs";
7
- import { extname as Jt, isAbsolute as Me, relative as Pe, sep as ve, join as Wt, resolve as Yt } from "node:path";
1
+ import { b as it, c as _t, f as Re, d as Nt, g as At, h as It, j as Mt, E as vt, k as Pt, i as te, l as $t, r as ct, m as jt, n as Lt, o as ut, p as zt, q as Ct, s as de, t as ee, e as Dt } from "./dataRoute-zUX-oR9j.js";
2
+ import { D as lo, M as fo, u as mo } from "./dataRoute-zUX-oR9j.js";
3
+ import { createHash as Ht, createHmac as Bt } from "node:crypto";
4
+ import { createLinkCardHandler as Ft } from "@aiquants/markdown/server";
5
+ import { data as Pe, redirect as Ut } from "react-router";
6
+ import { w as Xt, d as Gt, r as Jt, i as Wt, a as Yt, p as Kt, b as Vt, f as Zt, N as Qt } from "./location-V5BKeWNs.js";
7
+ import { existsSync as qt, statSync as er, realpathSync as tr, constants as ie } from "node:fs";
8
+ import { extname as rr, isAbsolute as $e, relative as je, sep as Le, join as nr, resolve as or } from "node:path";
8
9
  import { fileURLToPath as be } from "node:url";
9
- import { Worker as Kt } from "node:worker_threads";
10
- import { open as nt, lstat as Vt, realpath as Zt, readdir as Qt } from "node:fs/promises";
11
- import { Readable as qt } from "node:stream";
12
- const $e = Object.freeze({ kind: "anonymous" }), Wn = Object.freeze({
13
- authenticate: async () => ({ status: "signed-in", principal: $e }),
14
- principalKey: () => $e.kind,
10
+ import { Worker as sr } from "node:worker_threads";
11
+ import { open as lt, lstat as ar, realpath as ir, readdir as cr } from "node:fs/promises";
12
+ import { Readable as ur } from "node:stream";
13
+ const ze = Object.freeze({ kind: "anonymous" }), so = Object.freeze({
14
+ authenticate: async () => ({ status: "signed-in", principal: ze }),
15
+ principalKey: () => ze.kind,
15
16
  signedOutPage: (e, t) => new Response(null, { status: 401, headers: t })
16
- }), er = "application/octet-stream", ot = "application/pdf", tr = /* @__PURE__ */ new Set([
17
+ }), lr = "application/octet-stream", dt = "application/pdf", dr = /* @__PURE__ */ new Set([
17
18
  "image/png",
18
19
  "image/apng",
19
20
  "image/jpeg",
@@ -39,158 +40,158 @@ const $e = Object.freeze({ kind: "anonymous" }), Wn = Object.freeze({
39
40
  "video/webm",
40
41
  "video/ogg",
41
42
  "video/quicktime",
42
- ot
43
- ]), st = "default-src 'none'; media-src 'self'; style-src 'unsafe-inline'", rr = `${st}; sandbox`, nr = `${st}; sandbox allow-same-origin`, je = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/u, or = /^[\t\n\r ]+|[\t\n\r ]+$/gu, _e = /^[\t ]+|[\t ]+$/gu, sr = (e) => {
43
+ dt
44
+ ]), ft = "default-src 'none'; media-src 'self'; style-src 'unsafe-inline'", fr = `${ft}; sandbox`, mr = `${ft}; sandbox allow-same-origin`, Ce = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/u, pr = /^[\t\n\r ]+|[\t\n\r ]+$/gu, _e = /^[\t ]+|[\t ]+$/gu, wr = (e) => {
44
45
  const t = [];
45
46
  let r = "", n = 0;
46
47
  for (; ; ) {
47
48
  for (; n < e.length && e[n] !== '"' && e[n] !== ","; )
48
49
  r += e[n], n += 1;
49
50
  if (n < e.length && e[n] === '"') {
50
- const s = n;
51
+ const a = n;
51
52
  for (n += 1; n < e.length && e[n] !== '"'; )
52
53
  n += e[n] === "\\" ? 2 : 1;
53
- if (n = Math.min(n + 1, e.length), r += e.slice(s, n), n < e.length) continue;
54
+ if (n = Math.min(n + 1, e.length), r += e.slice(a, n), n < e.length) continue;
54
55
  }
55
56
  if (t.push(r.replace(_e, "")), r = "", n >= e.length) return t;
56
57
  n += 1;
57
58
  }
58
- }, ir = (e) => {
59
- const t = e.replace(or, ""), r = t.indexOf("/");
59
+ }, hr = (e) => {
60
+ const t = e.replace(pr, ""), r = t.indexOf("/");
60
61
  if (r < 0) return null;
61
- const n = t.slice(0, r), s = t.indexOf(";", r + 1), o = t.slice(r + 1, s < 0 ? t.length : s).replace(/[\t\n\r ]+$/u, "");
62
- return je.test(n) && je.test(o) ? `${n}/${o}`.toLowerCase() : null;
63
- }, ar = (e) => {
62
+ const n = t.slice(0, r), a = t.indexOf(";", r + 1), o = t.slice(r + 1, a < 0 ? t.length : a).replace(/[\t\n\r ]+$/u, "");
63
+ return Ce.test(n) && Ce.test(o) ? `${n}/${o}`.toLowerCase() : null;
64
+ }, gr = (e) => {
64
65
  let t = null;
65
- for (const r of sr(e)) {
66
- const n = ir(r);
66
+ for (const r of wr(e)) {
67
+ const n = hr(r);
67
68
  n !== null && n !== "*/*" && (t = n);
68
69
  }
69
70
  return t;
70
- }, cr = /['()*]/gu, ur = (e) => encodeURIComponent(e).replace(cr, (t) => `%${t.charCodeAt(0).toString(16).toUpperCase()}`), lr = Object.freeze({
71
+ }, Er = /['()*]/gu, yr = (e) => encodeURIComponent(e).replace(Er, (t) => `%${t.charCodeAt(0).toString(16).toUpperCase()}`), br = Object.freeze({
71
72
  "Cache-Control": "private, max-age=60, stale-while-revalidate=600, no-transform",
72
73
  Vary: "Cookie"
73
- }), dr = (e, t) => {
74
- const r = ar(e), n = r !== null && tr.has(r), s = n && (r.startsWith("audio/") || r.startsWith("video/"));
74
+ }), Sr = (e, t) => {
75
+ const r = gr(e), n = r !== null && dr.has(r), a = n && (r.startsWith("audio/") || r.startsWith("video/"));
75
76
  return {
76
- contentType: r === null ? er : r,
77
+ contentType: r === null ? lr : r,
77
78
  inline: n,
78
79
  headers: {
79
80
  "X-Content-Type-Options": "nosniff",
80
- "Content-Disposition": `${n ? "inline" : "attachment"}; filename*=UTF-8''${ur(t)}`,
81
- ...r === ot ? {} : { "Content-Security-Policy": s ? nr : rr },
81
+ "Content-Disposition": `${n ? "inline" : "attachment"}; filename*=UTF-8''${yr(t)}`,
82
+ ...r === dt ? {} : { "Content-Security-Policy": a ? mr : fr },
82
83
  "Cross-Origin-Resource-Policy": "same-origin"
83
84
  }
84
85
  };
85
- }, fr = /^bytes=(?:(\d+)-(\d*)|-(\d+))$/iu, fe = Object.freeze({ kind: "whole" }), Le = Object.freeze({ kind: "unsatisfiable" }), mr = (e, t, r) => {
86
+ }, Tr = /^bytes=(?:(\d+)-(\d*)|-(\d+))$/iu, fe = Object.freeze({ kind: "whole" }), De = Object.freeze({ kind: "unsatisfiable" }), xr = (e, t, r) => {
86
87
  const n = e.get("Range");
87
88
  if (n === null) return fe;
88
- const s = e.get("If-Range");
89
- if (s !== null && s !== r) return fe;
90
- const o = fr.exec(n);
89
+ const a = e.get("If-Range");
90
+ if (a !== null && a !== r) return fe;
91
+ const o = Tr.exec(n);
91
92
  if (o === null) return fe;
92
- const [, c, m, g] = o;
93
+ const [, c, f, g] = o;
93
94
  if (g !== void 0) {
94
- const w = Number(g);
95
- if (w === 0) return Le;
96
- const _ = Math.max(0, t - w);
95
+ const p = Number(g);
96
+ if (p === 0) return De;
97
+ const _ = Math.max(0, t - p);
97
98
  return { kind: "partial", range: { offset: _, length: t - _ } };
98
99
  }
99
- const T = Number(c), l = m === "" ? Number.POSITIVE_INFINITY : Number(m);
100
- return l < T ? fe : T >= t ? Le : { kind: "partial", range: { offset: T, length: Math.min(l, t - 1) - T + 1 } };
101
- }, ze = "W/", pr = (e) => {
100
+ const T = Number(c), d = f === "" ? Number.POSITIVE_INFINITY : Number(f);
101
+ return d < T ? fe : T >= t ? De : { kind: "partial", range: { offset: T, length: Math.min(d, t - 1) - T + 1 } };
102
+ }, He = "W/", Or = (e) => {
102
103
  const t = [];
103
104
  let r = 0, n = !1;
104
- for (let s = 0; s < e.length; s += 1)
105
- e[s] === '"' ? n = !n : e[s] === "," && !n && (t.push(e.slice(r, s).replace(_e, "")), r = s + 1);
105
+ for (let a = 0; a < e.length; a += 1)
106
+ e[a] === '"' ? n = !n : e[a] === "," && !n && (t.push(e.slice(r, a).replace(_e, "")), r = a + 1);
106
107
  return t.push(e.slice(r).replace(_e, "")), t;
107
- }, De = (e) => e.startsWith(ze) ? e.slice(ze.length) : e, wr = (e, t) => {
108
+ }, Be = (e) => e.startsWith(He) ? e.slice(He.length) : e, kr = (e, t) => {
108
109
  if (e === null) return !1;
109
- const r = pr(e);
110
+ const r = Or(e);
110
111
  if (r.length === 1 && r[0] === "*") return !0;
111
- const n = De(t);
112
- return r.some((s) => De(s) === n);
113
- }, hr = (e, t) => {
112
+ const n = Be(t);
113
+ return r.some((a) => Be(a) === n);
114
+ }, Rr = (e, t) => {
114
115
  let r = t;
115
116
  return e.pipeThrough(
116
117
  new TransformStream({
117
- transform: (n, s) => {
118
+ transform: (n, a) => {
118
119
  const o = n.byteLength > r ? n.subarray(0, r) : n;
119
- r -= o.byteLength, s.enqueue(o), r === 0 && s.terminate();
120
+ r -= o.byteLength, a.enqueue(o), r === 0 && a.terminate();
120
121
  },
121
122
  flush: (n) => {
122
123
  r > 0 && n.error(new RangeError("[markdown-explorer] the asset ended before its declared length"));
123
124
  }
124
125
  })
125
126
  );
126
- }, Se = async (e, t, r, n, s) => {
127
+ }, Se = async (e, t, r, n, a) => {
127
128
  if (n !== null && r.set("Content-Length", String(n)), e.method.toUpperCase() === "HEAD") return new Response(null, { status: t, headers: r });
128
- const o = await s();
129
- return new Response(n === null ? o : hr(o, n), { status: t, headers: r });
130
- }, gr = (e, t) => {
129
+ const o = await a();
130
+ return new Response(n === null ? o : Rr(o, n), { status: t, headers: r });
131
+ }, _r = (e, t) => {
131
132
  const r = new Headers(e);
132
- for (const [n, s] of Object.entries({ "Accept-Ranges": "bytes", "Content-Range": `bytes */${t}`, "Cache-Control": "private, no-store", "X-Content-Type-Options": "nosniff" })) r.set(n, s);
133
+ for (const [n, a] of Object.entries({ "Accept-Ranges": "bytes", "Content-Range": `bytes */${t}`, "Cache-Control": "private, no-store", "X-Content-Type-Options": "nosniff" })) r.set(n, a);
133
134
  return new Response(null, { status: 416, headers: r });
134
- }, Er = async (e, t, r) => {
135
- const n = `"${t.version}"`, s = dr(t.contentType, t.name), o = new Headers(r);
136
- for (const [g, T] of Object.entries({ ...s.headers, ...lr, ETag: n })) o.set(g, T);
137
- if (wr(e.headers.get("If-None-Match"), n)) return new Response(null, { status: 304, headers: o });
138
- if (o.set("Content-Type", s.contentType), t.size === null) return Se(e, 200, o, null, () => t.open(null));
135
+ }, Nr = async (e, t, r) => {
136
+ const n = `"${t.version}"`, a = Sr(t.contentType, t.name), o = new Headers(r);
137
+ for (const [g, T] of Object.entries({ ...a.headers, ...br, ETag: n })) o.set(g, T);
138
+ if (kr(e.headers.get("If-None-Match"), n)) return new Response(null, { status: 304, headers: o });
139
+ if (o.set("Content-Type", a.contentType), t.size === null) return Se(e, 200, o, null, () => t.open(null));
139
140
  if (t.size === 0)
140
141
  return o.set("Content-Length", "0"), new Response(null, { status: 200, headers: o });
141
142
  o.set("Accept-Ranges", "bytes");
142
- const c = mr(e.headers, t.size, n);
143
- if (c.kind === "unsatisfiable") return gr(r, t.size);
143
+ const c = xr(e.headers, t.size, n);
144
+ if (c.kind === "unsatisfiable") return _r(r, t.size);
144
145
  if (c.kind === "whole") return Se(e, 200, o, t.size, () => t.open(null));
145
- const { range: m } = c;
146
- return o.set("Content-Range", `bytes ${m.offset}-${m.offset + m.length - 1}/${t.size}`), Se(e, 206, o, m.length, () => t.open(m));
146
+ const { range: f } = c;
147
+ return o.set("Content-Range", `bytes ${f.offset}-${f.offset + f.length - 1}/${t.size}`), Se(e, 206, o, f.length, () => t.open(f));
147
148
  }, Te = (e, t) => {
148
149
  const r = new AbortController(), n = t(AbortSignal.any([e.signal, r.signal]));
149
- return new Promise((s) => {
150
+ return new Promise((a) => {
150
151
  let o;
151
152
  const c = setTimeout(() => {
152
- s(e.late), o = setTimeout(() => r.abort(), e.handOverMs);
153
- }, e.timeoutMs), m = () => {
153
+ a(e.late), o = setTimeout(() => r.abort(), e.handOverMs);
154
+ }, e.timeoutMs), f = () => {
154
155
  clearTimeout(c), clearTimeout(o);
155
156
  };
156
157
  n.then(
157
158
  (g) => {
158
- m(), s(g);
159
+ f(), a(g);
159
160
  },
160
161
  () => {
161
- m(), s(e.late);
162
+ f(), a(e.late);
162
163
  }
163
164
  );
164
165
  });
165
- }, yr = Object.freeze({
166
+ }, Ar = Object.freeze({
166
167
  error: (e, t) => {
167
168
  console.error(e, t);
168
169
  }
169
- }), it = /* @__PURE__ */ Symbol.for("@aiquants/markdown-explorer:ExplorerError");
170
+ }), mt = /* @__PURE__ */ Symbol.for("@aiquants/markdown-explorer:ExplorerError");
170
171
  class Ee extends Error {
171
172
  reason;
172
173
  code;
173
174
  constructor(t, r = {}) {
174
- if (!et(t)) throw new RangeError(`[markdown-explorer] ExplorerError needs a failure reason; got ${JSON.stringify(t)}`);
175
- if (r.code !== void 0 && !Et(r.code)) throw new RangeError(`[markdown-explorer] an ExplorerError code must be 1 to 64 lowercase letters, digits or hyphens; got ${JSON.stringify(r.code)}`);
176
- super(`[markdown-explorer] ${t}`, r.cause === void 0 ? void 0 : { cause: r.cause }), this.name = "ExplorerError", this.reason = t, this.code = r.code, Object.defineProperty(this, it, { value: !0 });
175
+ if (!it(t)) throw new RangeError(`[markdown-explorer] ExplorerError needs a failure reason; got ${JSON.stringify(t)}`);
176
+ if (r.code !== void 0 && !_t(r.code)) throw new RangeError(`[markdown-explorer] an ExplorerError code must be 1 to 64 lowercase letters, digits or hyphens; got ${JSON.stringify(r.code)}`);
177
+ super(`[markdown-explorer] ${t}`, r.cause === void 0 ? void 0 : { cause: r.cause }), this.name = "ExplorerError", this.reason = t, this.code = r.code, Object.defineProperty(this, mt, { value: !0 });
177
178
  }
178
179
  }
179
- const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr = (e) => typeof e == "object" && e !== null && e.name === "AbortError", Ne = (e, t, r) => {
180
+ const Ir = (e) => e instanceof Error && Object.hasOwn(e, mt) && it(e.reason), Mr = (e) => typeof e == "object" && e !== null && e.name === "AbortError", Ne = (e, t, r) => {
180
181
  try {
181
182
  e.error(t, r);
182
183
  } catch (n) {
183
184
  console.error("[markdown-explorer] the logger threw while reporting a failure", { operation: r.operation, error: n });
184
185
  }
185
- }, q = (e, t) => Ne(e, `[markdown-explorer] ${t.operation} failed`, t), Tr = (e, t) => Ne(e, `[markdown-explorer] ${t.operation} left out an entry`, t), xr = (e, t) => Ne(e, `[markdown-explorer] ${t.operation} refused a path the deny rules match`, { ...t, error: new RangeError("[markdown-explorer] the path matches a deny rule") }), Ce = (e, t) => {
186
+ }, q = (e, t) => Ne(e, `[markdown-explorer] ${t.operation} failed`, t), vr = (e, t) => Ne(e, `[markdown-explorer] ${t.operation} left out an entry`, t), Pr = (e, t) => Ne(e, `[markdown-explorer] ${t.operation} refused a path the deny rules match`, { ...t, error: new RangeError("[markdown-explorer] the path matches a deny rule") }), Fe = (e, t) => {
186
187
  e === null || typeof e != "object" && typeof e != "function" || Promise.resolve(e).then(void 0, t);
187
- }, Q = (e, t, r, n) => br(e) ? Re(e.reason, e.code) : (Sr(e) || r.aborted || q(n, { ...t, error: e }), { reason: "failed" }), He = (e, t) => {
188
+ }, Q = (e, t, r, n) => Ir(e) ? Re(e.reason, e.code) : (Mr(e) || r.aborted || q(n, { ...t, error: e }), { reason: "failed" }), Ue = (e, t) => {
188
189
  if (!Number.isSafeInteger(t) || t <= 0) throw new RangeError(`[markdown-explorer] a cache ${e} must be a positive integer; got ${String(t)}`);
189
- }, at = (e, t) => {
190
- He("capacity", e), t !== void 0 && He("weight budget", t.max);
190
+ }, pt = (e, t) => {
191
+ Ue("capacity", e), t !== void 0 && Ue("weight budget", t.max);
191
192
  const r = /* @__PURE__ */ new Map();
192
193
  let n = 0;
193
- const s = (o) => {
194
+ const a = (o) => {
194
195
  const c = r.get(o);
195
196
  c !== void 0 && (r.delete(o), n -= c.weight);
196
197
  };
@@ -201,415 +202,421 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
201
202
  return r.delete(o), r.set(o, c), c.value;
202
203
  },
203
204
  set: (o, c) => {
204
- s(o);
205
- const m = t === void 0 ? 0 : t.of(o, c);
206
- if (!(t !== void 0 && m > t.max)) {
207
- r.set(o, { value: c, weight: m }), n += m;
205
+ a(o);
206
+ const f = t === void 0 ? 0 : t.of(o, c);
207
+ if (!(t !== void 0 && f > t.max)) {
208
+ r.set(o, { value: c, weight: f }), n += f;
208
209
  for (const g of r.keys()) {
209
210
  if (r.size <= e && (t === void 0 || n <= t.max)) break;
210
- s(g);
211
+ a(g);
211
212
  }
212
213
  }
213
214
  },
214
- delete: s,
215
+ delete: a,
215
216
  size: () => r.size,
216
217
  weight: () => n
217
218
  };
218
- }, ct = (e) => Math.max(1, e - 1), Or = 2147483647, Be = Object.freeze({ status: "aborted" }), ne = (e, t, r) => {
219
+ }, wt = (e) => Math.max(1, e - 1), $r = 2147483647, Xe = Object.freeze({ status: "aborted" }), re = (e, t, r) => {
219
220
  const n = (e.get(t) ?? 0) + r;
220
221
  n === 0 ? e.delete(t) : e.set(t, n);
221
- }, ie = (e, t, r) => {
222
+ }, se = (e, t, r) => {
222
223
  if (!Number.isSafeInteger(t) || t <= 0 || t > r) throw new RangeError(`[markdown-explorer] a worker pool's ${e} must be an integer in 1..${String(r)}; got ${String(t)}`);
223
- }, kr = (e) => e !== null && typeof e == "object" && e.ready === !0 && !("id" in e), Rr = (e, t) => e !== null && typeof e == "object" && e.id === t && "output" in e, _r = ({ url: e, size: t, deadlineMs: r, jobsPerScope: n, maxQueuedJobs: s, heapLimits: o }) => {
224
- ie("size", t, Number.MAX_SAFE_INTEGER), ie("deadline", r, Or), ie("jobsPerScope", n, Number.MAX_SAFE_INTEGER), ie("maxQueuedJobs", s, Number.MAX_SAFE_INTEGER), ie("maxOldGenerationSizeMb", o.maxOldGenerationSizeMb, Number.MAX_SAFE_INTEGER), ie("maxYoungGenerationSizeMb", o.maxYoungGenerationSizeMb, Number.MAX_SAFE_INTEGER);
225
- const c = Object.freeze({ maxOldGenerationSizeMb: o.maxOldGenerationSizeMb, maxYoungGenerationSizeMb: o.maxYoungGenerationSizeMb }), m = /* @__PURE__ */ new Set(), g = [], T = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), w = ct(t);
224
+ }, jr = (e) => e !== null && typeof e == "object" && e.ready === !0 && !("id" in e), Lr = (e, t) => e !== null && typeof e == "object" && e.id === t && "output" in e, zr = ({ url: e, size: t, deadlineMs: r, jobsPerScope: n, maxQueuedJobs: a, heapLimits: o }) => {
225
+ se("size", t, Number.MAX_SAFE_INTEGER), se("deadline", r, $r), se("jobsPerScope", n, Number.MAX_SAFE_INTEGER), se("maxQueuedJobs", a, Number.MAX_SAFE_INTEGER), se("maxOldGenerationSizeMb", o.maxOldGenerationSizeMb, Number.MAX_SAFE_INTEGER), se("maxYoungGenerationSizeMb", o.maxYoungGenerationSizeMb, Number.MAX_SAFE_INTEGER);
226
+ const c = Object.freeze({ maxOldGenerationSizeMb: o.maxOldGenerationSizeMb, maxYoungGenerationSizeMb: o.maxYoungGenerationSizeMb }), f = /* @__PURE__ */ new Set(), g = [], T = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), p = wt(t);
226
227
  let _ = 0;
227
- const R = (u, a) => {
228
+ const R = (u, i) => {
228
229
  const { job: E } = u;
229
- u.timer !== null && clearTimeout(u.timer), u.timer = null, u.job = null, u.sent = !1, E !== null && (ne(T, E.scope, -1), ne(l, E.scope, -1), E.settle(a));
230
+ u.timer !== null && clearTimeout(u.timer), u.timer = null, u.job = null, u.sent = !1, E !== null && (re(T, E.scope, -1), re(d, E.scope, -1), E.settle(i));
230
231
  }, I = (u) => {
231
- const [a] = g.splice(u, 1);
232
- a?.detach();
232
+ const [i] = g.splice(u, 1);
233
+ i?.detach();
233
234
  }, O = () => {
234
- let u = -1, a = w, E = Number.POSITIVE_INFINITY;
235
- for (const [b, k] of g.entries()) {
236
- const A = T.get(k.scope) ?? 0, D = l.get(k.scope) ?? 0;
237
- (A < a || A === a && u >= 0 && D < E) && (u = b, a = A, E = D);
235
+ let u = -1, i = p, E = Number.POSITIVE_INFINITY;
236
+ for (const [S, k] of g.entries()) {
237
+ const A = T.get(k.scope) ?? 0, D = d.get(k.scope) ?? 0;
238
+ (A < i || A === i && u >= 0 && D < E) && (u = S, i = A, E = D);
238
239
  }
239
240
  return u;
240
- }, x = (u, a) => {
241
- m.has(u) && (m.delete(u), R(u, a), u.worker.terminate().catch(() => {
242
- }), L());
243
- }, v = (u) => {
241
+ }, x = (u, i) => {
242
+ f.has(u) && (f.delete(u), R(u, i), u.worker.terminate().catch(() => {
243
+ }), z());
244
+ }, P = (u) => {
244
245
  u.timer = setTimeout(() => {
245
246
  x(u, { status: "timeout" });
246
247
  }, r);
247
- }, y = (u, a) => u.sent ? { status: "crashed", error: a } : { status: "unavailable", error: a }, N = (u, a) => {
248
- u.sent = !0, v(u);
248
+ }, b = (u, i) => u.sent ? { status: "crashed", error: i } : { status: "unavailable", error: i }, N = (u, i) => {
249
+ u.sent = !0, P(u);
249
250
  try {
250
- u.worker.postMessage({ id: a.id, input: a.input });
251
+ u.worker.postMessage({ id: i.id, input: i.input });
251
252
  } catch (E) {
252
253
  R(u, { status: "crashed", error: E }), u.worker.unref();
253
254
  }
254
- }, z = () => {
255
- const u = { worker: new Kt(e, { resourceLimits: c }), job: null, sent: !1, timer: null, ready: !1 };
255
+ }, C = () => {
256
+ const u = { worker: new sr(e, { resourceLimits: c }), job: null, sent: !1, timer: null, ready: !1 };
256
257
  return u.worker.unref(), u.timer = setTimeout(() => {
257
258
  x(u, { status: "unavailable", error: new Error(`[markdown-explorer] a worker did not start within ${String(r)} ms`) });
258
- }, r), u.worker.on("message", (a) => {
259
- if (!u.ready && kr(a)) {
260
- u.ready = !0, u.timer !== null && clearTimeout(u.timer), u.timer = null, u.job === null ? u.worker.unref() : N(u, u.job), u.job === null && L();
259
+ }, r), u.worker.on("message", (i) => {
260
+ if (!u.ready && jr(i)) {
261
+ u.ready = !0, u.timer !== null && clearTimeout(u.timer), u.timer = null, u.job === null ? u.worker.unref() : N(u, u.job), u.job === null && z();
261
262
  return;
262
263
  }
263
264
  const { job: E } = u;
264
- if (E === null || !Rr(a, E.id)) {
265
- x(u, y(u, new Error("[markdown-explorer] a worker sent a message that answers no job")));
265
+ if (E === null || !Lr(i, E.id)) {
266
+ x(u, b(u, new Error("[markdown-explorer] a worker sent a message that answers no job")));
266
267
  return;
267
268
  }
268
- R(u, { status: "done", output: a.output }), u.worker.unref(), L();
269
- }), u.worker.on("error", (a) => {
270
- x(u, y(u, a));
271
- }), u.worker.on("messageerror", (a) => {
272
- x(u, y(u, a));
273
- }), u.worker.on("exit", (a) => {
274
- x(u, y(u, new Error(`[markdown-explorer] a worker exited with code ${String(a)}`)));
275
- }), m.add(u), u;
276
- }, L = () => {
269
+ R(u, { status: "done", output: i.output }), u.worker.unref(), z();
270
+ }), u.worker.on("error", (i) => {
271
+ x(u, b(u, i));
272
+ }), u.worker.on("messageerror", (i) => {
273
+ x(u, b(u, i));
274
+ }), u.worker.on("exit", (i) => {
275
+ x(u, b(u, new Error(`[markdown-explorer] a worker exited with code ${String(i)}`)));
276
+ }), f.add(u), u;
277
+ }, z = () => {
277
278
  for (; ; ) {
278
- const u = O(), a = g[u];
279
- if (a === void 0) return;
279
+ const u = O(), i = g[u];
280
+ if (i === void 0) return;
280
281
  let E;
281
- for (const k of m)
282
+ for (const k of f)
282
283
  if (k.job === null) {
283
284
  E = k;
284
285
  break;
285
286
  }
286
- if (E === void 0 && m.size < t)
287
+ if (E === void 0 && f.size < t)
287
288
  try {
288
- E = z();
289
+ E = C();
289
290
  } catch (k) {
290
- I(u), ne(l, a.scope, -1), a.settle({ status: "unavailable", error: k });
291
+ I(u), re(d, i.scope, -1), i.settle({ status: "unavailable", error: k });
291
292
  continue;
292
293
  }
293
294
  if (E === void 0) return;
294
- I(u), ne(T, a.scope, 1);
295
- const b = E;
296
- b.job = a, b.worker.ref(), b.ready && N(b, a);
295
+ I(u), re(T, i.scope, 1);
296
+ const S = E;
297
+ S.job = i, S.worker.ref(), S.ready && N(S, i);
297
298
  }
298
299
  };
299
300
  return {
300
- run: (u, { scope: a, signal: E }) => new Promise((b) => {
301
+ run: (u, { scope: i, signal: E }) => new Promise((S) => {
301
302
  if (E.aborted) {
302
- b(Be);
303
+ S(Xe);
303
304
  return;
304
305
  }
305
- if ((l.get(a) ?? 0) >= n) {
306
- b({ status: "refused", limit: "scope" });
306
+ if ((d.get(i) ?? 0) >= n) {
307
+ S({ status: "refused", limit: "scope" });
307
308
  return;
308
309
  }
309
310
  _ += 1;
310
- const k = { id: _, input: u, scope: a, settle: b, detach: () => {
311
+ const k = { id: _, input: u, scope: i, settle: S, detach: () => {
311
312
  } };
312
- g.push(k), ne(l, a, 1), L();
313
+ g.push(k), re(d, i, 1), z();
313
314
  const A = g.indexOf(k);
314
315
  if (A < 0) return;
315
- if (g.length > s) {
316
- I(A), ne(l, a, -1), b({ status: "refused", limit: "queue" });
316
+ if (g.length > a) {
317
+ I(A), re(d, i, -1), S({ status: "refused", limit: "queue" });
317
318
  return;
318
319
  }
319
320
  const D = () => {
320
321
  const M = g.indexOf(k);
321
- M < 0 || (I(M), ne(l, a, -1), b(Be));
322
+ M < 0 || (I(M), re(d, i, -1), S(Xe));
322
323
  };
323
324
  E.addEventListener("abort", D, { once: !0 }), k.detach = () => {
324
325
  E.removeEventListener("abort", D);
325
326
  };
326
327
  }),
327
- workers: () => m.size
328
+ workers: () => f.size
328
329
  };
329
- }, Ae = 1024 * 1024, Nr = 3e4, Ar = 4 * Ae, Ir = 64 * Ae, Mr = 3, Pr = 2, vr = (e, t) => e + ct(t) + Mr, $r = 4, jr = 32, Lr = 512, zr = 64, Dr = 4096, Cr = 32, Fe = 4096, Hr = 4, ut = ({ workerHeapMb: e, maxHtmlBytes: t }) => Math.floor(((e - zr) * Ae - t * Cr) / Dr), Br = ({ maxHtmlBytes: e }) => e, Fr = ({ maxHtmlBytes: e }) => Hr * e, Ur = 1024, Gr = 2147483647, Xr = 64, Jr = 2 ** 29, Wr = 1024 * 1024, Yr = 64, Ue = Object.freeze({ status: "rejected", reason: "too-large", cause: null }), xe = Object.freeze({ status: "rejected", reason: "failed", cause: null }), oe = (e, t, r, n) => {
330
+ }, Ae = 1024 * 1024, Cr = 3e4, Dr = 4 * Ae, Hr = 64 * Ae, Br = 3, Fr = 2, Ur = (e, t) => e + wt(t) + Br, Xr = 4, Gr = 32, Jr = 512, Wr = 64, Yr = 4096, Kr = 32, Ge = 4096, Vr = 4, ht = ({ workerHeapMb: e, maxHtmlBytes: t }) => Math.floor(((e - Wr) * Ae - t * Kr) / Yr), Zr = ({ maxHtmlBytes: e }) => e, Qr = ({ maxHtmlBytes: e }) => Vr * e, qr = 1024, en = 2147483647, tn = 64, rn = 2 ** 29, nn = 1024 * 1024, on = 64, Je = Object.freeze({ status: "rejected", reason: "too-large", cause: null }), xe = Object.freeze({ status: "rejected", reason: "failed", cause: null }), ne = (e, t, r, n) => {
330
331
  if (t === void 0) return r;
331
332
  if (typeof t != "number") throw new TypeError(`[markdown-explorer] sanitizer.${e} must be a number; got ${typeof t}`);
332
333
  if (!Number.isSafeInteger(t) || t <= 0 || t > n) throw new RangeError(`[markdown-explorer] sanitizer.${e} must be an integer in 1..${String(n)}; got ${String(t)}`);
333
334
  return t;
334
- }, Kr = (e, t) => {
335
+ }, sn = (e, t) => {
335
336
  if (e !== void 0 && (e === null || typeof e != "object")) throw new TypeError("[markdown-explorer] sanitizer must be an object of { workers, deadlineMs, maxHtmlBytes, cacheBytes, workerHeapMb, jobsPerScope, maxQueuedJobs }");
336
- const { workers: r, deadlineMs: n, maxHtmlBytes: s, cacheBytes: o, workerHeapMb: c, jobsPerScope: m, maxQueuedJobs: g } = e ?? {}, T = oe("workers", r, Pr, Xr), l = oe("jobsPerScope", m, vr(t, T), Number.MAX_SAFE_INTEGER), w = Object.freeze({
337
+ const { workers: r, deadlineMs: n, maxHtmlBytes: a, cacheBytes: o, workerHeapMb: c, jobsPerScope: f, maxQueuedJobs: g } = e ?? {}, T = ne("workers", r, Fr, tn), d = ne("jobsPerScope", f, Ur(t, T), Number.MAX_SAFE_INTEGER), p = Object.freeze({
337
338
  workers: T,
338
- deadlineMs: oe("deadlineMs", n, Nr, Gr),
339
- maxHtmlBytes: oe("maxHtmlBytes", s, Ar, Jr),
340
- cacheBytes: oe("cacheBytes", o, Ir, Number.MAX_SAFE_INTEGER),
341
- workerHeapMb: oe("workerHeapMb", c, Lr, Wr),
342
- jobsPerScope: l,
343
- maxQueuedJobs: oe("maxQueuedJobs", g, $r * l, Number.MAX_SAFE_INTEGER)
339
+ deadlineMs: ne("deadlineMs", n, Cr, en),
340
+ maxHtmlBytes: ne("maxHtmlBytes", a, Dr, rn),
341
+ cacheBytes: ne("cacheBytes", o, Hr, Number.MAX_SAFE_INTEGER),
342
+ workerHeapMb: ne("workerHeapMb", c, Jr, nn),
343
+ jobsPerScope: d,
344
+ maxQueuedJobs: ne("maxQueuedJobs", g, Xr * d, Number.MAX_SAFE_INTEGER)
344
345
  });
345
- if (w.jobsPerScope < t)
346
- throw new RangeError(`[markdown-explorer] sanitizer.jobsPerScope must be at least multiView.maxPanels (${String(t)}), because a page sends the document of every panel to the sanitizer at once for one reader; got ${String(w.jobsPerScope)}`);
347
- if (w.maxQueuedJobs < t)
348
- throw new RangeError(`[markdown-explorer] sanitizer.maxQueuedJobs must be at least multiView.maxPanels (${String(t)}), because a reader whose page finds every worker busy waits with the document of every panel; got ${String(w.maxQueuedJobs)}`);
349
- if (ut(w) < Fe)
346
+ if (p.jobsPerScope < t)
347
+ throw new RangeError(`[markdown-explorer] sanitizer.jobsPerScope must be at least multiView.maxPanels (${String(t)}), because a page sends the document of every panel to the sanitizer at once for one reader; got ${String(p.jobsPerScope)}`);
348
+ if (p.maxQueuedJobs < t)
349
+ throw new RangeError(`[markdown-explorer] sanitizer.maxQueuedJobs must be at least multiView.maxPanels (${String(t)}), because a reader whose page finds every worker busy waits with the document of every panel; got ${String(p.maxQueuedJobs)}`);
350
+ if (ht(p) < Ge)
350
351
  throw new RangeError(
351
- `[markdown-explorer] sanitizer.workerHeapMb (${String(w.workerHeapMb)} MiB) must leave room for ${String(Fe)} parsed nodes beside HTML of sanitizer.maxHtmlBytes (${String(w.maxHtmlBytes)} bytes); raise workerHeapMb or lower maxHtmlBytes`
352
+ `[markdown-explorer] sanitizer.workerHeapMb (${String(p.workerHeapMb)} MiB) must leave room for ${String(Ge)} parsed nodes beside HTML of sanitizer.maxHtmlBytes (${String(p.maxHtmlBytes)} bytes); raise workerHeapMb or lower maxHtmlBytes`
352
353
  );
353
- return w;
354
- }, Vr = () => {
355
- const e = import.meta.url, t = new URL(`./sanitizeWorker${Jt(be(e))}`, e);
356
- if (!Ut(be(t))) throw new Error(`[markdown-explorer] the HTML sanitizer worker is missing: ${be(t)}`);
354
+ return p;
355
+ }, an = () => {
356
+ const e = import.meta.url, t = new URL(`./sanitizeWorker${rr(be(e))}`, e);
357
+ if (!qt(be(t))) throw new Error(`[markdown-explorer] the HTML sanitizer worker is missing: ${be(t)}`);
357
358
  return t;
358
- }, Ge = /* @__PURE__ */ new Map(), Zr = (e, t) => {
359
+ }, We = /* @__PURE__ */ new Map(), cn = (e, t) => {
359
360
  const r = [e.href, t.workers, t.deadlineMs, t.workerHeapMb, t.jobsPerScope, t.maxQueuedJobs].map(String).join("\0");
360
- let n = Ge.get(r);
361
- return n === void 0 && (n = _r({
361
+ let n = We.get(r);
362
+ return n === void 0 && (n = zr({
362
363
  url: e,
363
364
  size: t.workers,
364
365
  deadlineMs: t.deadlineMs,
365
366
  jobsPerScope: t.jobsPerScope,
366
367
  maxQueuedJobs: t.maxQueuedJobs,
367
- heapLimits: { maxOldGenerationSizeMb: t.workerHeapMb, maxYoungGenerationSizeMb: jr }
368
- }), Ge.set(r, n)), n;
369
- }, Qr = (e) => {
368
+ heapLimits: { maxOldGenerationSizeMb: t.workerHeapMb, maxYoungGenerationSizeMb: Gr }
369
+ }), We.set(r, n)), n;
370
+ }, un = (e) => {
370
371
  if (e === null || typeof e != "object") return !1;
371
372
  const { status: t, html: r, message: n } = e;
372
373
  return t === "sanitized" && typeof r == "string" || t === "too-large" || t === "error" && typeof n == "string";
373
- }, qr = (e) => e instanceof Error && e.code === "ERR_WORKER_OUT_OF_MEMORY", en = ({ iframeHosts: e, dataPath: t, options: r, pool: n }) => {
374
- const s = Object.freeze([...e]), o = ut(r), c = Br(r), m = Fr(r), g = at(Ur, {
374
+ }, ln = (e) => e instanceof Error && e.code === "ERR_WORKER_OUT_OF_MEMORY", dn = ({ iframeHosts: e, dataPath: t, options: r, pool: n }) => {
375
+ const a = Object.freeze([...e]), o = ht(r), c = Zr(r), f = Qr(r), g = pt(qr, {
375
376
  max: r.cacheBytes,
376
- of: (O, x) => 2 * O.length + (x.status === "sanitized" ? 2 * x.html.length : Yr)
377
- }), T = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), w = (O) => {
377
+ of: (O, x) => 2 * O.length + (x.status === "sanitized" ? 2 * x.html.length : on)
378
+ }), T = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), p = (O) => {
378
379
  T.get(O.key) === O && T.delete(O.key);
379
- const x = l.get(O.hash);
380
- x?.delete(O), x?.size === 0 && l.delete(O.hash);
381
- }, _ = async (O, x, v) => {
382
- const y = await n.run({ html: O, iframeHosts: s, dataPath: t, maxNodes: o, maxAttributeChars: c, maxSanitizedChars: m }, { scope: x, signal: v });
383
- if (y.status === "refused") {
384
- const z = y.limit === "scope" ? `its reader already has ${String(r.jobsPerScope)} documents being sanitized or waiting` : `${String(r.maxQueuedJobs)} documents are already waiting`;
385
- return { outcome: { status: "rejected", reason: "failed", cause: new Error(`[markdown-explorer] the HTML sanitizer refused a document: ${z}`) }, lasting: !1 };
380
+ const x = d.get(O.hash);
381
+ x?.delete(O), x?.size === 0 && d.delete(O.hash);
382
+ }, _ = async (O, x, P) => {
383
+ const b = await n.run({ html: O, iframeHosts: a, dataPath: t, maxNodes: o, maxAttributeChars: c, maxSanitizedChars: f }, { scope: x, signal: P });
384
+ if (b.status === "refused") {
385
+ const C = b.limit === "scope" ? `its reader already has ${String(r.jobsPerScope)} documents being sanitized or waiting` : `${String(r.maxQueuedJobs)} documents are already waiting`;
386
+ return { outcome: { status: "rejected", reason: "failed", cause: new Error(`[markdown-explorer] the HTML sanitizer refused a document: ${C}`) }, lasting: !1 };
386
387
  }
387
- if (y.status === "aborted") return { outcome: xe, lasting: !1 };
388
- if (y.status === "timeout") return { outcome: { status: "rejected", reason: "too-large", cause: new Error(`[markdown-explorer] the HTML sanitizer did not finish within ${String(r.deadlineMs)} ms`) }, lasting: !0 };
389
- if (y.status === "unavailable") return { outcome: { status: "rejected", reason: "failed", cause: new Error("[markdown-explorer] the HTML sanitizer worker could not start", { cause: y.error }) }, lasting: !1 };
390
- if (y.status === "crashed" && qr(y.error))
391
- return { outcome: { status: "rejected", reason: "too-large", cause: new Error(`[markdown-explorer] the HTML sanitizer ran out of its ${String(r.workerHeapMb)} MiB worker heap`, { cause: y.error }) }, lasting: !0 };
392
- if (y.status === "crashed") return { outcome: { status: "rejected", reason: "failed", cause: new Error("[markdown-explorer] the HTML sanitizer worker failed", { cause: y.error }) }, lasting: !0 };
393
- const { output: N } = y;
394
- return Qr(N) ? N.status === "too-large" ? { outcome: Ue, lasting: !0 } : N.status === "error" ? { outcome: { status: "rejected", reason: "failed", cause: new Error(`[markdown-explorer] the HTML sanitizer failed: ${N.message}`) }, lasting: !0 } : N.html.length > m ? { outcome: { status: "rejected", reason: "too-large", cause: new Error(`[markdown-explorer] the HTML sanitizer's output of ${String(N.html.length)} characters exceeds its limit of ${String(m)}`) }, lasting: !0 } : { outcome: { status: "sanitized", html: N.html }, lasting: !0 } : { outcome: { status: "rejected", reason: "failed", cause: new Error("[markdown-explorer] the HTML sanitizer worker answered something that is not an outcome") }, lasting: !0 };
395
- }, R = (O, x, v, y) => {
388
+ if (b.status === "aborted") return { outcome: xe, lasting: !1 };
389
+ if (b.status === "timeout") return { outcome: { status: "rejected", reason: "too-large", cause: new Error(`[markdown-explorer] the HTML sanitizer did not finish within ${String(r.deadlineMs)} ms`) }, lasting: !0 };
390
+ if (b.status === "unavailable") return { outcome: { status: "rejected", reason: "failed", cause: new Error("[markdown-explorer] the HTML sanitizer worker could not start", { cause: b.error }) }, lasting: !1 };
391
+ if (b.status === "crashed" && ln(b.error))
392
+ return { outcome: { status: "rejected", reason: "too-large", cause: new Error(`[markdown-explorer] the HTML sanitizer ran out of its ${String(r.workerHeapMb)} MiB worker heap`, { cause: b.error }) }, lasting: !0 };
393
+ if (b.status === "crashed") return { outcome: { status: "rejected", reason: "failed", cause: new Error("[markdown-explorer] the HTML sanitizer worker failed", { cause: b.error }) }, lasting: !0 };
394
+ const { output: N } = b;
395
+ return un(N) ? N.status === "too-large" ? { outcome: Je, lasting: !0 } : N.status === "error" ? { outcome: { status: "rejected", reason: "failed", cause: new Error(`[markdown-explorer] the HTML sanitizer failed: ${N.message}`) }, lasting: !0 } : N.html.length > f ? { outcome: { status: "rejected", reason: "too-large", cause: new Error(`[markdown-explorer] the HTML sanitizer's output of ${String(N.html.length)} characters exceeds its limit of ${String(f)}`) }, lasting: !0 } : { outcome: { status: "sanitized", html: N.html }, lasting: !0 } : { outcome: { status: "rejected", reason: "failed", cause: new Error("[markdown-explorer] the HTML sanitizer worker answered something that is not an outcome") }, lasting: !0 };
396
+ }, R = (O, x, P, b) => {
396
397
  let N = () => {
397
398
  };
398
- const z = new Promise((a) => {
399
- N = a;
400
- }), L = { hash: x, key: v, outcome: z, answer: N, controller: new AbortController(), waiters: 0 };
401
- T.set(v, L);
402
- const u = l.get(x);
403
- return u === void 0 ? l.set(x, /* @__PURE__ */ new Set([L])) : u.add(L), _(O, y, L.controller.signal).catch((a) => ({ outcome: { status: "rejected", reason: "failed", cause: a instanceof Error ? a : new Error(String(a)) }, lasting: !0 })).then(({ outcome: a, lasting: E }) => {
404
- if (w(L), L.answer(a), !E) return;
405
- const b = g.get(x), k = b ?? (a.status === "rejected" ? { ...a, cause: null } : a);
406
- b === void 0 && g.set(x, k);
407
- for (const A of l.get(x) ?? [])
408
- w(A), A.answer(k), A.controller.abort();
409
- }), L;
410
- }, I = (O, x) => new Promise((v) => {
399
+ const C = new Promise((i) => {
400
+ N = i;
401
+ }), z = { hash: x, key: P, outcome: C, answer: N, controller: new AbortController(), waiters: 0 };
402
+ T.set(P, z);
403
+ const u = d.get(x);
404
+ return u === void 0 ? d.set(x, /* @__PURE__ */ new Set([z])) : u.add(z), _(O, b, z.controller.signal).catch((i) => ({ outcome: { status: "rejected", reason: "failed", cause: i instanceof Error ? i : new Error(String(i)) }, lasting: !0 })).then(({ outcome: i, lasting: E }) => {
405
+ if (p(z), z.answer(i), !E) return;
406
+ const S = g.get(x), k = S ?? (i.status === "rejected" ? { ...i, cause: null } : i);
407
+ S === void 0 && g.set(x, k);
408
+ for (const A of d.get(x) ?? [])
409
+ p(A), A.answer(k), A.controller.abort();
410
+ }), z;
411
+ }, I = (O, x) => new Promise((P) => {
411
412
  O.waiters += 1;
412
- const y = () => {
413
- O.waiters -= 1, v(xe), !(O.waiters > 0) && (w(O), O.controller.abort());
413
+ const b = () => {
414
+ O.waiters -= 1, P(xe), !(O.waiters > 0) && (p(O), O.controller.abort());
414
415
  };
415
- x.addEventListener("abort", y, { once: !0 }), O.outcome.then((N) => {
416
- x.removeEventListener("abort", y), v(N);
416
+ x.addEventListener("abort", b, { once: !0 }), O.outcome.then((N) => {
417
+ x.removeEventListener("abort", b), P(N);
417
418
  });
418
419
  });
419
- return (O, { scope: x, signal: v }) => {
420
- if (O.length > r.maxHtmlBytes || Buffer.byteLength(O, "utf8") > r.maxHtmlBytes) return Promise.resolve(Ue);
421
- const y = Mt("sha256").update(O, "utf8").digest("base64"), N = g.get(y);
420
+ return (O, { scope: x, signal: P }) => {
421
+ if (O.length > r.maxHtmlBytes || Buffer.byteLength(O, "utf8") > r.maxHtmlBytes) return Promise.resolve(Je);
422
+ const b = Ht("sha256").update(O, "utf8").digest("base64"), N = g.get(b);
422
423
  if (N !== void 0) return Promise.resolve(N);
423
- if (v.aborted) return Promise.resolve(xe);
424
- const z = `${y}\0${x}`, L = T.get(z);
425
- return I(L === void 0 ? R(O, y, z, x) : L, v);
424
+ if (P.aborted) return Promise.resolve(xe);
425
+ const C = `${b}\0${x}`, z = T.get(C);
426
+ return I(z === void 0 ? R(O, b, C, x) : z, P);
426
427
  };
427
- }, ye = (e) => ({ result: e, json: JSON.stringify(e) }), Oe = Object.freeze(ye(Object.freeze({ status: "error", failure: Object.freeze({ reason: "failed" }) }))), tn = (e) => e.status === "ok" && e.entries.length > 0, rn = ({ ttlMs: e, maxEntries: t, maxBytes: r, now: n }) => {
428
- const s = at(t, { max: r, of: (l, w) => 2 * w.tree.json.length }), o = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), m = (l, w) => {
429
- const _ = new AbortController(), R = { waiters: 0, superseded: !1, started: !1, loadTree: w }, I = c.get(l), O = (z, L) => {
430
- const u = ye(z);
431
- return !(R.superseded || _.signal.aborted) && tn(z) && s.set(l, { tree: u, loadedAt: L }), u;
432
- }, v = (async () => {
428
+ }, ye = (e) => ({ result: e, json: JSON.stringify(e) }), Oe = Object.freeze(ye(Object.freeze({ status: "error", failure: Object.freeze({ reason: "failed" }) }))), fn = (e) => e.status === "ok" && e.entries.length > 0, mn = ({ ttlMs: e, maxEntries: t, maxBytes: r, now: n }) => {
429
+ const a = pt(t, { max: r, of: (d, p) => 2 * p.tree.json.length }), o = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), f = (d, p) => {
430
+ const _ = new AbortController(), R = { waiters: 0, superseded: !1, started: !1, loadTree: p }, I = c.get(d), O = (C, z) => {
431
+ const u = ye(C);
432
+ return !(R.superseded || _.signal.aborted) && fn(C) && a.set(d, { tree: u, loadedAt: z }), u;
433
+ }, P = (async () => {
433
434
  if (I !== void 0 && await I, _.signal.aborted) return Oe;
434
- const z = n();
435
- return R.started = !0, O(await R.loadTree(_.signal, z), z);
435
+ const C = n();
436
+ return R.started = !0, O(await R.loadTree(_.signal, C), C);
436
437
  })().finally(() => {
437
- o.get(l) === y && o.delete(l);
438
- }), y = { promise: v, controller: _, state: R };
439
- o.set(l, y);
440
- const N = v.then(
438
+ o.get(d) === b && o.delete(d);
439
+ }), b = { promise: P, controller: _, state: R };
440
+ o.set(d, b);
441
+ const N = P.then(
441
442
  () => {
442
443
  },
443
444
  () => {
444
445
  }
445
446
  );
446
- return c.set(l, N), N.then(() => {
447
- c.get(l) === N && c.delete(l);
448
- }), y;
449
- }, g = (l, w, _) => {
450
- w.state.waiters += 1;
447
+ return c.set(d, N), N.then(() => {
448
+ c.get(d) === N && c.delete(d);
449
+ }), b;
450
+ }, g = (d, p, _) => {
451
+ p.state.waiters += 1;
451
452
  const R = () => {
452
- w.state.waiters -= 1, !(w.state.waiters > 0) && (o.get(l) === w && o.delete(l), w.controller.abort());
453
+ p.state.waiters -= 1, !(p.state.waiters > 0) && (o.get(d) === p && o.delete(d), p.controller.abort());
453
454
  };
454
- return _.addEventListener("abort", R, { once: !0 }), w.promise.finally(() => {
455
+ return _.addEventListener("abort", R, { once: !0 }), p.promise.finally(() => {
455
456
  _.removeEventListener("abort", R);
456
457
  });
457
- }, T = (l) => {
458
- s.delete(l);
459
- const w = o.get(l);
460
- w?.state.started && (w.state.superseded = !0, o.delete(l));
458
+ }, T = (d) => {
459
+ a.delete(d);
460
+ const p = o.get(d);
461
+ p?.state.started && (p.state.superseded = !0, o.delete(d));
461
462
  };
462
463
  return {
463
- load: (l, w, _) => {
464
- if (w.aborted) return Promise.resolve(Oe);
465
- const R = s.get(l);
464
+ load: (d, p, _) => {
465
+ if (p.aborted) return Promise.resolve(Oe);
466
+ const R = a.get(d);
466
467
  if (R !== void 0) {
467
468
  if (n() - R.loadedAt < e) return Promise.resolve(R.tree);
468
- s.delete(l);
469
+ a.delete(d);
469
470
  }
470
- const I = o.get(l);
471
- return g(l, I === void 0 ? m(l, _) : I, w);
471
+ const I = o.get(d);
472
+ return g(d, I === void 0 ? f(d, _) : I, p);
472
473
  },
473
- refresh: (l, w, _) => {
474
- if (w.aborted) return Promise.resolve(Oe);
475
- T(l);
476
- const R = o.get(l);
477
- return R === void 0 ? g(l, m(l, _), w) : (R.state.loadTree = _, g(l, R, w));
474
+ refresh: (d, p, _) => {
475
+ if (p.aborted) return Promise.resolve(Oe);
476
+ T(d);
477
+ const R = o.get(d);
478
+ return R === void 0 ? g(d, f(d, _), p) : (R.state.loadTree = _, g(d, R, p));
478
479
  },
479
480
  forget: T
480
481
  };
481
- }, nn = (e) => ({
482
+ }, pn = (e) => ({
482
483
  load: (t, r, n) => n(r, e()).then(ye),
483
484
  refresh: (t, r, n) => n(r, e()).then(ye),
484
485
  forget: () => {
485
486
  }
486
- }), P = (e) => {
487
+ }), v = (e) => {
487
488
  throw new TypeError(`[markdown-explorer] ${e}`);
488
- }, on = (e) => {
489
+ }, wn = (e) => {
489
490
  if (e === null || typeof e != "object") return null;
490
491
  const { name: t, path: r } = e;
491
492
  return typeof t != "string" || typeof r != "string" ? null : t === "" ? { path: r, reason: "an empty name" } : te(r) ? null : { path: r, reason: "a path the browser cannot address (empty, too long, a lone surrogate, a control character or a backslash)" };
492
- }, sn = (e, t, r, n, s) => {
493
+ }, hn = (e, t, r, n, a) => {
493
494
  const o = /* @__PURE__ */ new Set(), c = (g) => {
494
- if (!Array.isArray(g)) return P("a source returned entries that are not an array");
495
+ if (!Array.isArray(g)) return v("a source returned entries that are not an array");
495
496
  const T = [];
496
- for (const l of g) {
497
- const w = m(l);
498
- w !== null && T.push(w);
497
+ for (const d of g) {
498
+ const p = f(d);
499
+ p !== null && T.push(p);
499
500
  }
500
501
  return T;
501
- }, m = (g) => {
502
- const T = on(g);
502
+ }, f = (g) => {
503
+ const T = wn(g);
503
504
  if (T !== null)
504
505
  return n(T), null;
505
- const l = Ot(g);
506
- if (l !== null) return P(l);
507
- const w = g;
508
- if (o.has(w)) return P("a source returned entries that contain themselves");
509
- const { name: _, path: R, type: I, mimeType: O, children: x, lazy: v } = w;
506
+ const d = Pt(g);
507
+ if (d !== null) return v(d);
508
+ const p = g;
509
+ if (o.has(p)) return v("a source returned entries that contain themselves");
510
+ const { name: _, path: R, type: I, mimeType: O, children: x, lazy: P } = p;
510
511
  if (t.deniesName(_) || t.deniesPath(R)) return null;
511
- if (!s(R))
512
+ if (!a(R))
512
513
  return n({ path: R, reason: "a path outside the source's boundary" }), null;
513
- const y = O === void 0 ? { name: _, path: R } : { name: _, path: R, mimeType: O };
514
- if (I === "file") return { ...y, type: I };
515
- if (v === !0)
516
- return r ? { ...y, type: I, lazy: !0, children: [] } : P("a lazy directory came from a source without a children function");
517
- if (x === void 0) return { ...y, type: I };
518
- o.add(w);
514
+ const b = O === void 0 ? { name: _, path: R } : { name: _, path: R, mimeType: O };
515
+ if (I === "file") return { ...b, type: I };
516
+ if (P === !0)
517
+ return r ? { ...b, type: I, lazy: !0, children: [] } : v("a lazy directory came from a source without a children function");
518
+ if (x === void 0) return { ...b, type: I };
519
+ o.add(p);
519
520
  const N = c(x);
520
- return o.delete(w), { ...y, type: I, children: N };
521
+ return o.delete(p), { ...b, type: I, children: N };
521
522
  };
522
523
  return c(e);
523
- }, an = /^[\x21\x23-\x7E]{1,256}$/u, lt = (e) => typeof e == "string" && an.test(e), cn = /* @__PURE__ */ new Set(["text", "image", "media", "file"]), un = (e) => typeof e == "string" && cn.has(e), ln = (e, t) => {
524
+ }, gn = /^[\x21\x23-\x7E]{1,256}$/u, gt = (e) => typeof e == "string" && gn.test(e), En = /* @__PURE__ */ new Set(["text", "image", "media", "file"]), yn = (e) => typeof e == "string" && En.has(e), bn = (e, t) => {
524
525
  if (e !== null && typeof e == "object") {
525
- const s = e, { kind: o } = s;
526
- if (un(o)) {
527
- if (Object.hasOwn(s, "url")) return P(`a ${o} document carries its version, not a url`);
528
- if (typeof s.name != "string") return P("a document needs a name string");
529
- if (!lt(s.version)) return P(`a ${o} document needs a version of 1 to 256 visible ASCII characters other than '"'`);
530
- const c = t(s.version);
526
+ const a = e, { kind: o } = a;
527
+ if (yn(o)) {
528
+ if (Object.hasOwn(a, "url")) return v(`a ${o} document carries its version, not a url`);
529
+ if (typeof a.name != "string") return v("a document needs a name string");
530
+ if (!gt(a.version)) return v(`a ${o} document needs a version of 1 to 256 visible ASCII characters other than '"'`);
531
+ const c = t(a.version);
531
532
  switch (o) {
532
533
  case "image":
533
534
  case "file":
534
- return { kind: o, name: s.name, url: c };
535
+ return { kind: o, name: a.name, url: c };
535
536
  case "media": {
536
- const { mediaType: m } = s;
537
- return St(m) ? { kind: o, name: s.name, url: c, mediaType: m } : P(`unknown media type ${typeof m == "string" ? JSON.stringify(m.slice(0, 64)) : typeof m}`);
537
+ const { mediaType: f } = a;
538
+ return It(f) ? { kind: o, name: a.name, url: c, mediaType: f } : v(`unknown media type ${typeof f == "string" ? JSON.stringify(f.slice(0, 64)) : typeof f}`);
538
539
  }
539
540
  case "text":
540
- return typeof s.text != "string" || typeof s.truncated != "boolean" ? P("a text document needs text and truncated") : { kind: o, name: s.name, text: s.text, truncated: s.truncated, url: c };
541
+ return typeof a.text != "string" || typeof a.truncated != "boolean" ? v("a text document needs text and truncated") : { kind: o, name: a.name, text: a.text, truncated: a.truncated, url: c };
541
542
  }
542
543
  }
543
544
  }
544
- const r = Tt(e);
545
- if (r !== null) return P(r);
545
+ const r = Mt(e);
546
+ if (r !== null) return v(r);
546
547
  const n = e;
547
548
  switch (n.kind) {
548
549
  case "failure": {
549
- const { reason: s, code: o } = n.failure;
550
- return { kind: "failure", failure: Re(s, o) };
550
+ const { reason: a, code: o } = n.failure;
551
+ return { kind: "failure", failure: Re(a, o) };
551
552
  }
552
553
  case "markdown":
553
- return n.headings.length > xt ? { kind: "failure", failure: Re("too-large") } : { kind: "unsanitized-markdown", name: n.name, html: n.htmlContent, headings: n.headings.map(({ text: s, depth: o, id: c }) => ({ text: s, depth: o, id: c })) };
554
+ return n.headings.length > vt ? { kind: "failure", failure: Re("too-large") } : { kind: "unsanitized-markdown", name: n.name, html: n.htmlContent, headings: n.headings.map(({ text: a, depth: o, id: c }) => ({ text: a, depth: o, id: c })) };
554
555
  }
555
- }, dn = (e) => {
556
- if (e === null || typeof e != "object") return P("an asset file must be an object");
557
- const { name: t, contentType: r, size: n, version: s, open: o } = e;
558
- return typeof t != "string" || t === "" ? P("an asset file needs a non-empty name") : typeof r != "string" ? P("an asset file needs a contentType string ('' when unknown)") : n !== null && !(typeof n == "number" && Number.isSafeInteger(n) && n >= 0) ? P("an asset file's size must be null or a non-negative safe integer") : lt(s) ? typeof o != "function" ? P("an asset file needs an open function") : Object.freeze({ name: t, contentType: r, size: n, version: s, open: o }) : P(`an asset file needs a version of 1 to 256 visible ASCII characters other than '"'`);
559
- }, fn = (e) => Array.isArray(e) ? e.map((t) => {
560
- if (t === null || typeof t != "object") return P("a notice must be an object");
561
- const { id: r, tone: n, title: s, body: o, action: c } = t;
562
- if (typeof r != "string" || r === "" || typeof s != "string") return P("a notice needs an id and a title");
563
- if (!yt(n)) return P(`unknown notice tone ${typeof n == "string" ? JSON.stringify(n.slice(0, 64)) : typeof n}`);
564
- if (o !== void 0 && typeof o != "string") return P("a notice body must be a string");
565
- const g = { id: r, tone: n, title: s, ...o === void 0 ? {} : { body: o } };
556
+ }, Sn = (e) => {
557
+ if (e === null || typeof e != "object") return v("an asset file must be an object");
558
+ const { name: t, contentType: r, size: n, version: a, open: o } = e;
559
+ return typeof t != "string" || t === "" ? v("an asset file needs a non-empty name") : typeof r != "string" ? v("an asset file needs a contentType string ('' when unknown)") : n !== null && !(typeof n == "number" && Number.isSafeInteger(n) && n >= 0) ? v("an asset file's size must be null or a non-negative safe integer") : gt(a) ? typeof o != "function" ? v("an asset file needs an open function") : Object.freeze({ name: t, contentType: r, size: n, version: a, open: o }) : v(`an asset file needs a version of 1 to 256 visible ASCII characters other than '"'`);
560
+ }, Tn = (e) => Array.isArray(e) ? e.map((t) => {
561
+ if (t === null || typeof t != "object") return v("a notice must be an object");
562
+ const { id: r, tone: n, title: a, body: o, action: c } = t;
563
+ if (typeof r != "string" || r === "" || typeof a != "string") return v("a notice needs an id and a title");
564
+ if (!Nt(n)) return v(`unknown notice tone ${typeof n == "string" ? JSON.stringify(n.slice(0, 64)) : typeof n}`);
565
+ if (o !== void 0 && typeof o != "string") return v("a notice body must be a string");
566
+ const g = { id: r, tone: n, title: a, ...o === void 0 ? {} : { body: o } };
566
567
  if (c === void 0) return g;
567
- if (c === null || typeof c != "object") return P("a notice action must be an object");
568
- const { label: T, href: l } = c;
569
- return typeof T != "string" || !bt(l, kt) ? P("a notice action needs a label and an http(s), mailto or relative href") : { ...g, action: { label: T, href: l } };
570
- }) : P("notices must be an array"), mn = 4e3, me = Object.freeze({ ttlMs: 3e5, maxEntries: 64, maxBytes: 64 * 1024 * 1024 }), Xe = 32, dt = "private, no-store", pn = Object.freeze({
568
+ if (c === null || typeof c != "object") return v("a notice action must be an object");
569
+ const { label: T, href: d } = c;
570
+ return typeof T != "string" || !At(d, $t) ? v("a notice action needs a label and an http(s), mailto or relative href") : { ...g, action: { label: T, href: d } };
571
+ }) : v("notices must be an array"), xn = 4e3, me = Object.freeze({ ttlMs: 3e5, maxEntries: 64, maxBytes: 64 * 1024 * 1024 }), Ye = 32, Et = "private, no-store", On = Object.freeze({
571
572
  "Content-Type": "application/json; charset=utf-8",
572
- "Cache-Control": dt,
573
+ "Cache-Control": Et,
573
574
  "X-Content-Type-Options": "nosniff",
574
575
  "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'; sandbox",
575
576
  "Cross-Origin-Resource-Policy": "same-origin"
576
- }), wn = 22, hn = 2147483647, ke = Object.freeze([]), Je = Object.freeze(["contains", "confirm"]), X = (e, t, r) => {
577
+ }), kn = 22, Rn = 2147483647, ke = Object.freeze([]), Ke = Object.freeze(["contains", "confirm"]), Ve = Object.freeze({ readOnly: !1 }), _n = Object.freeze({ readOnly: !0 }), G = (e, t, r) => {
577
578
  if (!(r && t === void 0) && typeof t != "function")
578
579
  throw new TypeError(`[markdown-explorer] ${e} must be a function; got ${typeof t}`);
579
580
  }, ge = (e, t, r) => {
580
581
  if (typeof t != "number") throw new TypeError(`[markdown-explorer] ${e} must be a number; got ${typeof t}`);
581
582
  if (!Number.isSafeInteger(t) || t <= 0 || t > r) throw new RangeError(`[markdown-explorer] ${e} must be an integer in 1..${String(r)}; got ${String(t)}`);
582
583
  return t;
583
- }, gn = (e) => {
584
+ }, Nn = (e) => {
584
585
  if (e === null || typeof e != "object" || !Object.isFrozen(e)) throw new TypeError("[markdown-explorer] config must be the value returned by defineExplorerConfig");
585
- return Lt(e);
586
- }, En = (e) => {
586
+ return Jt(e);
587
+ }, Ze = (e) => {
588
+ try {
589
+ return new Headers(e);
590
+ } catch {
591
+ throw new TypeError("[markdown-explorer] authenticate returned headers that are not a valid headers init (their values are not logged)");
592
+ }
593
+ }, Qe = (e) => e instanceof Response ? new TypeError(`[markdown-explorer] authenticate threw a Response (status ${String(e.status)}), which a data request does not follow`) : e, An = (e) => {
587
594
  if (typeof e != "string") throw new TypeError(`[markdown-explorer] scopeSecret must be a string; got ${typeof e}`);
588
- if (e.length < Xe) throw new RangeError(`[markdown-explorer] scopeSecret must have at least ${String(Xe)} characters; got ${String(e.length)}`);
595
+ if (e.length < Ye) throw new RangeError(`[markdown-explorer] scopeSecret must have at least ${String(Ye)} characters; got ${String(e.length)}`);
589
596
  return e;
590
- }, yn = (e, t) => {
591
- if (!Bt(t)) throw new TypeError(`[markdown-explorer] ${e}.boundary must be a plain object { contains, confirm? }`);
597
+ }, In = (e, t) => {
598
+ if (!Zt(t)) throw new TypeError(`[markdown-explorer] ${e}.boundary must be a plain object { contains, confirm? }`);
592
599
  for (const r of Object.keys(t))
593
- if (!Je.includes(r)) throw new RangeError(`[markdown-explorer] ${e}.boundary.${r} is not an option; expected ${Je.join(", ")}`);
594
- X(`${e}.boundary.contains`, t.contains, !1), X(`${e}.boundary.confirm`, t.confirm, !0);
595
- }, bn = (e) => {
600
+ if (!Ke.includes(r)) throw new RangeError(`[markdown-explorer] ${e}.boundary.${r} is not an option; expected ${Ke.join(", ")}`);
601
+ G(`${e}.boundary.contains`, t.contains, !1), G(`${e}.boundary.confirm`, t.confirm, !0);
602
+ }, Mn = (e) => {
596
603
  if (!Array.isArray(e)) throw new TypeError("[markdown-explorer] sources must be an array");
597
604
  const t = e;
598
605
  if (t.length === 0) throw new RangeError("[markdown-explorer] sources must hold at least one source");
599
606
  const r = /* @__PURE__ */ new Set();
600
- for (const [n, s] of t.entries()) {
601
- if (s === null || typeof s != "object") throw new TypeError(`[markdown-explorer] sources[${String(n)}] must be an object`);
602
- const { id: o, label: c, boundary: m, tree: g, children: T, cacheScope: l } = s;
603
- if (!zt(o))
607
+ for (const [n, a] of t.entries()) {
608
+ if (a === null || typeof a != "object") throw new TypeError(`[markdown-explorer] sources[${String(n)}] must be an object`);
609
+ const { id: o, label: c, boundary: f, tree: g, children: T, cacheScope: d } = a;
610
+ if (!Wt(o))
604
611
  throw new RangeError(`[markdown-explorer] sources[${String(n)}].id must use lowercase letters, digits and "-" and start with a letter or digit; got ${typeof o == "string" ? JSON.stringify(o) : typeof o}`);
605
- const w = `source ${JSON.stringify(o)}`;
612
+ const p = `source ${JSON.stringify(o)}`;
606
613
  if (r.has(o)) throw new RangeError(`[markdown-explorer] source ids must be unique; ${JSON.stringify(o)} repeats at sources[${String(n)}]`);
607
- if (r.add(o), typeof c != "string" && typeof c != "function") throw new TypeError(`[markdown-explorer] ${w}.label must be a string or a function`);
608
- if (typeof c == "string" && c.trim() === "") throw new RangeError(`[markdown-explorer] ${w}.label must not be blank`);
609
- if (yn(w, m), X(`${w}.tree`, g, !1), X(`${w}.children`, T, !0), l !== void 0 && l !== "principal" && l !== "shared") throw new RangeError(`[markdown-explorer] ${w}.cacheScope must be "principal" or "shared"; got ${JSON.stringify(l)}`);
614
+ if (r.add(o), typeof c != "string" && typeof c != "function") throw new TypeError(`[markdown-explorer] ${p}.label must be a string or a function`);
615
+ if (typeof c == "string" && c.trim() === "") throw new RangeError(`[markdown-explorer] ${p}.label must not be blank`);
616
+ if (In(p, f), G(`${p}.tree`, g, !1), G(`${p}.children`, T, !0), d !== void 0 && d !== "principal" && d !== "shared") throw new RangeError(`[markdown-explorer] ${p}.cacheScope must be "principal" or "shared"; got ${JSON.stringify(d)}`);
610
617
  }
611
618
  return t;
612
- }, Sn = (e) => {
619
+ }, vn = (e) => {
613
620
  if (e === !1) return !1;
614
621
  if (e === void 0) return me;
615
622
  if (e === null || typeof e != "object") throw new TypeError("[markdown-explorer] treeCache must be { ttlMs, maxEntries, maxBytes } or false");
@@ -619,231 +626,252 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
619
626
  maxEntries: r === void 0 ? me.maxEntries : ge("treeCache.maxEntries", r, Number.MAX_SAFE_INTEGER),
620
627
  maxBytes: n === void 0 ? me.maxBytes : ge("treeCache.maxBytes", n, Number.MAX_SAFE_INTEGER)
621
628
  };
622
- }, We = (e) => {
629
+ }, qe = (e) => {
623
630
  if (e === null || typeof e != "object") throw new TypeError("[markdown-explorer] authenticate must resolve to { status, ... }");
624
631
  const { status: t } = e;
625
632
  if (t !== "signed-in" && t !== "signed-out" && t !== "forbidden") throw new TypeError(`[markdown-explorer] authenticate resolved to an unknown status ${JSON.stringify(t)}`);
626
633
  return e;
627
- }, Ye = (e, t) => {
634
+ }, et = (e, t) => {
628
635
  if (!(t instanceof Response)) throw new TypeError(`[markdown-explorer] ${e} must return a Response`);
629
636
  return t;
630
- }, Ke = (e, t) => {
637
+ }, tt = (e, t) => {
631
638
  if (typeof t != "string" || t === "") throw new TypeError("[markdown-explorer] principalKey must return a non-empty string");
632
- return Pt("sha256", e).update(t, "utf8").digest("base64url").slice(0, wn);
633
- }, Tn = (e) => e.view === "multi" ? e.docs : e.doc === null ? [] : [e.doc], pe = (e, t) => {
639
+ return Bt("sha256", e).update(t, "utf8").digest("base64url").slice(0, kn);
640
+ }, Pn = (e) => e.view === "multi" ? e.docs : e.doc === null ? [] : [e.doc], pe = (e, t) => {
634
641
  const r = e.getAll(t), [n] = r;
635
642
  return r.length === 1 && n !== void 0 && n !== "" ? n : null;
636
643
  }, ae = (e, t, r, n = {}) => {
637
- const s = new Headers(r);
638
- for (const [o, c] of Object.entries({ ...pn, ...n })) s.set(o, c);
639
- return new Response(t, { status: e, headers: s });
640
- }, F = (e, t, r) => ae(_t[e.reason], JSON.stringify({ failure: e }), t, r), Ve = (e) => {
641
- if (e.headers.get(rt) !== Nt) return !1;
644
+ const a = new Headers(r);
645
+ for (const [o, c] of Object.entries({ ...On, ...n })) a.set(o, c);
646
+ return new Response(t, { status: e, headers: a });
647
+ }, B = (e, t, r) => ae(Lt[e.reason], JSON.stringify({ failure: e }), t, r), rt = (e, t) => {
648
+ const r = t === "refresh" ? ["POST"] : ["GET", "HEAD"];
649
+ return r.includes(e.method.toUpperCase()) ? null : ae(405, JSON.stringify({ failure: { reason: "invalid" } }), void 0, { Allow: r.join(", ") });
650
+ }, nt = (e) => {
651
+ if (e.headers.get(ut) !== zt) return !1;
642
652
  const t = e.headers.get("Sec-Fetch-Site");
643
653
  return t === null || t === "same-origin";
644
- }, xn = ({ parentHeaders: e, loaderHeaders: t, errorHeaders: r }) => {
645
- const n = new Headers(), s = r === void 0 ? [e, t] : [e, t, r];
646
- for (const o of s)
647
- for (const [c, m] of o)
648
- c !== "set-cookie" && n.set(c, m);
654
+ }, $n = ({ parentHeaders: e, loaderHeaders: t, errorHeaders: r }) => {
655
+ const n = new Headers(), a = r === void 0 ? [e, t] : [e, t, r];
656
+ for (const o of a)
657
+ for (const [c, f] of o)
658
+ c !== "set-cookie" && n.set(c, f);
649
659
  return n;
650
- }, Yn = (e) => {
660
+ }, ao = (e) => {
651
661
  if (e === null || typeof e != "object") throw new TypeError("[markdown-explorer] the server configuration must be an object");
652
- const t = gn(e.config), r = En(e.scopeSecret);
653
- X("authenticate", e.authenticate, !1), X("principalKey", e.principalKey, !1), X("document", e.document, !1), X("asset", e.asset, !1), X("signedOutPage", e.signedOutPage, !1), X("forbiddenPage", e.forbiddenPage, !0), X("notices", e.notices, !0), X("onTreeRefreshed", e.onTreeRefreshed, !0);
654
- const n = bn(e.sources), s = $t(
662
+ const t = Nn(e.config), r = An(e.scopeSecret);
663
+ G("authenticate", e.authenticate, !1), G("principalKey", e.principalKey, !1), G("document", e.document, !1), G("asset", e.asset, !1), G("signedOutPage", e.signedOutPage, !1), G("forbiddenPage", e.forbiddenPage, !0), G("notices", e.notices, !0), G("onTreeRefreshed", e.onTreeRefreshed, !0);
664
+ const n = Mn(e.sources), a = Xt(
655
665
  t,
656
- n.map((i) => i.id)
666
+ n.map((s) => s.id)
657
667
  ), o = e.logger;
658
668
  if (o !== void 0 && (o === null || typeof o != "object" || typeof o.error != "function"))
659
669
  throw new TypeError("[markdown-explorer] logger must be an object with an error function");
660
- const c = e.logger === void 0 ? yr : e.logger, m = tt(e.deny), g = e.deferredTimeoutMs === void 0 ? mn : ge("deferredTimeoutMs", e.deferredTimeoutMs, hn), T = Sn(e.treeCache), l = () => Date.now(), w = T === !1 ? nn(l) : rn({ ...T, now: l }), _ = Kr(e.sanitizer, t.multiView.maxPanels), R = en({ iframeHosts: t.iframeHosts, dataPath: t.dataPath, options: _, pool: Zr(Vr(), _) }), I = new Map(n.map((i) => [i.id, i])), O = jt(t), { authenticate: x, principalKey: v, signedOutPage: y, forbiddenPage: N, onTreeRefreshed: z } = e, L = (i, h) => {
661
- if (typeof i.label == "string") return i.label;
662
- const d = i.label(h);
663
- if (typeof d != "string" || d.trim() === "") throw new TypeError(`[markdown-explorer] the label of source ${JSON.stringify(i.id)} must be a non-blank string`);
664
- return d;
665
- }, u = (i, h) => i.cacheScope === "shared" ? i.id : `${i.id}\0${h}`, a = (i, h) => {
666
- const d = (f) => q(c, { operation: "boundary", sourceId: i.id, path: h, error: f });
667
- let p;
670
+ const c = e.logger === void 0 ? Ar : e.logger, f = ct(e.deny), g = e.deferredTimeoutMs === void 0 ? xn : ge("deferredTimeoutMs", e.deferredTimeoutMs, Rn), T = vn(e.treeCache), d = () => Date.now(), p = T === !1 ? pn(d) : mn({ ...T, now: d }), _ = sn(e.sanitizer, t.multiView.maxPanels), R = dn({ iframeHosts: t.iframeHosts, dataPath: t.dataPath, options: _, pool: cn(an(), _) }), I = new Map(n.map((s) => [s.id, s])), O = Gt(t), { authenticate: x, principalKey: P, signedOutPage: b, forbiddenPage: N, onTreeRefreshed: C } = e, z = (s, m) => {
671
+ if (typeof s.label == "string") return s.label;
672
+ const l = s.label(m);
673
+ if (typeof l != "string" || l.trim() === "") throw new TypeError(`[markdown-explorer] the label of source ${JSON.stringify(s.id)} must be a non-blank string`);
674
+ return l;
675
+ }, u = (s, m) => s.cacheScope === "shared" ? s.id : `${s.id}\0${m}`, i = (s, m) => {
676
+ const l = (h) => q(c, { operation: "boundary", sourceId: s.id, path: m, error: h });
677
+ let w;
668
678
  try {
669
- p = i.boundary.contains(h);
670
- } catch (f) {
671
- return d(f), !1;
679
+ w = s.boundary.contains(m);
680
+ } catch (h) {
681
+ return l(h), !1;
672
682
  }
673
- return typeof p == "boolean" ? p : (Ce(p, d), d(new TypeError(`[markdown-explorer] boundary.contains of source ${JSON.stringify(i.id)} must return a boolean; got ${typeof p}`)), !1);
674
- }, E = async (i, h, d) => {
675
- const { confirm: p } = i.boundary;
676
- if (p === void 0) return { status: "inside", readPath: d };
677
- let f;
683
+ return typeof w == "boolean" ? w : (Fe(w, l), l(new TypeError(`[markdown-explorer] boundary.contains of source ${JSON.stringify(s.id)} must return a boolean; got ${typeof w}`)), !1);
684
+ }, E = async (s, m, l) => {
685
+ const { confirm: w } = s.boundary;
686
+ if (w === void 0) return { status: "inside", readPath: l };
687
+ let h;
678
688
  try {
679
- f = await p(h, d);
680
- } catch (K) {
681
- return { status: "error", failure: Q(K, { operation: "boundary", sourceId: i.id, path: d }, h.signal, c) };
689
+ h = await w(m, l);
690
+ } catch (V) {
691
+ return { status: "error", failure: Q(V, { operation: "boundary", sourceId: s.id, path: l }, m.signal, c) };
682
692
  }
683
- const S = (K) => (q(c, { operation: "boundary", sourceId: i.id, path: d, error: new TypeError(`[markdown-explorer] boundary.confirm of source ${JSON.stringify(i.id)} ${K}`) }), { status: "outside" });
684
- if (f === null || typeof f != "object") return S(`must resolve to { inside, readPath? }; got ${f === null ? "null" : typeof f}`);
685
- const { inside: j, readPath: C } = f;
686
- return j === !1 ? { status: "outside" } : j !== !0 || typeof C != "string" ? S("must resolve to { inside: false } or { inside: true, readPath: string }") : !te(C) || m.deniesPath(C) ? (q(c, { operation: "boundary", sourceId: i.id, path: d, error: new RangeError(`[markdown-explorer] boundary.confirm of source ${JSON.stringify(i.id)} answered a readPath the explorer does not serve (unacceptable or denied)`) }), { status: "error", failure: { reason: "failed" } }) : { status: "inside", readPath: C };
687
- }, b = async (i, h) => {
688
- const d = n.filter((f) => a(f, h));
689
- if (d.length === 0) return { status: "error", failure: { reason: "forbidden" } };
690
- if (d.some((f) => f.boundary.confirm === void 0)) return { status: "inside", readPath: h };
691
- let p = null;
692
- for (const f of d) {
693
- const S = await E(f, i, h);
694
- if (S.status === "inside") return S;
695
- S.status === "error" && p === null && (p = S.failure);
693
+ const y = (V) => (q(c, { operation: "boundary", sourceId: s.id, path: l, error: new TypeError(`[markdown-explorer] boundary.confirm of source ${JSON.stringify(s.id)} ${V}`) }), { status: "outside" });
694
+ if (h === null || typeof h != "object") return y(`must resolve to { inside, readPath? }; got ${h === null ? "null" : typeof h}`);
695
+ const { inside: j, readPath: L } = h;
696
+ return j === !1 ? { status: "outside" } : j !== !0 || typeof L != "string" ? y("must resolve to { inside: false } or { inside: true, readPath: string }") : !te(L) || f.deniesPath(L) ? (q(c, { operation: "boundary", sourceId: s.id, path: l, error: new RangeError(`[markdown-explorer] boundary.confirm of source ${JSON.stringify(s.id)} answered a readPath the explorer does not serve (unacceptable or denied)`) }), { status: "error", failure: { reason: "failed" } }) : { status: "inside", readPath: L };
697
+ }, S = async (s, m) => {
698
+ const l = n.filter((h) => i(h, m));
699
+ if (l.length === 0) return { status: "error", failure: { reason: "forbidden" } };
700
+ if (l.some((h) => h.boundary.confirm === void 0)) return { status: "inside", readPath: m };
701
+ let w = null;
702
+ for (const h of l) {
703
+ const y = await E(h, s, m);
704
+ if (y.status === "inside") return y;
705
+ y.status === "error" && w === null && (w = y.failure);
696
706
  }
697
- return { status: "error", failure: p === null ? { reason: "forbidden" } : p };
698
- }, k = (i, h, d) => {
699
- const p = ({ path: f, reason: S }) => Tr(c, { operation: d.operation, sourceId: d.sourceId, path: f, error: new TypeError(`[markdown-explorer] an entry with ${S} was left out`) });
707
+ return { status: "error", failure: w === null ? { reason: "forbidden" } : w };
708
+ }, k = (s, m, l) => {
709
+ const w = ({ path: h, reason: y }) => vr(c, { operation: l.operation, sourceId: l.sourceId, path: h, error: new TypeError(`[markdown-explorer] an entry with ${y} was left out`) });
700
710
  try {
701
- return { status: "ok", entries: sn(i, m, h.children !== void 0, p, (f) => a(h, f)) };
702
- } catch (f) {
703
- return q(c, { ...d, error: f }), { status: "error", failure: { reason: "failed" } };
711
+ return { status: "ok", entries: hn(s, f, m.children !== void 0, w, (h) => i(m, h)) };
712
+ } catch (h) {
713
+ return q(c, { ...l, error: h }), { status: "error", failure: { reason: "failed" } };
704
714
  }
705
- }, A = async (i, h, d) => {
706
- let p;
715
+ }, A = async (s, m, l) => {
716
+ let w;
707
717
  try {
708
- p = await i.tree(h);
709
- } catch (S) {
710
- return { status: "error", failure: Q(S, { operation: "tree", sourceId: i.id }, h.signal, c) };
718
+ w = await s.tree(m);
719
+ } catch (y) {
720
+ return { status: "error", failure: Q(y, { operation: "tree", sourceId: s.id }, m.signal, c) };
711
721
  }
712
- const f = k(p, i, { operation: "tree", sourceId: i.id });
713
- return f.status === "ok" ? { status: "ok", entries: f.entries, loadedAt: d } : f;
714
- }, D = (i, h, d, p) => (f, S) => A(i, { principal: h, request: d, signal: f, refresh: p }, S), M = (i, h, d, p, f) => w.load(u(i, d), f, D(i, h, p, !1)), U = (i, h, d, p) => w.refresh(u(i, d), p.signal, D(i, h, p, !0)), G = (i, h) => {
715
- if (z === void 0) return;
716
- const d = (p) => q(c, { operation: "refresh", sourceId: i.id, error: p });
722
+ const h = k(w, s, { operation: "tree", sourceId: s.id });
723
+ return h.status === "ok" ? { status: "ok", entries: h.entries, loadedAt: l } : h;
724
+ }, D = (s, m, l, w) => (h, y) => A(s, { principal: m, request: l, signal: h, refresh: w }, y), M = (s, m, l, w, h) => p.load(u(s, l), h, D(s, m, w, !1)), U = (s, m, l, w) => p.refresh(u(s, l), w.signal, D(s, m, w, !0)), X = (s, m) => {
725
+ if (C === void 0) return;
726
+ const l = (w) => q(c, { operation: "refresh", sourceId: s.id, error: w });
717
727
  try {
718
- Ce(z(h), d);
719
- } catch (p) {
720
- d(p);
728
+ Fe(C(m), l);
729
+ } catch (w) {
730
+ l(w);
721
731
  }
722
- }, B = async (i, h, d, p) => {
723
- if (m.deniesPath(p) || !a(i, p)) return { status: "error", failure: { reason: "forbidden" } };
724
- const f = await E(i, d, p);
725
- if (f.status === "outside") return { status: "error", failure: { reason: "forbidden" } };
726
- if (f.status === "error") return { status: "error", failure: f.failure };
727
- let S;
732
+ }, F = async (s, m, l, w) => {
733
+ if (f.deniesPath(w) || !i(s, w)) return { status: "error", failure: { reason: "forbidden" } };
734
+ const h = await E(s, l, w);
735
+ if (h.status === "outside") return { status: "error", failure: { reason: "forbidden" } };
736
+ if (h.status === "error") return { status: "error", failure: h.failure };
737
+ let y;
728
738
  try {
729
- S = await h(d, p, f.readPath);
739
+ y = await m(l, w, h.readPath);
730
740
  } catch (j) {
731
- return { status: "error", failure: Q(j, { operation: "children", sourceId: i.id, path: p }, d.signal, c) };
741
+ return { status: "error", failure: Q(j, { operation: "children", sourceId: s.id, path: w }, l.signal, c) };
732
742
  }
733
- return k(S, i, { operation: "children", sourceId: i.id, path: p });
734
- }, Z = async (i, h, d) => {
735
- if (m.deniesPath(d)) return ee("forbidden");
736
- const p = await b(i, d);
737
- if (p.status === "error") return { kind: "failure", failure: p.failure };
738
- let f;
743
+ return k(y, s, { operation: "children", sourceId: s.id, path: w });
744
+ }, Z = async (s, m, l) => {
745
+ if (f.deniesPath(l)) return ee("forbidden");
746
+ const w = await S(s, l);
747
+ if (w.status === "error") return { kind: "failure", failure: w.failure };
748
+ let h;
739
749
  try {
740
- f = await e.document(i, d, p.readPath);
741
- } catch (C) {
742
- return { kind: "failure", failure: Q(C, { operation: "document", path: d }, i.signal, c) };
750
+ h = await e.document(s, l, w.readPath);
751
+ } catch (L) {
752
+ return { kind: "failure", failure: Q(L, { operation: "document", path: l }, s.signal, c) };
743
753
  }
744
- let S;
754
+ let y;
745
755
  try {
746
- S = ln(f, (C) => It(t.dataPath, d, C));
747
- } catch (C) {
748
- return q(c, { operation: "document", path: d, error: C }), ee("failed");
756
+ y = bn(h, (L) => Dt(t.dataPath, l, L));
757
+ } catch (L) {
758
+ return q(c, { operation: "document", path: l, error: L }), ee("failed");
749
759
  }
750
- if (S.kind !== "unsanitized-markdown") return S;
751
- const j = await R(S.html, { scope: h, signal: i.signal });
752
- return j.status === "sanitized" ? { kind: "markdown", name: S.name, htmlContent: j.html, headings: S.headings } : (j.cause !== null && q(c, { operation: "document", path: d, error: j.cause }), ee(j.reason));
753
- }, $ = async (i) => {
760
+ if (y.kind !== "unsanitized-markdown") return y;
761
+ const j = await R(y.html, { scope: m, signal: s.signal });
762
+ return j.status === "sanitized" ? { kind: "markdown", name: y.name, htmlContent: j.html, headings: y.headings } : (j.cause !== null && q(c, { operation: "document", path: l, error: j.cause }), ee(j.reason));
763
+ }, $ = async (s) => {
754
764
  if (e.notices === void 0) return ke;
755
765
  try {
756
- return fn(await e.notices(i));
757
- } catch (h) {
758
- return Q(h, { operation: "notices" }, i.signal, c), ke;
766
+ return Tn(await e.notices(s));
767
+ } catch (m) {
768
+ return Q(m, { operation: "notices" }, s.signal, c), ke;
759
769
  }
760
- }, J = async (i, h, d) => {
761
- const p = pe(h, de.path);
762
- if (p === null || !te(p)) return F({ reason: "invalid" }, d);
763
- if (m.deniesPath(p))
764
- return xr(c, { operation: "asset", path: p }), F({ reason: "forbidden" }, d);
765
- const f = await b(i, p);
766
- if (f.status === "error") return F(f.failure, d);
770
+ }, J = async (s, m, l) => {
771
+ const w = pe(m, de.path);
772
+ if (w === null || !te(w)) return B({ reason: "invalid" }, l);
773
+ if (f.deniesPath(w))
774
+ return Pr(c, { operation: "asset", path: w }), B({ reason: "forbidden" }, l);
775
+ const h = await S(s, w);
776
+ if (h.status === "error") return B(h.failure, l);
767
777
  try {
768
- const S = dn(await e.asset(i, p, f.readPath));
769
- return await Er(i.request, S, d);
770
- } catch (S) {
771
- return F(Q(S, { operation: "asset", path: p }, i.signal, c), d);
778
+ const y = Sn(await e.asset(s, w, h.readPath));
779
+ return await Nr(s.request, y, l);
780
+ } catch (y) {
781
+ return B(Q(y, { operation: "asset", path: w }, s.signal, c), l);
772
782
  }
773
- }, W = async ({ request: i, url: h, params: d }) => {
774
- const p = We(await x(i)), f = new Headers(p.headers);
775
- if (f.set("Cache-Control", dt), p.status === "signed-out") throw Ye("signedOutPage", y(i, f));
776
- if (p.status === "forbidden") throw N === void 0 ? Ie(null, { status: 403, headers: f }) : Ye("forbiddenPage", N(i, f));
777
- const S = Dt(s, d["*"], h.searchParams);
778
- if (S.kind === "redirect") throw vt(S.href, { headers: f });
779
- const { location: j } = S, { principal: C } = p, K = Ke(r, v(C)), le = I.get(j.source);
780
- if (le === void 0) throw new RangeError(`[markdown-explorer] no source for ${JSON.stringify(j.source)}`);
781
- const re = { signal: i.signal, timeoutMs: g, late: null, handOverMs: g }, V = {
782
- scope: K,
783
- sources: n.map((H) => ({ id: H.id, label: L(H, C) })),
784
- settings: Ct(Ht(i.headers.get("Cookie"), t.settingsCookie), O),
783
+ }, K = async ({ request: s, url: m, params: l }) => {
784
+ const w = qe(await x(s, Ve)), h = Ze(w.headers);
785
+ if (h.set("Cache-Control", Et), w.status === "signed-out") throw et("signedOutPage", b(s, h));
786
+ if (w.status === "forbidden") throw N === void 0 ? Pe(null, { status: 403, headers: h }) : et("forbiddenPage", N(s, h));
787
+ const y = Yt(a, l["*"], m.searchParams);
788
+ if (y.kind === "redirect") throw Ut(y.href, { headers: h });
789
+ const { location: j } = y, { principal: L } = w, V = tt(r, P(L)), ce = I.get(j.source);
790
+ if (ce === void 0) throw new RangeError(`[markdown-explorer] no source for ${JSON.stringify(j.source)}`);
791
+ const ue = { signal: s.signal, timeoutMs: g, late: null, handOverMs: g }, oe = {
792
+ scope: V,
793
+ sources: n.map((H) => ({ id: H.id, label: z(H, L) })),
794
+ settings: Kt(Vt(s.headers.get("Cookie"), t.settingsCookie), O),
785
795
  tree: j.view === "single" ? null : {
786
796
  sourceId: j.source,
787
- result: Te(re, (H) => M(le, C, K, i, H).then((se) => se.result))
797
+ result: Te(ue, (H) => M(ce, L, V, s, H).then((Y) => Y.result))
788
798
  },
789
- documents: Tn(j).map((H) => ({ path: H, document: Te(re, (se) => Z({ principal: C, request: i, signal: se, refresh: !1 }, K, H)) })),
790
- notices: Te({ signal: i.signal, timeoutMs: g, late: ke, handOverMs: 0 }, (H) => $({ principal: C, request: i, signal: H, refresh: !1 }))
799
+ documents: Pn(j).map((H) => ({ path: H, document: Te(ue, (Y) => Z({ principal: L, request: s, signal: Y, refresh: !1 }, V, H)) })),
800
+ notices: Te({ signal: s.signal, timeoutMs: g, late: ke, handOverMs: 0 }, (H) => $({ principal: L, request: s, signal: H, refresh: !1 }))
791
801
  };
792
- return Ie(V, { headers: f });
793
- }, Y = async (i, h, d) => {
794
- let p;
802
+ return Pe(oe, { headers: h });
803
+ }, W = async (s, m) => {
804
+ const l = qe(await x(s, m));
805
+ return { authentication: l, headers: Ze(l.headers) };
806
+ }, le = async (s, m, l) => {
807
+ let w;
795
808
  try {
796
- p = We(await x(h));
797
- } catch (H) {
798
- return F(Q(H, { operation: "authenticate" }, h.signal, c));
809
+ w = await W(m, Ve);
810
+ } catch (Y) {
811
+ return B(Q(Qe(Y), { operation: "authenticate" }, m.signal, c));
812
+ }
813
+ const { authentication: h, headers: y } = w;
814
+ if (h.status === "signed-out") return B({ reason: "unauthorized" }, y);
815
+ if (h.status === "forbidden") return B({ reason: "forbidden" }, y);
816
+ const { principal: j } = h;
817
+ if (s === "asset") return J({ principal: j, request: m, signal: m.signal, refresh: !1 }, l, y);
818
+ const L = tt(r, P(j));
819
+ y.set(Ct, L);
820
+ const V = { principal: j, request: m, signal: m.signal, refresh: !1 }, ce = () => B({ reason: "invalid" }, y);
821
+ if (s === "document") {
822
+ const Y = pe(l, de.path);
823
+ if (Y === null || !te(Y)) return ce();
824
+ const ve = m.headers.has(ut);
825
+ return ve && !nt(m) ? B({ reason: "forbidden" }, y) : ae(200, JSON.stringify(await Z({ ...V, refresh: ve }, L, Y)), y);
826
+ }
827
+ const ue = pe(l, de.source), oe = pe(l, de.path);
828
+ if (ue === null || s === "children" && (oe === null || !te(oe))) return ce();
829
+ const H = I.get(ue);
830
+ if (H === void 0) return B({ reason: "not-found" }, y);
831
+ if (s === "tree") return ae(200, (await M(H, j, L, m, m.signal)).json, y);
832
+ if (s === "refresh") {
833
+ const Y = await U(H, j, L, m);
834
+ return m.signal.aborted || X(H, u(H, L)), ae(200, Y.json, y);
799
835
  }
800
- const f = new Headers(p.headers);
801
- if (p.status === "signed-out") return F({ reason: "unauthorized" }, f);
802
- if (p.status === "forbidden") return F({ reason: "forbidden" }, f);
803
- const { principal: S } = p;
804
- if (i === "asset") return J({ principal: S, request: h, signal: h.signal, refresh: !1 }, d, f);
805
- const j = Ke(r, v(S));
806
- f.set(At, j);
807
- const C = { principal: S, request: h, signal: h.signal, refresh: !1 }, K = () => F({ reason: "invalid" }, f);
808
- if (i === "document") {
809
- const H = pe(d, de.path);
810
- if (H === null || !te(H)) return K();
811
- const se = h.headers.has(rt);
812
- return se && !Ve(h) ? F({ reason: "forbidden" }, f) : ae(200, JSON.stringify(await Z({ ...C, refresh: se }, j, H)), f);
836
+ return H.children === void 0 || oe === null ? B({ reason: "not-found" }, y) : ae(200, JSON.stringify(await F(H, H.children, V, oe)), y);
837
+ }, kt = async (s) => {
838
+ const { authentication: m, headers: l } = await W(s, _n);
839
+ if (!l.keys().next().done) throw new TypeError("[markdown-explorer] authenticate returned headers in read-only mode; a read-only authentication must only read the session (none was forwarded)");
840
+ return m.status === "signed-in";
841
+ }, Ie = t.embeds.linkCardEndpoint === null ? null : Ft({ authorize: kt }), Rt = async (s, m) => {
842
+ try {
843
+ return await s(m);
844
+ } catch (l) {
845
+ return B(Q(Qe(l), { operation: "authenticate" }, m.signal, c));
813
846
  }
814
- const le = pe(d, de.source), re = pe(d, de.path);
815
- if (le === null || i === "children" && (re === null || !te(re))) return K();
816
- const V = I.get(le);
817
- if (V === void 0) return F({ reason: "not-found" }, f);
818
- if (i === "tree") return ae(200, (await M(V, S, j, h, h.signal)).json, f);
819
- if (i === "refresh") {
820
- const H = await U(V, S, j, h);
821
- return h.signal.aborted || G(V, u(V, j)), ae(200, H.json, f);
847
+ }, Me = async (s, m, l) => {
848
+ if (new URL(s.url).pathname.endsWith(".data")) return B({ reason: "not-found" });
849
+ if (!jt(l)) return B({ reason: "not-found" });
850
+ if (l === "link-card") {
851
+ if (Ie === null) return B({ reason: "not-found" });
852
+ const h = rt(s, l);
853
+ return h !== null ? h : Rt(Ie, s);
822
854
  }
823
- return V.children === void 0 || re === null ? F({ reason: "not-found" }, f) : ae(200, JSON.stringify(await B(V, V.children, C, re)), f);
824
- }, ue = async (i, h, d) => {
825
- if (new URL(i.url).pathname.endsWith(".data")) return F({ reason: "not-found" });
826
- if (!Rt(d)) return F({ reason: "not-found" });
827
- const p = i.method.toUpperCase(), f = d === "refresh";
828
- if (f ? p !== "POST" : p !== "GET" && p !== "HEAD") return ae(405, JSON.stringify({ failure: { reason: "invalid" } }), void 0, { Allow: f ? "POST" : "GET, HEAD" });
829
- if (f && !Ve(i)) return F({ reason: "forbidden" });
855
+ const w = rt(s, l);
856
+ if (w !== null) return w;
857
+ if (l === "refresh" && !nt(s)) return B({ reason: "forbidden" });
830
858
  try {
831
- return await Y(d, i, h.searchParams);
832
- } catch (S) {
833
- return F(Q(S, { operation: d }, i.signal, c));
859
+ return await le(l, s, m.searchParams);
860
+ } catch (h) {
861
+ return B(Q(h, { operation: l }, s.signal, c));
834
862
  }
835
863
  };
836
864
  return Object.freeze({
837
- loader: W,
838
- headers: xn,
839
- dataLoader: ({ request: i, url: h, params: d }) => ue(i, h, d["*"]),
840
- dataAction: ({ request: i, url: h, params: d }) => ue(i, h, d["*"]),
841
- forgetTree: (i) => {
842
- if (typeof i != "string") throw new TypeError(`[markdown-explorer] forgetTree needs the string key onTreeRefreshed received; got ${typeof i}`);
843
- w.forget(i);
865
+ loader: K,
866
+ headers: $n,
867
+ dataLoader: ({ request: s, url: m, params: l }) => Me(s, m, l["*"]),
868
+ dataAction: ({ request: s, url: m, params: l }) => Me(s, m, l["*"]),
869
+ forgetTree: (s) => {
870
+ if (typeof s != "string") throw new TypeError(`[markdown-explorer] forgetTree needs the string key onTreeRefreshed received; got ${typeof s}`);
871
+ p.forget(s);
844
872
  }
845
873
  });
846
- }, we = Object.freeze({ maxEntries: 2e4, maxDocumentBytes: 2 * 1024 * 1024, textPreviewBytes: 8 * 1024, walkConcurrency: 8 }), On = /* @__PURE__ */ new Set(["md", "markdown", "mdx"]), ft = new Map([
874
+ }, we = Object.freeze({ maxEntries: 2e4, maxDocumentBytes: 2 * 1024 * 1024, textPreviewBytes: 8 * 1024, walkConcurrency: 8 }), jn = /* @__PURE__ */ new Set(["md", "markdown", "mdx"]), yt = new Map([
847
875
  ...[
848
876
  ["png", "image/png"],
849
877
  ["jpg", "image/jpeg"],
@@ -878,7 +906,7 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
878
906
  ["wma", "audio/x-ms-wma"]
879
907
  ].map(([e, t]) => [e, { kind: "media", mediaType: "audio", contentType: t }]),
880
908
  ["pdf", { kind: "media", mediaType: "pdf", contentType: "application/pdf" }]
881
- ]), kn = /* @__PURE__ */ new Set([
909
+ ]), Ln = /* @__PURE__ */ new Set([
882
910
  "txt",
883
911
  "text",
884
912
  "log",
@@ -1003,7 +1031,7 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
1003
1031
  "eslintrc",
1004
1032
  "babelrc",
1005
1033
  "mailmap"
1006
- ]), Rn = /* @__PURE__ */ new Set([
1034
+ ]), zn = /* @__PURE__ */ new Set([
1007
1035
  "readme",
1008
1036
  "license",
1009
1037
  "licence",
@@ -1024,17 +1052,17 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
1024
1052
  "jenkinsfile",
1025
1053
  "brewfile",
1026
1054
  "codeowners"
1027
- ]), mt = typeof ce.O_NOFOLLOW == "number" ? ce.O_NOFOLLOW : 0, pt = typeof ce.O_NONBLOCK == "number" ? ce.O_NONBLOCK : 0, Ze = (e) => `${e.size}-${e.mtimeNs}`, _n = (e) => e !== "" && e !== "." && e !== ".." && !e.includes(":") && !e.endsWith(".") && !e.endsWith(" "), Qe = (e) => te(e) && e === e.normalize("NFC") && e.split("/").every(_n), wt = (e) => {
1055
+ ]), bt = typeof ie.O_NOFOLLOW == "number" ? ie.O_NOFOLLOW : 0, St = typeof ie.O_NONBLOCK == "number" ? ie.O_NONBLOCK : 0, ot = (e) => `${e.size}-${e.mtimeNs}`, Cn = (e) => e !== "" && e !== "." && e !== ".." && !e.includes(":") && !e.endsWith(".") && !e.endsWith(" "), st = (e) => te(e) && e === e.normalize("NFC") && e.split("/").every(Cn), Tt = (e) => {
1028
1056
  const t = e.toLowerCase(), r = t.lastIndexOf(".");
1029
1057
  return r < 0 ? "" : t.slice(r + 1);
1030
- }, Nn = (e) => {
1031
- const t = wt(e);
1032
- if (On.has(t)) return { kind: "markdown" };
1033
- const r = ft.get(t);
1058
+ }, Dn = (e) => {
1059
+ const t = Tt(e);
1060
+ if (jn.has(t)) return { kind: "markdown" };
1061
+ const r = yt.get(t);
1034
1062
  if (r !== void 0) return r.kind === "image" ? { kind: "image" } : { kind: "media", mediaType: r.mediaType };
1035
1063
  const n = e.toLowerCase();
1036
- return kn.has(t) || !n.includes(".") && Rn.has(n) ? { kind: "text" } : { kind: "file" };
1037
- }, ht = (e) => {
1064
+ return Ln.has(t) || !n.includes(".") && zn.has(n) ? { kind: "text" } : { kind: "file" };
1065
+ }, xt = (e) => {
1038
1066
  switch (typeof e == "object" && e !== null ? e.code : void 0) {
1039
1067
  case "ENOENT":
1040
1068
  case "ENOTDIR":
@@ -1050,122 +1078,122 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
1050
1078
  default:
1051
1079
  return null;
1052
1080
  }
1053
- }, gt = (e) => {
1054
- const t = ht(e);
1081
+ }, Ot = (e) => {
1082
+ const t = xt(e);
1055
1083
  return t === null ? e : new Ee(t);
1056
- }, An = (e) => {
1084
+ }, Hn = (e) => {
1057
1085
  const t = typeof e == "object" && e !== null ? e.code : void 0;
1058
1086
  return t === "EACCES" || t === "EPERM" || t === "ENOENT" || t === "ENOTDIR";
1059
- }, qe = async (e, t) => {
1087
+ }, at = async (e, t) => {
1060
1088
  const r = [];
1061
1089
  for await (const n of e.createReadStream({ start: 0, end: t - 1, autoClose: !1 }))
1062
1090
  r.push(n);
1063
1091
  return Buffer.concat(r);
1064
- }, In = (e, t) => e !== null ? { start: e.offset, end: e.offset + e.length - 1 } : t === 0n ? {} : { start: 0, end: Number(t) - 1 }, Mn = async (e, t, r, n) => {
1065
- let s;
1092
+ }, Bn = (e, t) => e !== null ? { start: e.offset, end: e.offset + e.length - 1 } : t === 0n ? {} : { start: 0, end: Number(t) - 1 }, Fn = async (e, t, r, n) => {
1093
+ let a;
1066
1094
  try {
1067
- s = await nt(e, ce.O_RDONLY | mt | pt);
1068
- const g = await s.stat({ bigint: !0 });
1095
+ a = await lt(e, ie.O_RDONLY | bt | St);
1096
+ const g = await a.stat({ bigint: !0 });
1069
1097
  if (!g.isFile() || g.ino !== t.ino || g.dev !== t.dev || g.size !== t.size || g.mtimeNs !== t.mtimeNs) throw new Ee("not-found");
1070
1098
  } catch (g) {
1071
- throw await s?.close(), gt(g);
1099
+ throw await a?.close(), Ot(g);
1072
1100
  }
1073
- const o = s.createReadStream(In(r, t.size)), c = qt.toWeb(o), m = () => {
1101
+ const o = a.createReadStream(Bn(r, t.size)), c = ur.toWeb(o), f = () => {
1074
1102
  o.destroy(n.reason);
1075
1103
  };
1076
- return n.aborted ? m() : n.addEventListener("abort", m, { once: !0 }), c;
1077
- }, Pn = (e, t) => {
1078
- const r = Ft.compare(e, t);
1104
+ return n.aborted ? f() : n.addEventListener("abort", f, { once: !0 }), c;
1105
+ }, Un = (e, t) => {
1106
+ const r = Qt.compare(e, t);
1079
1107
  return r !== 0 ? r : e === t ? 0 : e < t ? -1 : 1;
1080
- }, vn = (e) => {
1108
+ }, Xn = (e) => {
1081
1109
  let t = 0;
1082
1110
  const r = [];
1083
1111
  return async (n) => {
1084
- t < e ? t += 1 : await new Promise((s) => r.push(s));
1112
+ t < e ? t += 1 : await new Promise((a) => r.push(a));
1085
1113
  try {
1086
1114
  return await n();
1087
1115
  } finally {
1088
- const s = r.shift();
1089
- s === void 0 ? t -= 1 : s();
1116
+ const a = r.shift();
1117
+ a === void 0 ? t -= 1 : a();
1090
1118
  }
1091
1119
  };
1092
- }, $n = (e, t) => {
1120
+ }, Gn = (e, t) => {
1093
1121
  if (e.isSymbolicLink()) return "symbolic-link";
1094
1122
  if (!(e.isDirectory() || e.isFile())) return "special-file";
1095
1123
  const { name: r } = e;
1096
1124
  return r !== r.normalize("NFC") ? "not-nfc" : r.includes(":") ? "colon" : r.endsWith(".") || r.endsWith(" ") ? "trailing-dot-or-space" : te(r) ? te(t) ? null : "path-too-long" : "control-character-or-backslash";
1097
- }, jn = /* @__PURE__ */ new Set(["id", "label", "root", "pathPrefix", "parse", "deny", "maxEntries", "maxDocumentBytes", "textPreviewBytes", "walkConcurrency", "cacheScope", "reportSkipped"]), he = (e, t, r) => {
1125
+ }, Jn = /* @__PURE__ */ new Set(["id", "label", "root", "pathPrefix", "parse", "deny", "maxEntries", "maxDocumentBytes", "textPreviewBytes", "walkConcurrency", "cacheScope", "reportSkipped"]), he = (e, t, r) => {
1098
1126
  if (t === void 0) return r;
1099
1127
  if (typeof t != "number" || !Number.isSafeInteger(t) || t <= 0) throw new RangeError(`[markdown-explorer] ${e} must be a positive integer; got ${String(t)}`);
1100
1128
  return t;
1101
- }, Kn = (e) => {
1129
+ }, io = (e) => {
1102
1130
  if (e === null || typeof e != "object") throw new TypeError("[markdown-explorer] createFileSystemSource needs an options object");
1103
- for (const a of Object.keys(e))
1104
- if (!jn.has(a)) throw new TypeError(`[markdown-explorer] createFileSystemSource does not know the option ${JSON.stringify(a)}`);
1105
- const { id: t, label: r, root: n, parse: s } = e;
1131
+ for (const i of Object.keys(e))
1132
+ if (!Jn.has(i)) throw new TypeError(`[markdown-explorer] createFileSystemSource does not know the option ${JSON.stringify(i)}`);
1133
+ const { id: t, label: r, root: n, parse: a } = e;
1106
1134
  if (typeof t != "string" || t === "") throw new TypeError("[markdown-explorer] a file-system source needs a non-empty id");
1107
1135
  if (typeof r != "string" || r.trim() === "") throw new TypeError("[markdown-explorer] a file-system source needs a non-blank label");
1108
- if (typeof s != "function") throw new TypeError("[markdown-explorer] a file-system source needs a parse function");
1109
- if (typeof n != "string" || !Me(n)) throw new RangeError(`[markdown-explorer] root must be an absolute path; got ${JSON.stringify(n)}`);
1136
+ if (typeof a != "function") throw new TypeError("[markdown-explorer] a file-system source needs a parse function");
1137
+ if (typeof n != "string" || !$e(n)) throw new RangeError(`[markdown-explorer] root must be an absolute path; got ${JSON.stringify(n)}`);
1110
1138
  let o;
1111
1139
  try {
1112
- o = Gt(n).isDirectory();
1113
- } catch (a) {
1114
- throw new RangeError(`[markdown-explorer] root does not exist: ${n}`, { cause: a });
1140
+ o = er(n).isDirectory();
1141
+ } catch (i) {
1142
+ throw new RangeError(`[markdown-explorer] root does not exist: ${n}`, { cause: i });
1115
1143
  }
1116
1144
  if (!o) throw new RangeError(`[markdown-explorer] root is not a directory: ${n}`);
1117
- const c = Xt(n), m = e.pathPrefix;
1118
- if (typeof m != "string") throw new TypeError('[markdown-explorer] pathPrefix is required: "" for a source over the whole root, or relative segments ending with "/"');
1119
- if (m !== "" && !(m.endsWith("/") && Qe(m.slice(0, -1))))
1120
- throw new RangeError(`[markdown-explorer] pathPrefix must be empty or relative segments ending with "/"; got ${JSON.stringify(m)}`);
1121
- const g = tt(e.deny), T = he("maxEntries", e.maxEntries, we.maxEntries), l = he("maxDocumentBytes", e.maxDocumentBytes, we.maxDocumentBytes), w = he("textPreviewBytes", e.textPreviewBytes, we.textPreviewBytes), _ = he("walkConcurrency", e.walkConcurrency, we.walkConcurrency), R = e.cacheScope === void 0 ? "principal" : e.cacheScope;
1145
+ const c = tr(n), f = e.pathPrefix;
1146
+ if (typeof f != "string") throw new TypeError('[markdown-explorer] pathPrefix is required: "" for a source over the whole root, or relative segments ending with "/"');
1147
+ if (f !== "" && !(f.endsWith("/") && st(f.slice(0, -1))))
1148
+ throw new RangeError(`[markdown-explorer] pathPrefix must be empty or relative segments ending with "/"; got ${JSON.stringify(f)}`);
1149
+ const g = ct(e.deny), T = he("maxEntries", e.maxEntries, we.maxEntries), d = he("maxDocumentBytes", e.maxDocumentBytes, we.maxDocumentBytes), p = he("textPreviewBytes", e.textPreviewBytes, we.textPreviewBytes), _ = he("walkConcurrency", e.walkConcurrency, we.walkConcurrency), R = e.cacheScope === void 0 ? "principal" : e.cacheScope;
1122
1150
  if (R !== "principal" && R !== "shared") throw new RangeError(`[markdown-explorer] cacheScope must be "principal" or "shared"; got ${JSON.stringify(R)}`);
1123
1151
  const I = e.reportSkipped;
1124
1152
  if (I !== void 0 && typeof I != "function") throw new TypeError("[markdown-explorer] reportSkipped must be a function");
1125
- const O = I === void 0 ? (a) => {
1126
- console.warn(`[markdown-explorer] the file-system source ${JSON.stringify(a.sourceId)} does not list ${JSON.stringify(a.path)}: ${a.reason}`);
1127
- } : I, x = /* @__PURE__ */ new Set(), v = (a) => {
1128
- const E = Yt(c, ...a.split("/")), b = Pe(c, E);
1129
- return b === "" || b === ".." || b.startsWith(`..${ve}`) || Me(b) ? null : E;
1130
- }, y = (a, E) => {
1131
- const b = `${E}\0${a}`;
1132
- x.has(b) || x.size >= T || (x.add(b), O({ sourceId: t, path: a, reason: E }));
1133
- }, N = async ({ signal: a }) => {
1134
- a.throwIfAborted();
1135
- const E = new AbortController(), b = () => {
1136
- E.abort(a.reason);
1153
+ const O = I === void 0 ? (i) => {
1154
+ console.warn(`[markdown-explorer] the file-system source ${JSON.stringify(i.sourceId)} does not list ${JSON.stringify(i.path)}: ${i.reason}`);
1155
+ } : I, x = /* @__PURE__ */ new Set(), P = (i) => {
1156
+ const E = or(c, ...i.split("/")), S = je(c, E);
1157
+ return S === "" || S === ".." || S.startsWith(`..${Le}`) || $e(S) ? null : E;
1158
+ }, b = (i, E) => {
1159
+ const S = `${E}\0${i}`;
1160
+ x.has(S) || x.size >= T || (x.add(S), O({ sourceId: t, path: i, reason: E }));
1161
+ }, N = async ({ signal: i }) => {
1162
+ i.throwIfAborted();
1163
+ const E = new AbortController(), S = () => {
1164
+ E.abort(i.reason);
1137
1165
  };
1138
- a.addEventListener("abort", b, { once: !0 });
1139
- const k = vn(_);
1166
+ i.addEventListener("abort", S, { once: !0 });
1167
+ const k = Xn(_);
1140
1168
  let A = 0;
1141
1169
  const D = async (M, U) => {
1142
- const G = await k(async () => {
1170
+ const X = await k(async () => {
1143
1171
  E.signal.throwIfAborted();
1144
1172
  try {
1145
- return await Qt(M, { withFileTypes: !0 });
1173
+ return await cr(M, { withFileTypes: !0 });
1146
1174
  } catch ($) {
1147
- if (U === "" || !An($)) throw $;
1175
+ if (U === "" || !Hn($)) throw $;
1148
1176
  return null;
1149
1177
  }
1150
1178
  });
1151
- if (E.signal.throwIfAborted(), G === null)
1152
- return y(`${m}${U}`, "unreadable-directory"), null;
1153
- const B = [];
1154
- for (const $ of G) {
1179
+ if (E.signal.throwIfAborted(), X === null)
1180
+ return b(`${f}${U}`, "unreadable-directory"), null;
1181
+ const F = [];
1182
+ for (const $ of X) {
1155
1183
  if (g.deniesName($.name)) continue;
1156
- const J = U === "" ? $.name : `${U}/${$.name}`, W = `${m}${J}`, Y = $n($, W);
1157
- if (Y !== null) {
1158
- y(W, Y);
1184
+ const J = U === "" ? $.name : `${U}/${$.name}`, K = `${f}${J}`, W = Gn($, K);
1185
+ if (W !== null) {
1186
+ b(K, W);
1159
1187
  continue;
1160
1188
  }
1161
- B.push({ dirent: $, relativePath: J, path: W });
1189
+ F.push({ dirent: $, relativePath: J, path: K });
1162
1190
  }
1163
- if (A += B.length, A > T) throw new Ee("too-large");
1164
- return B.sort(($, J) => Pn($.dirent.name, J.dirent.name)), (await Promise.all(
1165
- B.map(async ({ dirent: $, relativePath: J, path: W }) => {
1166
- if (!$.isDirectory()) return { name: $.name, path: W, type: "file" };
1167
- const Y = await D(Wt(M, $.name), J);
1168
- return Y === null ? null : { name: $.name, path: W, type: "directory", children: Y };
1191
+ if (A += F.length, A > T) throw new Ee("too-large");
1192
+ return F.sort(($, J) => Un($.dirent.name, J.dirent.name)), (await Promise.all(
1193
+ F.map(async ({ dirent: $, relativePath: J, path: K }) => {
1194
+ if (!$.isDirectory()) return { name: $.name, path: K, type: "file" };
1195
+ const W = await D(nr(M, $.name), J);
1196
+ return W === null ? null : { name: $.name, path: K, type: "directory", children: W };
1169
1197
  })
1170
1198
  )).filter(($) => $ !== null);
1171
1199
  };
@@ -1176,78 +1204,78 @@ const br = (e) => e instanceof Error && Object.hasOwn(e, it) && et(e.reason), Sr
1176
1204
  } catch (M) {
1177
1205
  throw E.abort(), M;
1178
1206
  } finally {
1179
- a.removeEventListener("abort", b);
1207
+ i.removeEventListener("abort", S);
1180
1208
  }
1181
- }, z = async (a) => {
1182
- if (!a.startsWith(m)) return { status: "refused", reason: "not-found" };
1183
- const E = a.slice(m.length);
1184
- if (!Qe(E)) return { status: "refused", reason: "invalid" };
1209
+ }, C = async (i) => {
1210
+ if (!i.startsWith(f)) return { status: "refused", reason: "not-found" };
1211
+ const E = i.slice(f.length);
1212
+ if (!st(E)) return { status: "refused", reason: "invalid" };
1185
1213
  if (g.deniesPath(E)) return { status: "refused", reason: "forbidden" };
1186
- const b = v(E);
1187
- if (b === null) return { status: "refused", reason: "forbidden" };
1188
- const k = await Vt(b, { bigint: !0 });
1214
+ const S = P(E);
1215
+ if (S === null) return { status: "refused", reason: "forbidden" };
1216
+ const k = await ar(S, { bigint: !0 });
1189
1217
  if (k.isSymbolicLink()) return { status: "refused", reason: "forbidden" };
1190
1218
  if (!k.isFile()) return { status: "refused", reason: "unsupported" };
1191
- const A = await Zt(b);
1192
- return A !== b || g.deniesPath(Pe(c, A).split(ve).join("/")) ? { status: "refused", reason: "forbidden" } : { status: "file", target: b, name: E.slice(E.lastIndexOf("/") + 1), stats: k };
1193
- }, L = async (a, E, b) => {
1219
+ const A = await ir(S);
1220
+ return A !== S || g.deniesPath(je(c, A).split(Le).join("/")) ? { status: "refused", reason: "forbidden" } : { status: "file", target: S, name: E.slice(E.lastIndexOf("/") + 1), stats: k };
1221
+ }, z = async (i, E, S) => {
1194
1222
  let k;
1195
1223
  try {
1196
- const A = await z(b);
1224
+ const A = await C(S);
1197
1225
  if (A.status === "refused") return ee(A.reason);
1198
- const { target: D, name: M, stats: U } = A, G = Nn(M), B = Ze(U);
1199
- if (G.kind === "image") return { kind: "image", name: M, version: B };
1200
- if (G.kind === "media") return { kind: "media", name: M, mediaType: G.mediaType, version: B };
1201
- if (G.kind === "file") return { kind: "file", name: M, version: B };
1202
- k = await nt(D, ce.O_RDONLY | mt | pt);
1226
+ const { target: D, name: M, stats: U } = A, X = Dn(M), F = ot(U);
1227
+ if (X.kind === "image") return { kind: "image", name: M, version: F };
1228
+ if (X.kind === "media") return { kind: "media", name: M, mediaType: X.mediaType, version: F };
1229
+ if (X.kind === "file") return { kind: "file", name: M, version: F };
1230
+ k = await lt(D, ie.O_RDONLY | bt | St);
1203
1231
  const Z = await k.stat({ bigint: !0 });
1204
1232
  if (!Z.isFile() || Z.ino !== U.ino || Z.dev !== U.dev) return ee("forbidden");
1205
- if (G.kind === "markdown") {
1206
- if (Z.size > BigInt(l)) return ee("too-large");
1207
- const Y = await qe(k, l + 1);
1208
- if (Y.length > l) return ee("too-large");
1209
- const ue = await s(new TextDecoder("utf-8").decode(Y), E);
1210
- return { kind: "markdown", name: M, htmlContent: ue.htmlContent, headings: ue.headings };
1233
+ if (X.kind === "markdown") {
1234
+ if (Z.size > BigInt(d)) return ee("too-large");
1235
+ const W = await at(k, d + 1);
1236
+ if (W.length > d) return ee("too-large");
1237
+ const le = await a(new TextDecoder("utf-8").decode(W), E);
1238
+ return { kind: "markdown", name: M, htmlContent: le.htmlContent, headings: le.headings };
1211
1239
  }
1212
- const $ = await qe(k, w);
1213
- if ($.includes(0)) return { kind: "file", name: M, version: B };
1214
- const J = Z.size > BigInt(w), W = new TextDecoder("utf-8").decode($, { stream: J });
1215
- return { kind: "text", name: M, text: W, truncated: J, version: B };
1240
+ const $ = await at(k, p);
1241
+ if ($.includes(0)) return { kind: "file", name: M, version: F };
1242
+ const J = Z.size > BigInt(p), K = new TextDecoder("utf-8").decode($, { stream: J });
1243
+ return { kind: "text", name: M, text: K, truncated: J, version: F };
1216
1244
  } catch (A) {
1217
- const D = ht(A);
1245
+ const D = xt(A);
1218
1246
  if (D === null) throw A;
1219
1247
  return ee(D);
1220
1248
  } finally {
1221
1249
  await k?.close();
1222
1250
  }
1223
- }, u = async (a, E, b) => {
1251
+ }, u = async (i, E, S) => {
1224
1252
  let k;
1225
1253
  try {
1226
- k = await z(b);
1227
- } catch (B) {
1228
- throw gt(B);
1254
+ k = await C(S);
1255
+ } catch (F) {
1256
+ throw Ot(F);
1229
1257
  }
1230
1258
  if (k.status === "refused") throw new Ee(k.reason);
1231
- const { target: A, name: D, stats: M } = k, U = ft.get(wt(D)), G = U === void 0 ? "" : U.contentType;
1232
- return { name: D, contentType: G, size: Number(M.size), version: Ze(M), open: (B) => Mn(A, M, B, a.signal) };
1259
+ const { target: A, name: D, stats: M } = k, U = yt.get(Tt(D)), X = U === void 0 ? "" : U.contentType;
1260
+ return { name: D, contentType: X, size: Number(M.size), version: ot(M), open: (F) => Fn(A, M, F, i.signal) };
1233
1261
  };
1234
1262
  return Object.freeze({
1235
1263
  id: t,
1236
1264
  label: r,
1237
1265
  cacheScope: R,
1238
- boundary: Object.freeze({ contains: (a) => a.startsWith(m) }),
1266
+ boundary: Object.freeze({ contains: (i) => i.startsWith(f) }),
1239
1267
  tree: N,
1240
- document: L,
1268
+ document: z,
1241
1269
  asset: u
1242
1270
  });
1243
1271
  };
1244
1272
  export {
1245
- Qn as DEFAULT_DENIED_PATH_SEGMENTS,
1273
+ lo as DEFAULT_DENIED_PATH_SEGMENTS,
1246
1274
  Ee as ExplorerError,
1247
- qn as MAX_DOCUMENT_PATH_LENGTH,
1248
- Wn as anonymousAccess,
1249
- Kn as createFileSystemSource,
1250
- Yn as createMarkdownExplorer,
1275
+ fo as MAX_DOCUMENT_PATH_LENGTH,
1276
+ so as anonymousAccess,
1277
+ io as createFileSystemSource,
1278
+ ao as createMarkdownExplorer,
1251
1279
  te as isAcceptableDocumentPath,
1252
- eo as isDeniedPath
1280
+ mo as isDeniedPath
1253
1281
  };