@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
@@ -1,291 +1,281 @@
1
- import { parentPort as Z } from "node:worker_threads";
2
- import { defaultTreeAdapter as b, parse as ee, html as te } from "parse5";
1
+ import { parentPort as ee } from "node:worker_threads";
2
+ import { defaultTreeAdapter as b, parse as te, html as re } from "parse5";
3
+ import { allowedFrameUrlOf as ne, reduceFrameFeatures as oe, EMBED_FRAME_REFERRER_POLICIES as se, EMBED_LINK_ATTRIBUTE as H, placeholderLinkOf as ae } from "@aiquants/markdown/embeds";
3
4
  import S from "isomorphic-dompurify";
4
- import { i as re, e as ne } from "./dataRoute-Bkfwfp1R.js";
5
- const B = 512, oe = 4096, F = 1024, P = /* @__PURE__ */ Symbol("placement"), G = 2, se = 3, ae = /* @__PURE__ */ new Set(["html", "head", "body"]), _ = 0, y = 1, I = 2, j = 3, D = 4, L = 5, O = 6, N = 7, V = 8, k = 9, W = 10, w = -1, ie = 0, ce = 1, le = 2, ue = 3, fe = 4, de = 5, X = 6, pe = 7, me = (t) => {
5
+ import { i as ie, e as ce } from "./dataRoute-zUX-oR9j.js";
6
+ const F = 512, le = 4096, G = 1024, j = /* @__PURE__ */ Symbol("placement"), V = 2, ue = 3, fe = /* @__PURE__ */ new Set(["html", "head", "body"]), w = 0, D = 1, M = 2, W = 3, z = 4, O = 5, k = 6, N = 7, Q = 8, I = 9, $ = 10, _ = -1, de = 0, pe = 1, Ee = 2, me = 3, he = 4, Te = 5, K = 6, Ae = 7, ge = (t) => {
6
7
  switch (t) {
7
8
  case 9:
8
9
  case 10:
9
10
  case 12:
10
11
  case 13:
11
12
  case 32:
12
- return ie;
13
+ return de;
13
14
  case 47:
14
- return ce;
15
+ return pe;
15
16
  case 62:
16
- return le;
17
+ return Ee;
17
18
  case 61:
18
- return ue;
19
+ return me;
19
20
  case 34:
20
- return fe;
21
+ return he;
21
22
  case 39:
22
- return de;
23
+ return Te;
23
24
  default:
24
- return X;
25
+ return K;
25
26
  }
26
- }, Ee = Uint8Array.from({ length: 128 }, (t, n) => me(n)), U = 60, Q = 47, he = /[\t\n\f\r />="'<]/g, Ae = /["<]/g, Te = /['<]/g, A = -1 - I, ge = Int8Array.from(
27
+ }, Se = Uint8Array.from({ length: 128 }, (t, i) => ge(i)), v = 60, X = 47, _e = /[\t\n\f\r />="'<]/g, we = /["<]/g, be = /['<]/g, A = -1 - M, Ne = Int8Array.from(
27
28
  [
28
- [y, k, w, _, _, _, _],
29
- [y, k, w, A, A, A, A],
30
- [j, k, w, D, I, I, I],
31
- [j, k, w, D, A, A, A],
32
- [D, N, w, N, L, O, N],
33
- [L, L, L, L, V, L, L],
34
- [O, O, O, O, O, V, O],
35
- [y, N, w, N, N, N, N],
36
- [y, k, w, A, A, A, A],
37
- [y, k, w, A, A, A, A]
29
+ [D, I, _, w, w, w, w],
30
+ [D, I, _, A, A, A, A],
31
+ [W, I, _, z, M, M, M],
32
+ [W, I, _, z, A, A, A],
33
+ [z, N, _, N, O, k, N],
34
+ [O, O, O, O, Q, O, O],
35
+ [k, k, k, k, k, Q, k],
36
+ [D, N, _, N, N, N, N],
37
+ [D, I, _, A, A, A, A],
38
+ [D, I, _, A, A, A, A]
38
39
  ].flat()
39
- ), $ = (t) => t >= 65 && t <= 90 || t >= 97 && t <= 122, Se = (t, n) => {
40
- let o = new Int32Array(W), l = new Int32Array(W), i = 0, T = 0, s = 0;
41
- for (; s < t.length; ) {
42
- if (i === 0) {
43
- const r = t.indexOf("<", s);
44
- if (r < 0) return !1;
45
- s = r + 1, t.charCodeAt(s) === Q && (s += 1), $(t.charCodeAt(s)) && (o[_] = 0, i = 1 << _, s += 1);
40
+ ), J = (t) => t >= 65 && t <= 90 || t >= 97 && t <= 122, Oe = (t, i) => {
41
+ let u = new Int32Array($), f = new Int32Array($), c = 0, h = 0, n = 0;
42
+ for (; n < t.length; ) {
43
+ if (c === 0) {
44
+ const p = t.indexOf("<", n);
45
+ if (p < 0) return !1;
46
+ n = p + 1, t.charCodeAt(n) === X && (n += 1), J(t.charCodeAt(n)) && (u[w] = 0, c = 1 << w, n += 1);
46
47
  continue;
47
48
  }
48
- if ((i & -230) === 0 && s >= T) {
49
- const r = i === 1 << L ? Ae : i === 1 << O ? Te : he;
50
- r.lastIndex = s;
51
- const d = r.exec(t);
52
- if (d === null) return !1;
53
- s = d.index, t.charCodeAt(s) === U && (T = s + 3);
49
+ if ((c & -230) === 0 && n >= h) {
50
+ const p = c === 1 << O ? we : c === 1 << k ? be : _e;
51
+ p.lastIndex = n;
52
+ const a = p.exec(t);
53
+ if (a === null) return !1;
54
+ n = a.index, t.charCodeAt(n) === v && (h = n + 3);
54
55
  }
55
- const E = t.charCodeAt(s), g = E < 128 ? Ee[E] : X;
56
- let h = 0;
57
- for (let r = i; r !== 0; r &= r - 1) {
58
- const d = 31 - Math.clz32(r & -r);
59
- let f = ge[d * pe + g], m = o[d];
60
- if (f < w && (f = -1 - f, m += 1, m > n))
56
+ const m = t.charCodeAt(n), g = m < 128 ? Se[m] : K;
57
+ let T = 0;
58
+ for (let p = c; p !== 0; p &= p - 1) {
59
+ const a = 31 - Math.clz32(p & -p);
60
+ let r = Ne[a * Ae + g], o = u[a];
61
+ if (r < _ && (r = -1 - r, o += 1, o > i))
61
62
  return !0;
62
- if (f === w) continue;
63
- const R = 1 << f;
64
- ((h & R) === 0 || m > l[f]) && (l[f] = m), h |= R;
63
+ if (r === _) continue;
64
+ const E = 1 << r;
65
+ ((T & E) === 0 || o > f[r]) && (f[r] = o), T |= E;
65
66
  }
66
- $(E) && (t.charCodeAt(s - 1) === U || t.charCodeAt(s - 1) === Q && t.charCodeAt(s - 2) === U) && (h & 1 << _) === 0 && (l[_] = 0, h |= 1 << _);
67
- const u = o;
68
- o = l, l = u, i = h, s += 1;
67
+ J(m) && (t.charCodeAt(n - 1) === v || t.charCodeAt(n - 1) === X && t.charCodeAt(n - 2) === v) && (T & 1 << w) === 0 && (f[w] = 0, T |= 1 << w);
68
+ const L = u;
69
+ u = f, f = L, c = T, n += 1;
69
70
  }
70
71
  return !1;
71
72
  };
72
73
  class C extends Error {
73
74
  status;
74
- constructor(n) {
75
- super(`[markdown-explorer] the nesting guard stopped the parse: ${n}`), this.name = "ParseStop", this.status = n;
75
+ constructor(i) {
76
+ super(`[markdown-explorer] the nesting guard stopped the parse: ${i}`), this.name = "ParseStop", this.status = i;
76
77
  }
77
78
  }
78
- const we = (t, n, o, l) => {
79
- if (!Number.isSafeInteger(n) || n <= 0) throw new RangeError(`[markdown-explorer] the nesting guard's depth limit must be a positive safe integer; got ${String(n)}`);
80
- if (!Number.isSafeInteger(o) || o <= 0) throw new RangeError(`[markdown-explorer] the nesting guard's node budget must be a positive safe integer; got ${String(o)}`);
81
- if (!Number.isSafeInteger(l) || l <= 0) throw new RangeError(`[markdown-explorer] the nesting guard's attribute character budget must be a positive safe integer; got ${String(l)}`);
82
- if (Se(t, F)) return { status: "too-many-attributes" };
83
- const i = n + G, T = t.length + se;
84
- let s = null, E = 0, g = 0, h = 0, u = 0;
85
- const r = (e) => {
86
- if (g += e, g > o) throw new C("too-many-nodes");
87
- }, d = (e) => {
88
- for (const a of e) u += a.name.length + a.value.length;
89
- if (u > l) throw new C("too-many-attribute-characters");
90
- }, f = (e, a, c, p) => {
91
- const v = { node: e, above: null, levels: a, height: 0, keepsChildren: c, attributes: p, first: null, next: null, previous: null }, q = e;
92
- return q[P] = v, v;
93
- }, m = (e) => {
94
- const c = e[P];
95
- if (c === void 0) throw new Error("[markdown-explorer] the nesting guard was handed a node it did not create");
96
- return c;
97
- }, R = (e, a) => {
98
- let c = a;
99
- for (let p = e; p !== null && c > p.height; p = p.above)
100
- p.height = c, c += p.levels;
101
- if (s !== null && s.height > i) throw new C("too-deep");
102
- }, M = (e) => {
103
- const a = e.above;
104
- a?.keepsChildren && (e.previous === null ? a.first = e.next : e.previous.next = e.next, e.next !== null && (e.next.previous = e.previous)), e.above = null, e.next = null, e.previous = null;
105
- }, H = (e, a) => {
106
- if (!b.isElementNode(a)) return;
107
- const c = m(a), p = m(e);
108
- M(c), c.above = p, p.keepsChildren && (c.next = p.first, p.first !== null && (p.first.previous = c), p.first = c), a.parentNode = e, R(p, c.height + c.levels);
109
- }, K = {
79
+ const ke = (t, i, u, f) => {
80
+ if (!Number.isSafeInteger(i) || i <= 0) throw new RangeError(`[markdown-explorer] the nesting guard's depth limit must be a positive safe integer; got ${String(i)}`);
81
+ if (!Number.isSafeInteger(u) || u <= 0) throw new RangeError(`[markdown-explorer] the nesting guard's node budget must be a positive safe integer; got ${String(u)}`);
82
+ if (!Number.isSafeInteger(f) || f <= 0) throw new RangeError(`[markdown-explorer] the nesting guard's attribute character budget must be a positive safe integer; got ${String(f)}`);
83
+ if (Oe(t, G)) return { status: "too-many-attributes" };
84
+ const c = i + V, h = t.length + ue;
85
+ let n = null, m = 0, g = 0, T = 0, L = 0;
86
+ const p = (e) => {
87
+ if (g += e, g > u) throw new C("too-many-nodes");
88
+ }, a = (e) => {
89
+ for (const s of e) L += s.name.length + s.value.length;
90
+ if (L > f) throw new C("too-many-attribute-characters");
91
+ }, r = (e, s, l, d) => {
92
+ const P = { node: e, above: null, levels: s, height: 0, keepsChildren: l, attributes: d, first: null, next: null, previous: null }, Z = e;
93
+ return Z[j] = P, P;
94
+ }, o = (e) => {
95
+ const l = e[j];
96
+ if (l === void 0) throw new Error("[markdown-explorer] the nesting guard was handed a node it did not create");
97
+ return l;
98
+ }, E = (e, s) => {
99
+ let l = s;
100
+ for (let d = e; d !== null && l > d.height; d = d.above)
101
+ d.height = l, l += d.levels;
102
+ if (n !== null && n.height > c) throw new C("too-deep");
103
+ }, y = (e) => {
104
+ const s = e.above;
105
+ s?.keepsChildren && (e.previous === null ? s.first = e.next : e.previous.next = e.next, e.next !== null && (e.next.previous = e.previous)), e.above = null, e.next = null, e.previous = null;
106
+ }, R = (e, s) => {
107
+ if (!b.isElementNode(s)) return;
108
+ const l = o(s), d = o(e);
109
+ y(l), l.above = d, d.keepsChildren && (l.next = d.first, d.first !== null && (d.first.previous = l), d.first = l), s.parentNode = e, E(d, l.height + l.levels);
110
+ }, x = {
110
111
  ...b,
111
112
  createDocument: () => {
112
113
  const e = b.createDocument();
113
- return s = f(e, 0, !1, 0), e;
114
+ return n = r(e, 0, !1, 0), e;
114
115
  },
115
116
  createDocumentFragment: () => {
116
117
  const e = b.createDocumentFragment();
117
- return f(e, 0, !1, 0), e;
118
+ return r(e, 0, !1, 0), e;
118
119
  },
119
- createElement: (e, a, c) => {
120
- if (E += 1, E > T) throw new C("too-many-elements");
121
- r(1 + c.length), d(c);
122
- const p = b.createElement(e, a, c);
123
- return f(p, 1, !(a === te.NS.HTML && ae.has(e)), c.length), p;
120
+ createElement: (e, s, l) => {
121
+ if (m += 1, m > h) throw new C("too-many-elements");
122
+ p(1 + l.length), a(l);
123
+ const d = b.createElement(e, s, l);
124
+ return r(d, 1, !(s === re.NS.HTML && fe.has(e)), l.length), d;
124
125
  },
125
126
  createCommentNode: (e) => {
126
- if (h += 1, h > oe) throw new C("too-many-comments");
127
- return r(1), b.createCommentNode(e);
127
+ if (T += 1, T > le) throw new C("too-many-comments");
128
+ return p(1), b.createCommentNode(e);
128
129
  },
129
- setTemplateContent: (e, a) => {
130
- b.setTemplateContent(e, a);
131
- const c = m(a);
132
- c.above = m(e), R(c.above, c.height);
130
+ setTemplateContent: (e, s) => {
131
+ b.setTemplateContent(e, s);
132
+ const l = o(s);
133
+ l.above = o(e), E(l.above, l.height);
133
134
  },
134
- appendChild: H,
135
- insertBefore: (e, a) => H(e, a),
135
+ appendChild: R,
136
+ insertBefore: (e, s) => R(e, s),
136
137
  detachNode: (e) => {
137
- b.isElementNode(e) && (M(m(e)), e.parentNode = null);
138
+ b.isElementNode(e) && (y(o(e)), e.parentNode = null);
138
139
  },
139
140
  getFirstChild: (e) => {
140
- const a = m(e);
141
- if (!a.keepsChildren) throw new Error("[markdown-explorer] the nesting guard was asked for the children of a node whose children it does not keep");
142
- return a.first === null ? null : a.first.node;
141
+ const s = o(e);
142
+ if (!s.keepsChildren) throw new Error("[markdown-explorer] the nesting guard was asked for the children of a node whose children it does not keep");
143
+ return s.first === null ? null : s.first.node;
143
144
  },
144
145
  getChildNodes: () => {
145
146
  throw new Error("[markdown-explorer] the nesting guard keeps no child lists for source locations");
146
147
  },
147
148
  onItemPop: (e) => {
148
- const a = m(e);
149
- a.keepsChildren = !1, a.first = null;
149
+ const s = o(e);
150
+ s.keepsChildren = !1, s.first = null;
150
151
  },
151
152
  insertText: () => {
152
153
  },
153
154
  insertTextBefore: () => {
154
155
  },
155
- adoptAttributes: (e, a) => {
156
- r(a.length), d(a);
157
- const c = m(e);
158
- if (c.attributes += a.length, c.attributes > F) throw new C("too-many-attributes");
156
+ adoptAttributes: (e, s) => {
157
+ p(s.length), a(s);
158
+ const l = o(e);
159
+ if (l.attributes += s.length, l.attributes > G) throw new C("too-many-attributes");
159
160
  }
160
161
  };
161
- let z;
162
+ let B;
162
163
  try {
163
- z = ee(t, { scriptingEnabled: !1, treeAdapter: K });
164
+ B = te(t, { scriptingEnabled: !1, treeAdapter: x });
164
165
  } catch (e) {
165
166
  if (e instanceof C) return { status: e.status };
166
167
  throw e;
167
168
  }
168
- return { status: "within", depth: m(z).height - G, elements: E, nodes: g };
169
+ return { status: "within", depth: o(B).height - V, elements: m, nodes: g };
169
170
  };
170
- class J extends RangeError {
171
- constructor(n) {
172
- super(`[markdown-explorer] the HTML nests deeper than ${String(n)} levels`), this.name = "HtmlNestingLimitError";
171
+ class Y extends RangeError {
172
+ constructor(i) {
173
+ super(`[markdown-explorer] the HTML nests deeper than ${String(i)} levels`), this.name = "HtmlNestingLimitError";
173
174
  }
174
175
  }
175
- const _e = ["script", "style", "noscript", "template", "form", "button", "textarea", "select", "option", "object", "embed", "base", "meta", "link", "frame", "frameset"], be = ["srcdoc", "formaction"], Ne = /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/iu, Le = /* @__PURE__ */ new Set(["left", "right", "center", "justify", "start", "end"]), Oe = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6"]), x = 1, Y = Object.freeze({
176
+ const Ce = ["script", "style", "noscript", "template", "form", "button", "textarea", "select", "option", "object", "embed", "base", "meta", "link", "frame", "frameset"], Le = ["srcdoc", "formaction"], Re = /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/iu, Ie = /* @__PURE__ */ new Set(["left", "right", "center", "justify", "start", "end"]), ye = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6"]), U = 1, De = 3, Me = 7, Ue = 8, q = Object.freeze({
176
177
  a: Object.freeze(["target", "data-link-kind", "data-doc-path", "data-doc-exists", "data-footnote-ref", "data-footnote-backref"]),
177
178
  area: Object.freeze(["target"]),
178
179
  img: Object.freeze(["data-asset-src", "data-asset-exists"]),
179
180
  section: Object.freeze(["data-footnotes"]),
180
181
  iframe: Object.freeze(["allow", "allowfullscreen", "frameborder", "referrerpolicy"])
181
- }), Re = [...new Set(Object.values(Y).flatMap((t) => t.filter((n) => n.startsWith("data-"))))], Ce = /* @__PURE__ */ new Set(["no-referrer", "origin", "same-origin", "strict-origin", "strict-origin-when-cross-origin"]), ke = /* @__PURE__ */ new Set(["autoplay", "clipboard-write", "encrypted-media", "fullscreen", "picture-in-picture", "web-share"]), ye = /* @__PURE__ */ new Set(["src", "href", "xlink:href"]), Ie = /^data:/iu, De = Object.freeze({
182
- FORBID_TAGS: _e,
183
- FORBID_ATTR: be,
182
+ }), xe = [...new Set(Object.values(q).flatMap((t) => t.filter((i) => i.startsWith("data-"))))], He = /* @__PURE__ */ new Set(["src", "href", "xlink:href"]), ze = /^data:/iu, ve = Object.freeze({
183
+ FORBID_TAGS: Ce,
184
+ FORBID_ATTR: Le,
184
185
  ADD_TAGS: ["iframe"],
185
- ADD_ATTR: (t, n) => Y[n]?.includes(t) === !0,
186
- ADD_URI_SAFE_ATTR: Re,
187
- ALLOWED_URI_REGEXP: Ne,
186
+ ADD_ATTR: (t, i) => q[i]?.includes(t) === !0,
187
+ ADD_URI_SAFE_ATTR: xe,
188
+ ALLOWED_URI_REGEXP: Re,
188
189
  ALLOW_DATA_ATTR: !1
189
- }), Ue = (t) => {
190
- let n = null;
191
- for (const o of t.split(";")) {
192
- const l = o.indexOf(":");
193
- if (l < 0 || o.slice(0, l).trim().toLowerCase() !== "text-align") continue;
194
- const i = o.slice(l + 1).trim().toLowerCase();
195
- Le.has(i) && (n = i);
196
- }
197
- return n === null ? null : `text-align: ${n}`;
198
- }, xe = (t) => {
199
- const n = /* @__PURE__ */ new Set();
200
- for (const o of t.split(";")) {
201
- const [l] = o.trim().toLowerCase().split(/\s+/u);
202
- l !== void 0 && ke.has(l) && n.add(l);
203
- }
204
- return n.size === 0 ? null : [...n].join("; ");
205
- }, Me = (t, n) => {
206
- if (t === null) return !1;
207
- let o;
208
- try {
209
- o = new URL(t.trim());
210
- } catch {
211
- return !1;
190
+ }), Be = (t) => {
191
+ let i = null;
192
+ for (const u of t.split(";")) {
193
+ const f = u.indexOf(":");
194
+ if (f < 0 || u.slice(0, f).trim().toLowerCase() !== "text-align") continue;
195
+ const c = u.slice(f + 1).trim().toLowerCase();
196
+ Ie.has(c) && (i = c);
212
197
  }
213
- return o.protocol === "https:" && o.username === "" && o.password === "" && o.port === "" && n.has(o.hostname);
214
- }, He = (t) => {
215
- const n = t.getAttribute("type");
216
- return n !== null && n.trim().toLowerCase() === "checkbox" && t.hasAttribute("disabled");
217
- }, ze = (t, n, o) => {
198
+ return i === null ? null : `text-align: ${i}`;
199
+ }, Pe = (t) => t.nodeType === De ? { kind: "text", text: t.nodeValue ?? "" } : t.nodeType === Ue || t.nodeType === Me ? { kind: "ignored" } : t.nodeType === U && t.nodeName.toLowerCase() === "a" ? { kind: "link", href: t.getAttribute("href") } : { kind: "element" }, Fe = (t) => {
200
+ const i = t.getAttribute("type");
201
+ return i !== null && i.trim().toLowerCase() === "checkbox" && t.hasAttribute("disabled");
202
+ }, Ge = (t, i, u) => {
218
203
  if (S.isSupported !== !0) throw new Error("[markdown-explorer] the HTML sanitizer cannot run in this environment");
219
- if (!Number.isSafeInteger(o) || o <= 0) throw new RangeError(`[markdown-explorer] the HTML sanitizer's depth limit must be a positive integer; got ${String(o)}`);
220
- const l = new Set(t);
221
- let i = /* @__PURE__ */ new WeakMap();
222
- const T = (u) => {
223
- const r = u.parentNode === null ? void 0 : i.get(u.parentNode), d = r === void 0 ? 0 : r + 1;
224
- if (i.set(u, d), u.nodeType === x && d > o) throw new J(o);
225
- }, s = (u, r) => {
226
- if (u.nodeType !== x) return;
227
- const d = u;
228
- (r.tagName === "input" && !He(d) || r.tagName === "iframe" && !Me(d.getAttribute("src"), l)) && d.parentNode?.removeChild(d);
229
- }, E = (u, r) => {
230
- const d = u.nodeName.toLowerCase();
204
+ if (!Number.isSafeInteger(u) || u <= 0) throw new RangeError(`[markdown-explorer] the HTML sanitizer's depth limit must be a positive integer; got ${String(u)}`);
205
+ const f = Object.freeze([...t]);
206
+ let c = /* @__PURE__ */ new WeakMap(), h = /* @__PURE__ */ new WeakMap();
207
+ const n = (a) => {
208
+ const r = a.parentNode === null ? void 0 : c.get(a.parentNode), o = r === void 0 ? 0 : r + 1;
209
+ if (c.set(a, o), a.nodeType === U && o > u) throw new Y(u);
210
+ }, m = (a, r) => {
211
+ if (a.nodeType !== U) return;
212
+ const o = a;
213
+ (r.tagName === "input" && !Fe(o) || r.tagName === "iframe" && ne(o.getAttribute("src")?.trim(), f) === null) && o.parentNode?.removeChild(o);
214
+ }, g = (a, r) => {
215
+ const o = a.nodeName.toLowerCase();
231
216
  if (r.attrName === "style") {
232
- const f = Ue(r.attrValue);
233
- f === null ? r.keepAttr = !1 : r.attrValue = f;
234
- } else if (r.attrName === "allow" && d === "iframe") {
235
- const f = xe(r.attrValue);
236
- f === null ? r.keepAttr = !1 : r.attrValue = f;
237
- } else if (r.attrName === "referrerpolicy" && d === "iframe") {
238
- const f = r.attrValue.trim().toLowerCase();
239
- Ce.has(f) ? r.attrValue = f : r.keepAttr = !1;
240
- } else ye.has(r.attrName) && Ie.test(r.attrValue) ? r.keepAttr = !1 : r.attrName === "id" && Oe.has(d) && (r.forceKeepAttr = !0);
241
- }, g = (u) => {
242
- const r = u.getAttribute("data-asset-src");
243
- r !== null && (u.getAttribute("data-asset-exists") !== "false" && re(r) ? u.setAttribute("src", ne(n, r, null)) : u.removeAttribute("src"));
244
- }, h = (u) => {
245
- if (u.nodeType !== x) return;
246
- const r = u;
247
- r.nodeName.toLowerCase() === "img" && g(r);
248
- const d = r.getAttribute("target");
249
- if (d === null || d.trim().toLowerCase() === "_self") return;
250
- const f = r.getAttribute("rel"), m = new Set(f === null ? [] : f.split(/\s+/u).filter((R) => R !== ""));
251
- m.add("noopener"), m.add("noreferrer"), r.setAttribute("rel", [...m].join(" "));
217
+ const E = Be(r.attrValue);
218
+ E === null ? r.keepAttr = !1 : r.attrValue = E;
219
+ } else if (r.attrName === "allow" && o === "iframe") {
220
+ const E = oe(r.attrValue);
221
+ E === null ? r.keepAttr = !1 : r.attrValue = E;
222
+ } else if (r.attrName === "referrerpolicy" && o === "iframe") {
223
+ const E = r.attrValue.trim().toLowerCase();
224
+ se.has(E) ? r.attrValue = E : r.keepAttr = !1;
225
+ } else r.attrName === H && o === "p" ? h.set(a, a.getAttribute(H)) : He.has(r.attrName) && ze.test(r.attrValue) ? r.keepAttr = !1 : r.attrName === "id" && ye.has(o) && (r.forceKeepAttr = !0);
226
+ }, T = (a) => {
227
+ const r = a.getAttribute("data-asset-src");
228
+ r !== null && (a.getAttribute("data-asset-exists") !== "false" && ie(r) ? a.setAttribute("src", ce(i, r, null)) : a.removeAttribute("src"));
229
+ }, L = (a) => {
230
+ const r = a.parentNode;
231
+ if (r === null) return;
232
+ const o = h.get(r);
233
+ o != null && ae(o, [...r.childNodes].map(Pe)) !== null && r.setAttribute(H, o);
234
+ }, p = (a) => {
235
+ if (a.nodeType !== U) return;
236
+ const r = a, o = r.nodeName.toLowerCase();
237
+ o === "img" ? T(r) : o === "a" && L(r);
238
+ const E = r.getAttribute("target");
239
+ if (E === null || E.trim().toLowerCase() === "_self") return;
240
+ const y = r.getAttribute("rel"), R = new Set(y === null ? [] : y.split(/\s+/u).filter((x) => x !== ""));
241
+ R.add("noopener"), R.add("noreferrer"), r.setAttribute("rel", [...R].join(" "));
252
242
  };
253
- return (u) => {
254
- i = /* @__PURE__ */ new WeakMap(), S.addHook("beforeSanitizeElements", T), S.addHook("uponSanitizeElement", s), S.addHook("uponSanitizeAttribute", E), S.addHook("afterSanitizeAttributes", h);
243
+ return (a) => {
244
+ c = /* @__PURE__ */ new WeakMap(), h = /* @__PURE__ */ new WeakMap(), S.addHook("beforeSanitizeElements", n), S.addHook("uponSanitizeElement", m), S.addHook("uponSanitizeAttribute", g), S.addHook("afterSanitizeAttributes", p);
255
245
  try {
256
- return S.sanitize(u, De);
246
+ return S.sanitize(a, ve);
257
247
  } finally {
258
- S.removeHook("beforeSanitizeElements", T), S.removeHook("uponSanitizeElement", s), S.removeHook("uponSanitizeAttribute", E), S.removeHook("afterSanitizeAttributes", h);
248
+ S.removeHook("beforeSanitizeElements", n), S.removeHook("uponSanitizeElement", m), S.removeHook("uponSanitizeAttribute", g), S.removeHook("afterSanitizeAttributes", p);
259
249
  }
260
250
  };
261
- }, ve = (t) => {
251
+ }, je = (t) => {
262
252
  if (t === null || typeof t != "object") return !1;
263
- const { id: n, input: o } = t;
264
- if (typeof n != "number" || o === null || typeof o != "object") return !1;
265
- const { html: l, iframeHosts: i, dataPath: T, maxNodes: s, maxAttributeChars: E, maxSanitizedChars: g } = o;
266
- return typeof l == "string" && Array.isArray(i) && i.every((h) => typeof h == "string") && typeof T == "string" && T !== "" && [s, E, g].every((h) => Number.isSafeInteger(h) && h > 0);
267
- }, Be = () => {
268
- const t = Z;
253
+ const { id: i, input: u } = t;
254
+ if (typeof i != "number" || u === null || typeof u != "object") return !1;
255
+ const { html: f, iframeHosts: c, dataPath: h, maxNodes: n, maxAttributeChars: m, maxSanitizedChars: g } = u;
256
+ return typeof f == "string" && Array.isArray(c) && c.every((T) => typeof T == "string") && typeof h == "string" && h !== "" && [n, m, g].every((T) => Number.isSafeInteger(T) && T > 0);
257
+ }, Ve = () => {
258
+ const t = ee;
269
259
  if (t === null) throw new Error("[markdown-explorer] the sanitizer worker must run in a worker thread");
270
- const n = /* @__PURE__ */ new Map();
271
- t.on("message", (o) => {
272
- if (!ve(o)) throw new TypeError("[markdown-explorer] the sanitizer worker received a message that is not a job");
273
- const { id: l, input: i } = o;
274
- let T;
260
+ const i = /* @__PURE__ */ new Map();
261
+ t.on("message", (u) => {
262
+ if (!je(u)) throw new TypeError("[markdown-explorer] the sanitizer worker received a message that is not a job");
263
+ const { id: f, input: c } = u;
264
+ let h;
275
265
  try {
276
- if (we(i.html, B, i.maxNodes, i.maxAttributeChars).status !== "within") {
277
- t.postMessage({ id: l, output: { status: "too-large" } });
266
+ if (ke(c.html, F, c.maxNodes, c.maxAttributeChars).status !== "within") {
267
+ t.postMessage({ id: f, output: { status: "too-large" } });
278
268
  return;
279
269
  }
280
- const s = JSON.stringify([i.iframeHosts, i.dataPath]);
281
- let E = n.get(s);
282
- E === void 0 && (E = ze(i.iframeHosts, i.dataPath, B), n.set(s, E));
283
- const g = E(i.html);
284
- T = g.length > i.maxSanitizedChars ? { status: "too-large" } : { status: "sanitized", html: g };
285
- } catch (s) {
286
- T = s instanceof J ? { status: "too-large" } : { status: "error", message: s instanceof Error ? `${s.name}: ${s.message}` : String(s) };
270
+ const n = JSON.stringify([c.iframeHosts, c.dataPath]);
271
+ let m = i.get(n);
272
+ m === void 0 && (m = Ge(c.iframeHosts, c.dataPath, F), i.set(n, m));
273
+ const g = m(c.html);
274
+ h = g.length > c.maxSanitizedChars ? { status: "too-large" } : { status: "sanitized", html: g };
275
+ } catch (n) {
276
+ h = n instanceof Y ? { status: "too-large" } : { status: "error", message: n instanceof Error ? `${n.name}: ${n.message}` : String(n) };
287
277
  }
288
- t.postMessage({ id: l, output: T });
278
+ t.postMessage({ id: f, output: h });
289
279
  }), t.postMessage({ ready: !0 });
290
280
  };
291
- Be();
281
+ Ve();
@@ -1,9 +1,9 @@
1
- import { ExplorerAuthentication } from "./ports.cjs";
1
+ import { ExplorerAuthentication, ExplorerAuthenticationMode } from "./ports.cjs";
2
2
  export type AnonymousPrincipal = {
3
3
  readonly kind: "anonymous";
4
4
  };
5
5
  export type AnonymousAccess = {
6
- readonly authenticate: (request: Request) => Promise<ExplorerAuthentication<AnonymousPrincipal>>;
6
+ readonly authenticate: (request: Request, mode: ExplorerAuthenticationMode) => Promise<ExplorerAuthentication<AnonymousPrincipal>>;
7
7
  readonly principalKey: (principal: AnonymousPrincipal) => string;
8
8
  readonly signedOutPage: (request: Request, headers: Headers) => Response;
9
9
  };
@@ -1,9 +1,9 @@
1
- import { ExplorerAuthentication } from "./ports.js";
1
+ import { ExplorerAuthentication, ExplorerAuthenticationMode } from "./ports.js";
2
2
  export type AnonymousPrincipal = {
3
3
  readonly kind: "anonymous";
4
4
  };
5
5
  export type AnonymousAccess = {
6
- readonly authenticate: (request: Request) => Promise<ExplorerAuthentication<AnonymousPrincipal>>;
6
+ readonly authenticate: (request: Request, mode: ExplorerAuthenticationMode) => Promise<ExplorerAuthentication<AnonymousPrincipal>>;
7
7
  readonly principalKey: (principal: AnonymousPrincipal) => string;
8
8
  readonly signedOutPage: (request: Request, headers: Headers) => Response;
9
9
  };
@@ -15,6 +15,9 @@ export type ExplorerAuthentication<P> = {
15
15
  readonly status: "forbidden";
16
16
  readonly headers?: HeadersInit;
17
17
  };
18
+ export type ExplorerAuthenticationMode = {
19
+ readonly readOnly: boolean;
20
+ };
18
21
  export type ExplorerSourceContext<P> = {
19
22
  readonly principal: P;
20
23
  readonly request: Request;
@@ -77,7 +80,7 @@ export type ExplorerHostDocument = {
77
80
  } | ExplorerFailureDocument;
78
81
  export type MarkdownExplorerServerConfig<P> = {
79
82
  readonly config: ExplorerConfig;
80
- readonly authenticate: (request: Request) => Promise<ExplorerAuthentication<P>>;
83
+ readonly authenticate: (request: Request, mode: ExplorerAuthenticationMode) => Promise<ExplorerAuthentication<P>>;
81
84
  readonly principalKey: (principal: P) => string;
82
85
  readonly scopeSecret: string;
83
86
  readonly sources: readonly ExplorerSource<P>[];
@@ -15,6 +15,9 @@ export type ExplorerAuthentication<P> = {
15
15
  readonly status: "forbidden";
16
16
  readonly headers?: HeadersInit;
17
17
  };
18
+ export type ExplorerAuthenticationMode = {
19
+ readonly readOnly: boolean;
20
+ };
18
21
  export type ExplorerSourceContext<P> = {
19
22
  readonly principal: P;
20
23
  readonly request: Request;
@@ -77,7 +80,7 @@ export type ExplorerHostDocument = {
77
80
  } | ExplorerFailureDocument;
78
81
  export type MarkdownExplorerServerConfig<P> = {
79
82
  readonly config: ExplorerConfig;
80
- readonly authenticate: (request: Request) => Promise<ExplorerAuthentication<P>>;
83
+ readonly authenticate: (request: Request, mode: ExplorerAuthenticationMode) => Promise<ExplorerAuthentication<P>>;
81
84
  readonly principalKey: (principal: P) => string;
82
85
  readonly scopeSecret: string;
83
86
  readonly sources: readonly ExplorerSource<P>[];