@drm3/sdk 0.1.2

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 (228) hide show
  1. package/LICENSE +75 -0
  2. package/README.md +426 -0
  3. package/bin/drm3.js +255 -0
  4. package/dist/alerts-bell.d.ts +7 -0
  5. package/dist/alerts-bell.d.ts.map +1 -0
  6. package/dist/alerts-bell.js +118 -0
  7. package/dist/alerts-bell.js.map +1 -0
  8. package/dist/alerts-fetch.d.ts +41 -0
  9. package/dist/alerts-fetch.d.ts.map +1 -0
  10. package/dist/alerts-fetch.js +60 -0
  11. package/dist/alerts-fetch.js.map +1 -0
  12. package/dist/alerts-styles.d.ts +4 -0
  13. package/dist/alerts-styles.d.ts.map +1 -0
  14. package/dist/alerts-styles.js +49 -0
  15. package/dist/alerts-styles.js.map +1 -0
  16. package/dist/alerts.d.ts +3 -0
  17. package/dist/alerts.d.ts.map +1 -0
  18. package/dist/alerts.global.js +206 -0
  19. package/dist/alerts.global.text.js +2 -0
  20. package/dist/alerts.js +21 -0
  21. package/dist/alerts.js.map +1 -0
  22. package/dist/index.d.ts +64 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +117 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/keys-canonical.d.ts +7 -0
  27. package/dist/keys-canonical.d.ts.map +1 -0
  28. package/dist/keys-canonical.js +57 -0
  29. package/dist/keys-canonical.js.map +1 -0
  30. package/dist/keys-generate.d.ts +39 -0
  31. package/dist/keys-generate.d.ts.map +1 -0
  32. package/dist/keys-generate.js +39 -0
  33. package/dist/keys-generate.js.map +1 -0
  34. package/dist/keys-verify.d.ts +62 -0
  35. package/dist/keys-verify.d.ts.map +1 -0
  36. package/dist/keys-verify.js +68 -0
  37. package/dist/keys-verify.js.map +1 -0
  38. package/dist/keys.d.ts +4 -0
  39. package/dist/keys.d.ts.map +1 -0
  40. package/dist/keys.js +22 -0
  41. package/dist/keys.js.map +1 -0
  42. package/dist/meter/adapter.d.ts +35 -0
  43. package/dist/meter/adapter.d.ts.map +1 -0
  44. package/dist/meter/adapter.js +0 -0
  45. package/dist/meter/adapter.js.map +1 -0
  46. package/dist/meter/cascade.d.ts +56 -0
  47. package/dist/meter/cascade.d.ts.map +1 -0
  48. package/dist/meter/cascade.js +64 -0
  49. package/dist/meter/cascade.js.map +1 -0
  50. package/dist/meter/client.d.ts +78 -0
  51. package/dist/meter/client.d.ts.map +1 -0
  52. package/dist/meter/client.js +84 -0
  53. package/dist/meter/client.js.map +1 -0
  54. package/dist/meter/core.d.ts +37 -0
  55. package/dist/meter/core.d.ts.map +1 -0
  56. package/dist/meter/core.js +49 -0
  57. package/dist/meter/core.js.map +1 -0
  58. package/dist/meter/gate-client.d.ts +94 -0
  59. package/dist/meter/gate-client.d.ts.map +1 -0
  60. package/dist/meter/gate-client.js +77 -0
  61. package/dist/meter/gate-client.js.map +1 -0
  62. package/dist/meter/gate-decide.d.ts +61 -0
  63. package/dist/meter/gate-decide.d.ts.map +1 -0
  64. package/dist/meter/gate-decide.js +54 -0
  65. package/dist/meter/gate-decide.js.map +1 -0
  66. package/dist/meter/gate.d.ts +10 -0
  67. package/dist/meter/gate.d.ts.map +1 -0
  68. package/dist/meter/gate.js +10 -0
  69. package/dist/meter/gate.js.map +1 -0
  70. package/dist/meter/index.d.ts +28 -0
  71. package/dist/meter/index.d.ts.map +1 -0
  72. package/dist/meter/index.js +28 -0
  73. package/dist/meter/index.js.map +1 -0
  74. package/dist/meter/meters-buckets.d.ts +56 -0
  75. package/dist/meter/meters-buckets.d.ts.map +1 -0
  76. package/dist/meter/meters-buckets.js +111 -0
  77. package/dist/meter/meters-buckets.js.map +1 -0
  78. package/dist/meter/meters-charge.d.ts +13 -0
  79. package/dist/meter/meters-charge.d.ts.map +1 -0
  80. package/dist/meter/meters-charge.js +76 -0
  81. package/dist/meter/meters-charge.js.map +1 -0
  82. package/dist/meter/meters.d.ts +63 -0
  83. package/dist/meter/meters.d.ts.map +1 -0
  84. package/dist/meter/meters.js +44 -0
  85. package/dist/meter/meters.js.map +1 -0
  86. package/dist/meter/plans.d.ts +63 -0
  87. package/dist/meter/plans.d.ts.map +1 -0
  88. package/dist/meter/plans.js +114 -0
  89. package/dist/meter/plans.js.map +1 -0
  90. package/dist/meter/pricebook.d.ts +32 -0
  91. package/dist/meter/pricebook.d.ts.map +1 -0
  92. package/dist/meter/pricebook.js +38 -0
  93. package/dist/meter/pricebook.js.map +1 -0
  94. package/dist/meter/resolve.d.ts +103 -0
  95. package/dist/meter/resolve.d.ts.map +1 -0
  96. package/dist/meter/resolve.js +100 -0
  97. package/dist/meter/resolve.js.map +1 -0
  98. package/dist/meter/sink.d.ts +26 -0
  99. package/dist/meter/sink.d.ts.map +1 -0
  100. package/dist/meter/sink.js +9 -0
  101. package/dist/meter/sink.js.map +1 -0
  102. package/dist/meter/sql/d1.d.ts +32 -0
  103. package/dist/meter/sql/d1.d.ts.map +1 -0
  104. package/dist/meter/sql/d1.js +41 -0
  105. package/dist/meter/sql/d1.js.map +1 -0
  106. package/dist/meter/sql/driver.d.ts +34 -0
  107. package/dist/meter/sql/driver.d.ts.map +1 -0
  108. package/dist/meter/sql/driver.js +17 -0
  109. package/dist/meter/sql/driver.js.map +1 -0
  110. package/dist/meter/sql/postgres.d.ts +23 -0
  111. package/dist/meter/sql/postgres.d.ts.map +1 -0
  112. package/dist/meter/sql/postgres.js +36 -0
  113. package/dist/meter/sql/postgres.js.map +1 -0
  114. package/dist/meter/sql/schema.d.ts +13 -0
  115. package/dist/meter/sql/schema.d.ts.map +1 -0
  116. package/dist/meter/sql/schema.js +32 -0
  117. package/dist/meter/sql/schema.js.map +1 -0
  118. package/dist/meter/sql/sql-adapter.d.ts +36 -0
  119. package/dist/meter/sql/sql-adapter.d.ts.map +1 -0
  120. package/dist/meter/sql/sql-adapter.js +124 -0
  121. package/dist/meter/sql/sql-adapter.js.map +1 -0
  122. package/dist/meter/sql/statements.d.ts +30 -0
  123. package/dist/meter/sql/statements.d.ts.map +1 -0
  124. package/dist/meter/sql/statements.js +24 -0
  125. package/dist/meter/sql/statements.js.map +1 -0
  126. package/dist/meter/types.d.ts +48 -0
  127. package/dist/meter/types.d.ts.map +1 -0
  128. package/dist/meter/types.js +8 -0
  129. package/dist/meter/types.js.map +1 -0
  130. package/dist/meter/units.d.ts +33 -0
  131. package/dist/meter/units.d.ts.map +1 -0
  132. package/dist/meter/units.js +45 -0
  133. package/dist/meter/units.js.map +1 -0
  134. package/dist/meter/wallet-buckets.d.ts +63 -0
  135. package/dist/meter/wallet-buckets.d.ts.map +1 -0
  136. package/dist/meter/wallet-buckets.js +131 -0
  137. package/dist/meter/wallet-buckets.js.map +1 -0
  138. package/dist/meter/wallet-charge.d.ts +15 -0
  139. package/dist/meter/wallet-charge.d.ts.map +1 -0
  140. package/dist/meter/wallet-charge.js +64 -0
  141. package/dist/meter/wallet-charge.js.map +1 -0
  142. package/dist/meter/wallet.d.ts +68 -0
  143. package/dist/meter/wallet.d.ts.map +1 -0
  144. package/dist/meter/wallet.js +47 -0
  145. package/dist/meter/wallet.js.map +1 -0
  146. package/dist/receipts-api.d.ts +5 -0
  147. package/dist/receipts-api.d.ts.map +1 -0
  148. package/dist/receipts-api.js +117 -0
  149. package/dist/receipts-api.js.map +1 -0
  150. package/dist/receipts-chain.d.ts +3 -0
  151. package/dist/receipts-chain.d.ts.map +1 -0
  152. package/dist/receipts-chain.js +121 -0
  153. package/dist/receipts-chain.js.map +1 -0
  154. package/dist/receipts-modal.d.ts +14 -0
  155. package/dist/receipts-modal.d.ts.map +1 -0
  156. package/dist/receipts-modal.js +100 -0
  157. package/dist/receipts-modal.js.map +1 -0
  158. package/dist/receipts-registry.d.ts +4 -0
  159. package/dist/receipts-registry.d.ts.map +1 -0
  160. package/dist/receipts-registry.js +54 -0
  161. package/dist/receipts-registry.js.map +1 -0
  162. package/dist/receipts-render.d.ts +9 -0
  163. package/dist/receipts-render.d.ts.map +1 -0
  164. package/dist/receipts-render.js +83 -0
  165. package/dist/receipts-render.js.map +1 -0
  166. package/dist/receipts-types.d.ts +61 -0
  167. package/dist/receipts-types.d.ts.map +1 -0
  168. package/dist/receipts-types.js +12 -0
  169. package/dist/receipts-types.js.map +1 -0
  170. package/dist/receipts-ui.d.ts +10 -0
  171. package/dist/receipts-ui.d.ts.map +1 -0
  172. package/dist/receipts-ui.js +103 -0
  173. package/dist/receipts-ui.js.map +1 -0
  174. package/dist/receipts-verify.d.ts +8 -0
  175. package/dist/receipts-verify.d.ts.map +1 -0
  176. package/dist/receipts-verify.js +113 -0
  177. package/dist/receipts-verify.js.map +1 -0
  178. package/dist/receipts.d.ts +9 -0
  179. package/dist/receipts.d.ts.map +1 -0
  180. package/dist/receipts.global.js +587 -0
  181. package/dist/receipts.global.text.js +2 -0
  182. package/dist/receipts.js +28 -0
  183. package/dist/receipts.js.map +1 -0
  184. package/dist/sso/index.d.ts +4 -0
  185. package/dist/sso/index.d.ts.map +1 -0
  186. package/dist/sso/index.js +10 -0
  187. package/dist/sso/index.js.map +1 -0
  188. package/dist/sso/jwt.d.ts +29 -0
  189. package/dist/sso/jwt.d.ts.map +1 -0
  190. package/dist/sso/jwt.js +73 -0
  191. package/dist/sso/jwt.js.map +1 -0
  192. package/dist/sso/launch.d.ts +70 -0
  193. package/dist/sso/launch.d.ts.map +1 -0
  194. package/dist/sso/launch.js +75 -0
  195. package/dist/sso/launch.js.map +1 -0
  196. package/dist/sso/revocation.d.ts +23 -0
  197. package/dist/sso/revocation.d.ts.map +1 -0
  198. package/dist/sso/revocation.js +53 -0
  199. package/dist/sso/revocation.js.map +1 -0
  200. package/dist/switcher.d.ts +22 -0
  201. package/dist/switcher.d.ts.map +1 -0
  202. package/dist/switcher.js +174 -0
  203. package/dist/switcher.js.map +1 -0
  204. package/dist/x402/chain.d.ts +49 -0
  205. package/dist/x402/chain.d.ts.map +1 -0
  206. package/dist/x402/chain.js +33 -0
  207. package/dist/x402/chain.js.map +1 -0
  208. package/dist/x402/crypto.d.ts +25 -0
  209. package/dist/x402/crypto.d.ts.map +1 -0
  210. package/dist/x402/crypto.js +74 -0
  211. package/dist/x402/crypto.js.map +1 -0
  212. package/dist/x402/eip712.d.ts +20 -0
  213. package/dist/x402/eip712.d.ts.map +1 -0
  214. package/dist/x402/eip712.js +49 -0
  215. package/dist/x402/eip712.js.map +1 -0
  216. package/dist/x402/envelope.d.ts +45 -0
  217. package/dist/x402/envelope.d.ts.map +1 -0
  218. package/dist/x402/envelope.js +50 -0
  219. package/dist/x402/envelope.js.map +1 -0
  220. package/dist/x402/index.d.ts +41 -0
  221. package/dist/x402/index.d.ts.map +1 -0
  222. package/dist/x402/index.js +41 -0
  223. package/dist/x402/index.js.map +1 -0
  224. package/dist/x402/verify.d.ts +51 -0
  225. package/dist/x402/verify.d.ts.map +1 -0
  226. package/dist/x402/verify.js +110 -0
  227. package/dist/x402/verify.js.map +1 -0
  228. package/package.json +100 -0
@@ -0,0 +1,587 @@
1
+ "use strict";
2
+ var drm3Receipts = (() => {
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/receipts.ts
22
+ var receipts_exports = {};
23
+ __export(receipts_exports, {
24
+ ALERT: () => ALERT,
25
+ CHECK: () => CHECK,
26
+ DOWNLOAD: () => DOWNLOAD,
27
+ FAILED: () => FAILED,
28
+ HEX: () => HEX,
29
+ LOCK: () => LOCK,
30
+ RECEIPT: () => RECEIPT,
31
+ SPIN: () => SPIN,
32
+ STAMP: () => STAMP,
33
+ UNVERIFIABLE_NO_ACCESS: () => UNVERIFIABLE_NO_ACCESS,
34
+ VERIFIED: () => VERIFIED,
35
+ appendDownload: () => appendDownload,
36
+ buildModal: () => buildModal,
37
+ canonicalize: () => canonicalize,
38
+ countsLine: () => countsLine,
39
+ esc: () => esc,
40
+ hashHex: () => hashHex,
41
+ injectStyles: () => injectStyles,
42
+ isEd25519Supported: () => isEd25519Supported,
43
+ legDetail: () => legDetail,
44
+ loadRegistry: () => loadRegistry,
45
+ monoColor: () => monoColor,
46
+ mountVerifyButton: () => mountVerifyButton,
47
+ openReceiptById: () => openReceiptById,
48
+ openReceiptModal: () => openReceiptModal,
49
+ prettyAction: () => prettyAction,
50
+ resolveReceipt: () => resolveReceipt,
51
+ sealVerdict: () => sealVerdict,
52
+ sha256Hex: () => sha256Hex,
53
+ shortHex: () => shortHex,
54
+ shortKey: () => shortKey,
55
+ verifyChainInto: () => verifyChainInto,
56
+ verifyContentSig: () => verifyContentSig,
57
+ verifyReceipt: () => verifyReceipt
58
+ });
59
+
60
+ // src/receipts-render.ts
61
+ var esc = (s) => String(s).replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);
62
+ function shortHex(h) {
63
+ const x = String(h || "").replace(/^(ed25519|sha256|sha1):/, "");
64
+ return x ? `${x.slice(0, 10)}\u2026${x.slice(-6)}` : "-";
65
+ }
66
+ function shortKey(k) {
67
+ const h = String(k || "").replace(/^ed25519:/, "");
68
+ return h ? `ed25519:${h.slice(0, 8)}\u2026${h.slice(-6)}` : "-";
69
+ }
70
+ function prettyAction(a) {
71
+ if (/fetch/i.test(a)) return "Fetched & extracted";
72
+ if (/analy/i.test(a)) return "AI analysis";
73
+ if (/scrape|extract/i.test(a)) return "Content extracted";
74
+ if (/digest|compose/i.test(a)) return "Composed";
75
+ if (/infer/i.test(a)) return "Inference";
76
+ return String(a || "receipt").replace(/[._-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
77
+ }
78
+ function monoColor(s) {
79
+ let h = 0;
80
+ for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) % 360;
81
+ return `hsl(${h} 52% 64%)`;
82
+ }
83
+ function countsLine(c) {
84
+ return `<span class="drm3v-counts">${c.verified} verified \xB7 ${c.gated} not accessible \xB7 ${c.failed} failed</span>`;
85
+ }
86
+ function fieldRow(label, value, mono = false) {
87
+ return `<div class="drm3v-kv"><span>${esc(label)}</span>${mono ? `<code>${esc(value)}</code>` : `<b>${esc(value)}</b>`}</div>`;
88
+ }
89
+ function legDetail(payload, contentRef) {
90
+ const meta = payload?.metadata?._meta || {};
91
+ const rows = [];
92
+ const model = String(meta.model || "");
93
+ const provider = String(meta.provider || "");
94
+ if (model) rows.push(fieldRow("model", provider ? `${model} \xB7 ${provider}` : model));
95
+ else if (meta.extractor) rows.push(fieldRow("extractor", String(meta.extractor)));
96
+ const ih = String(payload.input_hash || "");
97
+ const oh = String(payload.output_hash || "");
98
+ if (ih) rows.push(fieldRow("input", shortHex(ih), true));
99
+ if (oh) rows.push(fieldRow("output", shortHex(oh), true));
100
+ if (payload.timestamp) {
101
+ const d = new Date(String(payload.timestamp));
102
+ if (!Number.isNaN(d.getTime())) rows.push(fieldRow("signed", d.toUTCString()));
103
+ }
104
+ const att = String(meta.attestation || "");
105
+ const attHtml = att ? `<div class="drm3v-att">${esc(att)}</div>` : "";
106
+ const links = [];
107
+ if (contentRef?.ourUrl) links.push(`<a class="drm3v-clink" href="${esc(contentRef.ourUrl)}" target="_blank" rel="noopener">read the copy \u2197</a>`);
108
+ if (contentRef?.origUrl)
109
+ links.push(`<a class="drm3v-clink" href="${esc(contentRef.origUrl)}" target="_blank" rel="noopener noreferrer">original source \u2197</a>`);
110
+ const linksHtml = links.length ? `<div class="drm3v-clinks">${links.join("")}</div>` : "";
111
+ if (!rows.length && !attHtml && !linksHtml) return "";
112
+ return `<div class="drm3v-detail">${rows.join("")}${attHtml}${linksHtml}</div>`;
113
+ }
114
+
115
+ // src/receipts-types.ts
116
+ var VERIFIED = "verified";
117
+ var UNVERIFIABLE_NO_ACCESS = "unverifiable_no_access";
118
+ var FAILED = "failed";
119
+
120
+ // src/receipts-verify.ts
121
+ function canonicalize(obj) {
122
+ if (obj === null || obj === void 0) return JSON.stringify(obj);
123
+ if (Array.isArray(obj)) return `[${obj.map(canonicalize).join(",")}]`;
124
+ if (typeof obj === "object") {
125
+ const keys = Object.keys(obj).map((k) => k.normalize("NFC")).sort();
126
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`).join(",")}}`;
127
+ }
128
+ if (typeof obj === "string") return JSON.stringify(obj.normalize("NFC"));
129
+ return JSON.stringify(obj);
130
+ }
131
+ function hexToBytes(hex) {
132
+ const out = new Uint8Array(hex.length / 2);
133
+ for (let i = 0; i < hex.length; i += 2) out[i / 2] = Number.parseInt(hex.substr(i, 2), 16);
134
+ return out;
135
+ }
136
+ var SPEC11_FIELDS = ["purpose", "caller", "inputs", "outputs", "content_sig"];
137
+ async function verifyReceipt(r) {
138
+ const p = typeof r.receipt_json === "string" ? JSON.parse(r.receipt_json) : r.receipt_json;
139
+ if (!p) return false;
140
+ const sig = (r.signature || p.signature || "").replace(/^ed25519:/, "");
141
+ const pub = (r.public_key || p.public_key || "").replace(/^ed25519:/, "");
142
+ if (!sig || !pub) return false;
143
+ const key = await crypto.subtle.importKey("raw", hexToBytes(pub), { name: "Ed25519" }, false, ["verify"]);
144
+ const sigBytes = hexToBytes(sig);
145
+ const payloadFor = (ts) => {
146
+ const base = {
147
+ id: p.id,
148
+ action: p.action,
149
+ timestamp: ts,
150
+ input_hash: p.input_hash,
151
+ output_hash: p.output_hash,
152
+ cost: p.cost ?? null,
153
+ duration_ms: p.duration_ms ?? null,
154
+ parent_id: p.parent_id ?? null,
155
+ metadata: p.metadata ?? null,
156
+ public_key: p.public_key
157
+ };
158
+ for (const k of SPEC11_FIELDS) {
159
+ if (p[k] !== void 0 && p[k] !== null) base[k] = p[k];
160
+ }
161
+ return base;
162
+ };
163
+ const tryVerify = (ts) => crypto.subtle.verify("Ed25519", key, sigBytes, new TextEncoder().encode(canonicalize(payloadFor(ts))));
164
+ if (await tryVerify(p.timestamp)) return true;
165
+ if (typeof p.timestamp === "string" && p.timestamp.endsWith("Z")) {
166
+ if (await tryVerify(`${p.timestamp.slice(0, -1)}+00:00`)) return true;
167
+ }
168
+ return false;
169
+ }
170
+ async function verifyContentSig(contentSig, publicKey, body) {
171
+ const sig = String(contentSig || "").replace(/^ed25519:/, "");
172
+ const pub = String(publicKey || "").replace(/^ed25519:/, "");
173
+ if (!sig || !pub || !body || !crypto?.subtle) return null;
174
+ try {
175
+ const key = await crypto.subtle.importKey("raw", hexToBytes(pub), { name: "Ed25519" }, false, ["verify"]);
176
+ return await crypto.subtle.verify("Ed25519", key, hexToBytes(sig), new TextEncoder().encode(body));
177
+ } catch {
178
+ return null;
179
+ }
180
+ }
181
+ async function hashHex(algo, s) {
182
+ const buf = await crypto.subtle.digest(algo, new TextEncoder().encode(s));
183
+ return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join("");
184
+ }
185
+ var sha256Hex = (s) => hashHex("SHA-256", s);
186
+ async function isEd25519Supported() {
187
+ try {
188
+ await crypto.subtle.generateKey({ name: "Ed25519" }, false, ["sign", "verify"]);
189
+ return true;
190
+ } catch {
191
+ return false;
192
+ }
193
+ }
194
+
195
+ // src/receipts-chain.ts
196
+ function parentRefs(r, pj) {
197
+ const out = [];
198
+ const add = (v) => {
199
+ if (typeof v === "string" && v) out.push(v);
200
+ };
201
+ add(r.parent_receipt_id);
202
+ add(pj?.parent_id);
203
+ for (const e of pj?.inputs || []) if (e && typeof e === "object") add(e.ref);
204
+ return out;
205
+ }
206
+ function safeParse(s) {
207
+ try {
208
+ return JSON.parse(s);
209
+ } catch {
210
+ return null;
211
+ }
212
+ }
213
+ async function verifyChainInto(chain, registry, addStep, settle, wait, contentRef) {
214
+ const counts = { verified: 0, gated: 0, failed: 0 };
215
+ const present = /* @__PURE__ */ new Set();
216
+ for (const r of chain) {
217
+ const pj = typeof r.receipt_json === "string" ? safeParse(r.receipt_json) : r.receipt_json;
218
+ if (r.id) present.add(r.id);
219
+ if (typeof pj?.id === "string") present.add(pj.id);
220
+ }
221
+ const referencedGated = /* @__PURE__ */ new Set();
222
+ for (const r of chain) {
223
+ const pj = typeof r.receipt_json === "string" ? safeParse(r.receipt_json) : r.receipt_json;
224
+ for (const pid of parentRefs(r, pj)) if (!present.has(pid)) referencedGated.add(pid);
225
+ }
226
+ const ordered = [...chain].reverse();
227
+ for (const r of ordered) {
228
+ const payload = typeof r.receipt_json === "string" ? JSON.parse(r.receipt_json) : r.receipt_json;
229
+ const action = r.action || payload?.action || r.receipt_type || "receipt";
230
+ const pub = (r.public_key || payload?.public_key || "").toLowerCase();
231
+ const signer = r.signer_path || payload?.metadata?._meta?.signer || "";
232
+ const el = addStep(prettyAction(action), signer ? `signer ${signer} \xB7 ${shortKey(pub)}` : shortKey(pub), legDetail(payload, contentRef));
233
+ await wait(420);
234
+ let ok = false;
235
+ try {
236
+ ok = await verifyReceipt(r);
237
+ } catch {
238
+ ok = false;
239
+ }
240
+ const rec = registry.get(pub);
241
+ const known = registry.size === 0 || !!rec;
242
+ const ts = payload?.timestamp || r.timestamp || "";
243
+ let verdict = ok && known ? VERIFIED : FAILED;
244
+ let note = "";
245
+ if (ok && rec) {
246
+ if (rec.status === "compromised" || rec.status === "revoked") {
247
+ verdict = FAILED;
248
+ note = ` \xB7 \u26A0 key ${rec.status}`;
249
+ } else if (rec.status === "superseded" || rec.status === "retired") {
250
+ const inWindow = (!rec.valid_from || !ts || ts >= rec.valid_from) && (!rec.valid_until || !ts || ts <= rec.valid_until);
251
+ if (inWindow) {
252
+ verdict = VERIFIED;
253
+ note = ` \xB7 key since rotated${rec.valid_until ? ` ${rec.valid_until.slice(0, 10)}` : ""} (verified)`;
254
+ } else {
255
+ verdict = FAILED;
256
+ note = " \xB7 \u26A0 signed outside the key's validity window";
257
+ }
258
+ }
259
+ } else if (ok && !known) {
260
+ note = " \xB7 \u26A0 key not found in registry";
261
+ }
262
+ settle(el, verdict);
263
+ if (verdict === VERIFIED) counts.verified++;
264
+ else counts.failed++;
265
+ if (note) {
266
+ const meta = el.querySelector(".drm3v-meta");
267
+ if (meta) meta.textContent += note;
268
+ }
269
+ await wait(180);
270
+ }
271
+ for (const pid of referencedGated) {
272
+ const el = addStep(
273
+ "Upstream step (not accessible)",
274
+ `referenced ${shortHex(pid)} \xB7 receipt not retrievable to you`,
275
+ `<div class="drm3v-detail"><div class="drm3v-clinks"><a class="drm3v-clink" href="#" onclick="event.preventDefault();event.stopPropagation();window.drm3Receipts&&window.drm3Receipts.openReceiptById('${esc(pid)}')">resolve this receipt</a></div></div>`
276
+ );
277
+ await wait(280);
278
+ settle(el, UNVERIFIABLE_NO_ACCESS);
279
+ counts.gated++;
280
+ await wait(120);
281
+ }
282
+ return counts;
283
+ }
284
+
285
+ // src/receipts-ui.ts
286
+ var CHECK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>';
287
+ var LOCK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>';
288
+ var HEX = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.5 20.5 7.2v9.6L12 21.5 3.5 16.8V7.2z"/><path d="m8.7 12 2.2 2.2 4.4-4.4"/></svg>';
289
+ var STAMP = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5.4" stroke-dasharray="1.4 2.3"/><path d="m9.5 12 1.8 1.8 3.6-3.7"/></svg>';
290
+ var ALERT = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>';
291
+ var RECEIPT = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 3v18l2-1.2L9 21l2-1.2L13 21l2-1.2L17 21l2-1.2V3l-2 1.2L15 3l-2 1.2L11 3 9 4.2 7 3z"/><path d="M8 8.5h8M8 12h8M8 15.5h5" stroke-width="1.4"/></svg>';
292
+ var SPIN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><path d="M12 3a9 9 0 1 0 9 9" opacity=".95"/></svg>';
293
+ var DOWNLOAD = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"/></svg>';
294
+ function injectStyles() {
295
+ if (typeof document === "undefined" || document.getElementById("drm3v-css")) return;
296
+ const s = document.createElement("style");
297
+ s.id = "drm3v-css";
298
+ s.textContent = `
299
+ .drm3v-trigger{display:inline-flex;align-items:center;gap:7px;margin:12px 0;padding:9px 15px;font:inherit;font-size:.82rem;font-weight:600;
300
+ color:#0a0a10;background:linear-gradient(180deg,#7fe3b0,#46c98a);border:none;border-radius:999px;cursor:pointer;transition:transform .12s,filter .15s}
301
+ .drm3v-trigger:hover{transform:translateY(-1px);filter:brightness(1.05)}
302
+ .drm3v-trigger svg{width:15px;height:15px}
303
+ .drm3v-ov{position:fixed;inset:0;z-index:99990;display:flex;align-items:center;justify-content:center;padding:20px;
304
+ background:rgba(4,4,9,.78);backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);animation:drm3v-fade .18s ease}
305
+ @keyframes drm3v-fade{from{opacity:0}to{opacity:1}}
306
+ .drm3v-modal{width:min(600px,100%);max-height:90vh;overflow:auto;background:linear-gradient(180deg,#13131f,#0d0d16);
307
+ border:1px solid #2a2a3f;border-radius:20px;box-shadow:0 30px 90px rgba(0,0,0,.66);padding:22px 22px 18px;font-family:ui-sans-serif,system-ui,sans-serif;color:#e8e8f2}
308
+ .drm3v-modal::-webkit-scrollbar{width:10px}
309
+ .drm3v-modal::-webkit-scrollbar-thumb{background:#2a2a3f;border-radius:8px;border:3px solid transparent;background-clip:padding-box}
310
+ .drm3v-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px}
311
+ .drm3v-h h3{font-size:1.02rem;margin:0;color:#fff;display:flex;align-items:center;gap:9px}
312
+ .drm3v-h h3 svg{width:18px;height:18px;color:#7fe3b0}
313
+ .drm3v-x{background:none;border:none;color:#a8a8be;font-size:1.4rem;line-height:1;cursor:pointer}
314
+ .drm3v-x:hover{color:#e8e8f2}
315
+ .drm3v-sub{font-size:.79rem;color:#b6b6c8;margin-bottom:14px;line-height:1.5}
316
+ .drm3v-rcpt{position:relative;overflow:hidden;border:1px solid #2c2c42;border-radius:16px;padding:15px 17px 14px;margin:4px 0 2px;
317
+ background:radial-gradient(135% 150% at 0 0,rgba(70,201,138,.13),transparent 56%),#15151f}
318
+ .drm3v-rcpt::after{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(180deg,#7fe3b0,#46c98a)}
319
+ .drm3v-rcpt.part::after{background:linear-gradient(180deg,#f3d09a,#e3a24b)}
320
+ .drm3v-rcpt.bad::after{background:linear-gradient(180deg,#ffb3c0,#e0556b)}
321
+ .drm3v-rcpt.wait::after{background:linear-gradient(180deg,#3a3a52,#2a2a3d)}
322
+ .drm3v-rtop{display:flex;align-items:center;gap:7px;font-size:.69rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:#9ff0c4}
323
+ .drm3v-rtop .svc{color:#fff}
324
+ .drm3v-rtop .dep{color:#a8a8be;font-weight:600}
325
+ .drm3v-raction{margin-left:auto;font-family:ui-monospace,Menlo,monospace;font-size:.69rem;font-weight:600;color:#cfcfe0;
326
+ background:rgba(141,141,163,.14);border:1px solid #2c2c42;padding:2px 9px;border-radius:999px;letter-spacing:0;text-transform:none}
327
+ .drm3v-rsigner{display:flex;align-items:center;gap:9px;margin-top:12px}
328
+ .drm3v-rsigner>svg{flex:none;width:20px;height:20px;color:#7fe3b0}
329
+ .drm3v-rname{font-weight:700;font-size:.95rem;color:#fff;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
330
+ .drm3v-rstate{margin-left:auto;display:inline-flex;align-items:center;gap:5px;font-size:.71rem;font-weight:700;
331
+ padding:4px 10px;border-radius:999px;border:1px solid;white-space:nowrap;flex:none}
332
+ .drm3v-rstate svg{width:13px;height:13px}
333
+ .drm3v-rstate.ok{color:#9ff0c4;background:rgba(70,201,138,.15);border-color:rgba(70,201,138,.45)}
334
+ .drm3v-rstate.wait{color:#c2c2d4;background:rgba(141,141,163,.14);border-color:#34344a}
335
+ .drm3v-rstate.part{color:#f3d09a;background:rgba(227,162,75,.15);border-color:rgba(227,162,75,.45)}
336
+ .drm3v-rstate.bad{color:#ffb3c0;background:rgba(224,85,107,.15);border-color:rgba(224,85,107,.45)}
337
+ .drm3v-rstate.spin svg{animation:drm3v-spin .7s linear infinite}
338
+ .drm3v-rkey{font-family:ui-monospace,Menlo,monospace;font-size:.71rem;color:#a8a8be;margin-top:9px;word-break:break-all}
339
+ .drm3v-rnote{font-size:.77rem;color:#bdbdd0;margin-top:8px;line-height:1.45}
340
+ .drm3v-rnote b{color:#fff}
341
+ .drm3v-rseal{position:absolute;right:-12px;bottom:-18px;width:94px;height:94px;color:#46c98a;opacity:.09;transform:rotate(-11deg);pointer-events:none}
342
+ .drm3v-rcpt.part .drm3v-rseal{color:#e3a24b}
343
+ .drm3v-rcpt.bad .drm3v-rseal{color:#e0556b}
344
+ .drm3v-railhead{display:flex;align-items:center;gap:8px;font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:#a8a8be;margin:17px 0 4px}
345
+ .drm3v-railhead .ct{color:#cfcfe0;font-family:ui-monospace,Menlo,monospace;letter-spacing:0;background:rgba(141,141,163,.14);border-radius:999px;padding:1px 8px}
346
+ .drm3v-step{display:flex;gap:12px;padding:11px 0;border-top:1px solid #1d1d2c;opacity:.35;transform:translateY(4px);transition:opacity .4s,transform .4s}
347
+ .drm3v-step.on{opacity:1;transform:none}
348
+ .drm3v-dot{flex:none;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.7rem;
349
+ background:#1d1d2c;color:#a8a8be;border:1px solid #2a2a3d}
350
+ .drm3v-dot svg{width:13px;height:13px}
351
+ .drm3v-dot.ok{background:#46c98a;color:#0a0a10;border-color:#46c98a}
352
+ .drm3v-dot.warn{background:rgba(227,162,75,.18);color:#f3d09a;border-color:rgba(227,162,75,.5)}
353
+ .drm3v-dot.bad{background:#e0556b;color:#fff;border-color:#e0556b}
354
+ .drm3v-dot.spin{border-top-color:#7fe3b0;animation:drm3v-spin .7s linear infinite}
355
+ @keyframes drm3v-spin{to{transform:rotate(360deg)}}
356
+ .drm3v-body{flex:1;min-width:0}
357
+ .drm3v-act{font-weight:600;font-size:.88rem;color:#fff}
358
+ .drm3v-meta{font-size:.71rem;color:#a8a8be;margin-top:3px;word-break:break-all;font-family:ui-monospace,Menlo,monospace}
359
+ .drm3v-detail{margin:8px 0 2px;padding:9px 11px;background:#0e0e16;border:1px solid #1d1d2c;border-radius:9px}
360
+ .drm3v-kv{display:flex;gap:9px;font-size:.71rem;line-height:1.5;margin:2px 0}
361
+ .drm3v-kv>span{flex:none;width:56px;color:#a8a8be;text-transform:uppercase;letter-spacing:.05em;font-size:.64rem;font-weight:700;padding-top:2px}
362
+ .drm3v-kv>b{color:#e8e8f2;font-weight:600;min-width:0;word-break:break-word}
363
+ .drm3v-kv>code{font-family:ui-monospace,Menlo,monospace;color:#9ff0c4;word-break:break-all;font-size:.7rem}
364
+ .drm3v-att{margin-top:8px;font-size:.72rem;line-height:1.55;color:#a6a6bd;border-left:2px solid #2a2a3d;padding:1px 0 1px 9px}
365
+ .drm3v-clinks{display:flex;flex-wrap:wrap;gap:8px;margin-top:9px}
366
+ .drm3v-clink{font-size:.72rem;font-weight:600;color:#7fe3b0;text-decoration:none;border:1px solid rgba(70,201,138,.32);border-radius:999px;padding:3px 11px;transition:background .14s,border-color .14s;cursor:pointer}
367
+ .drm3v-clink:hover{background:rgba(70,201,138,.13);border-color:rgba(70,201,138,.5)}
368
+ .drm3v-dlbtn{display:inline-flex;align-items:center;gap:7px;margin-top:13px;padding:8px 14px;font:inherit;font-size:.78rem;font-weight:600;
369
+ color:#cfcfe0;background:rgba(141,141,163,.12);border:1px solid #34344a;border-radius:9px;cursor:pointer;transition:border-color .14s,background .14s}
370
+ .drm3v-dlbtn:hover{border-color:#7fe3b0;color:#9ff0c4;background:rgba(70,201,138,.1)}
371
+ .drm3v-dlbtn svg{width:14px;height:14px}
372
+ .drm3v-final{margin-top:16px;padding:16px;border-radius:14px;font-size:.86rem;line-height:1.5}
373
+ .drm3v-final.ok{background:rgba(70,201,138,.10);border:1px solid rgba(70,201,138,.4);color:#cdeede}
374
+ .drm3v-final.part{background:rgba(227,162,75,.10);border:1px solid rgba(227,162,75,.4);color:#ecd6ad}
375
+ .drm3v-final.bad{background:rgba(224,85,107,.10);border:1px solid rgba(224,85,107,.4);color:#f3c0c9}
376
+ .drm3v-final b{color:#fff}
377
+ .drm3v-final svg{width:16px;height:16px;vertical-align:-3px;margin-right:4px}
378
+ .drm3v-counts{display:block;margin-top:8px;font-size:.78rem;font-family:ui-monospace,Menlo,monospace;color:inherit;opacity:.92}`;
379
+ document.head.appendChild(s);
380
+ }
381
+
382
+ // src/receipts-modal.ts
383
+ function dlJSON(filename, obj) {
384
+ const blob = new Blob([JSON.stringify(obj, null, 2)], { type: "application/json" });
385
+ const url = URL.createObjectURL(blob);
386
+ const a = document.createElement("a");
387
+ a.href = url;
388
+ a.download = filename;
389
+ a.click();
390
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
391
+ }
392
+ function appendDownload(host, filename, obj) {
393
+ if (!obj) return;
394
+ const btn = document.createElement("button");
395
+ btn.type = "button";
396
+ btn.className = "drm3v-dlbtn";
397
+ btn.innerHTML = `${DOWNLOAD}<span>Download receipt JSON</span>`;
398
+ btn.addEventListener("click", () => dlJSON(filename, obj));
399
+ host.appendChild(btn);
400
+ }
401
+ function buildModal(title, subtitle) {
402
+ injectStyles();
403
+ const ov = document.createElement("div");
404
+ ov.className = "drm3v-ov";
405
+ ov.innerHTML = `<div class="drm3v-modal" role="dialog" aria-label="${esc(title)}">
406
+ <div class="drm3v-h"><h3>${RECEIPT}${esc(title)}</h3><button class="drm3v-x" aria-label="Close">&times;</button></div>
407
+ <div class="drm3v-sub">${subtitle}</div>
408
+ <div class="drm3v-steps"></div>
409
+ <div class="drm3v-final"></div></div>`;
410
+ document.body.appendChild(ov);
411
+ const close = () => ov.remove();
412
+ ov.addEventListener("click", (e) => {
413
+ if (e.target === ov) close();
414
+ });
415
+ ov.querySelector(".drm3v-x")?.addEventListener("click", close);
416
+ const onEsc = (e) => {
417
+ if (e.key === "Escape") {
418
+ close();
419
+ document.removeEventListener("keydown", onEsc);
420
+ }
421
+ };
422
+ document.addEventListener("keydown", onEsc);
423
+ const steps = ov.querySelector(".drm3v-steps");
424
+ const final = ov.querySelector(".drm3v-final");
425
+ const addStep = (act, meta, detail) => {
426
+ const el = document.createElement("div");
427
+ el.className = "drm3v-step";
428
+ el.innerHTML = `<div class="drm3v-dot spin"></div><div class="drm3v-body"><div class="drm3v-act">${esc(act)}</div><div class="drm3v-meta">${esc(meta)}</div>${detail || ""}</div>`;
429
+ steps.appendChild(el);
430
+ requestAnimationFrame(() => el.classList.add("on"));
431
+ return el;
432
+ };
433
+ const settle = (el, verdict) => {
434
+ const dot = el.querySelector(".drm3v-dot");
435
+ if (verdict === VERIFIED) {
436
+ dot.className = "drm3v-dot ok";
437
+ dot.innerHTML = CHECK;
438
+ } else if (verdict === UNVERIFIABLE_NO_ACCESS) {
439
+ dot.className = "drm3v-dot warn";
440
+ dot.innerHTML = LOCK;
441
+ } else {
442
+ dot.className = "drm3v-dot bad";
443
+ dot.innerHTML = "&times;";
444
+ }
445
+ };
446
+ const wait = (ms) => new Promise((r) => setTimeout(r, ms));
447
+ return { ov, steps, final, addStep, settle, wait };
448
+ }
449
+ function sealVerdict(final, counts) {
450
+ if (counts.verified + counts.gated + counts.failed === 0) {
451
+ final.className = "drm3v-final bad";
452
+ final.textContent = "No receipts were found to verify.";
453
+ return;
454
+ }
455
+ if (counts.failed > 0) {
456
+ final.className = "drm3v-final bad";
457
+ final.innerHTML = `One or more signatures did not verify. That's exactly what provenance is for - it tells you when something doesn't add up.${countsLine(counts)}`;
458
+ } else if (counts.gated > 0) {
459
+ final.className = "drm3v-final part";
460
+ final.innerHTML = `${LOCK} <b>Verified in part.</b> Every receipt you could retrieve carries a valid Ed25519 signature from a registered DRM3 signer, checked right here in your browser. ${counts.gated} upstream step${counts.gated === 1 ? "" : "s"} ${counts.gated === 1 ? "is" : "are"} referenced but not accessible to you - a normal access boundary, not a failure.${countsLine(counts)}`;
461
+ } else {
462
+ final.className = "drm3v-final ok";
463
+ final.innerHTML = `${CHECK} <b>Verified.</b> Every receipt in this chain carries a valid Ed25519 signature from a registered DRM3 signer - checked right here in your browser.${countsLine(counts)}`;
464
+ }
465
+ }
466
+
467
+ // src/receipts-registry.ts
468
+ var DEFAULT_REGISTRY_URL = "https://status.drm3.network/.well-known/drm3-keys.json";
469
+ var registryCache = /* @__PURE__ */ new Map();
470
+ async function loadRegistry(url = DEFAULT_REGISTRY_URL) {
471
+ const cached = registryCache.get(url);
472
+ if (cached) return cached;
473
+ const map = /* @__PURE__ */ new Map();
474
+ try {
475
+ const reg = await (await fetch(url)).json();
476
+ for (const svc of reg.services || []) {
477
+ for (const k of svc.current || [])
478
+ if (k.key) map.set(k.key.toLowerCase(), { status: k.status || "current", valid_from: k.valid_from, valid_until: k.valid_until });
479
+ for (const k of svc.history || [])
480
+ if (k.key && !map.has(k.key.toLowerCase()))
481
+ map.set(k.key.toLowerCase(), { status: k.status || "superseded", valid_from: k.valid_from, valid_until: k.valid_until });
482
+ }
483
+ for (const k of reg.keys || []) if (k.key && !map.has(k.key.toLowerCase())) map.set(k.key.toLowerCase(), { status: "current" });
484
+ } catch {
485
+ }
486
+ registryCache.set(url, map);
487
+ return map;
488
+ }
489
+ async function resolveReceipt(id, cfg = {}) {
490
+ try {
491
+ const base = cfg.resolverBase || "";
492
+ const r = await fetch(`${base}/receipts/${encodeURIComponent(id)}`, cfg.headers ? { headers: cfg.headers } : void 0);
493
+ if (!r.ok) return null;
494
+ const j = await r.json();
495
+ return j?.ok && j.receipt ? j : null;
496
+ } catch {
497
+ return null;
498
+ }
499
+ }
500
+
501
+ // src/receipts-api.ts
502
+ var activeCfg = {};
503
+ async function openReceiptModal(chain, cfg = activeCfg) {
504
+ if (typeof document === "undefined") return;
505
+ registerGlobal(cfg);
506
+ const { final, addStep, settle, wait } = buildModal(
507
+ cfg.title || "Provenance receipt",
508
+ cfg.subtitle || "A signed, content-addressed receipt, verified <b>in your browser</b> against the public key registry. Each leg confirms only the one before it; anything it cannot open, it says so."
509
+ );
510
+ if (!await isEd25519Supported()) {
511
+ final.className = "drm3v-final bad";
512
+ final.innerHTML = "This browser can't do Ed25519 in the page (try a recent Chrome, Safari, or Firefox). The receipts are still independently verifiable - see <b>status.drm3.network</b>.";
513
+ return;
514
+ }
515
+ if (!chain.length) {
516
+ final.className = "drm3v-final bad";
517
+ final.textContent = "No receipts attached.";
518
+ return;
519
+ }
520
+ const registry = await loadRegistry(cfg.registryUrl);
521
+ const counts = await verifyChainInto(chain, registry, addStep, settle, wait, cfg.contentRef);
522
+ await wait(200);
523
+ sealVerdict(final, counts);
524
+ if (chain.length === 1) appendDownload(final, `receipt-${chain[0].id || "drm3"}.json`, chain[0].receipt_json || chain[0]);
525
+ }
526
+ async function openReceiptById(id, cfg = activeCfg) {
527
+ if (typeof document === "undefined") return;
528
+ registerGlobal(cfg);
529
+ const { final, addStep, settle, wait } = buildModal(
530
+ cfg.title || "Provenance receipt",
531
+ cfg.subtitle || "Resolved by its content-addressed id and verified <b>in your browser</b> against the public key registry."
532
+ );
533
+ if (!await isEd25519Supported()) {
534
+ final.className = "drm3v-final bad";
535
+ final.innerHTML = "This browser can't do Ed25519 in the page. The receipt is still independently verifiable - see <b>status.drm3.network</b>.";
536
+ return;
537
+ }
538
+ const resolved = await resolveReceipt(id, cfg);
539
+ if (!resolved?.receipt) {
540
+ final.className = "drm3v-final bad";
541
+ final.textContent = "This receipt isn't retrievable here (it may live on another host, or require access).";
542
+ return;
543
+ }
544
+ const rc = resolved.receipt;
545
+ const chain = [
546
+ {
547
+ id,
548
+ receipt_json: rc,
549
+ signature: rc.signature,
550
+ public_key: rc.public_key,
551
+ action: rc.action
552
+ }
553
+ ];
554
+ const registry = await loadRegistry(cfg.registryUrl);
555
+ const counts = await verifyChainInto(chain, registry, addStep, settle, wait, cfg.contentRef);
556
+ await wait(200);
557
+ sealVerdict(final, counts);
558
+ appendDownload(final, `receipt-${id}.json`, rc);
559
+ }
560
+ function mountVerifyButton(target, source, cfg = {}) {
561
+ if (!target || typeof document === "undefined") return;
562
+ injectStyles();
563
+ const btn = document.createElement("button");
564
+ btn.type = "button";
565
+ btn.className = "drm3v-trigger";
566
+ btn.innerHTML = `${CHECK}<span>Verify provenance in your browser</span>`;
567
+ btn.addEventListener("click", async () => {
568
+ const resolved = typeof source === "function" ? await source() : source;
569
+ if (typeof resolved === "string") return void openReceiptById(resolved, cfg);
570
+ const chain = Array.isArray(resolved) ? resolved : [resolved];
571
+ return void openReceiptModal(chain, cfg);
572
+ });
573
+ target.appendChild(btn);
574
+ }
575
+ function registerGlobal(cfg) {
576
+ activeCfg = cfg;
577
+ if (typeof window === "undefined") return;
578
+ const w = window;
579
+ if (!w.drm3Receipts) {
580
+ try {
581
+ w.drm3Receipts = { openReceiptById, openReceiptModal, mountVerifyButton };
582
+ } catch {
583
+ }
584
+ }
585
+ }
586
+ return __toCommonJS(receipts_exports);
587
+ })();