@hwlt/era-connect 0.1.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 (81) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +9 -0
  3. package/README.md +101 -0
  4. package/btc/package.json +6 -0
  5. package/dist/btc-DfQ0q79G.d.ts +58 -0
  6. package/dist/btc-Dn6_Y12c.d.cts +58 -0
  7. package/dist/btc-Fr6Jz4Fi.cjs +104 -0
  8. package/dist/btc-Fr6Jz4Fi.cjs.map +1 -0
  9. package/dist/btc-VyJKXq7d.js +99 -0
  10. package/dist/btc-VyJKXq7d.js.map +1 -0
  11. package/dist/btc.cjs +9 -0
  12. package/dist/btc.d.cts +3 -0
  13. package/dist/btc.d.ts +3 -0
  14. package/dist/btc.js +3 -0
  15. package/dist/evm-BHj_2OTG.cjs +134 -0
  16. package/dist/evm-BHj_2OTG.cjs.map +1 -0
  17. package/dist/evm-DJxGGAbD.d.cts +76 -0
  18. package/dist/evm-KrV5wK08.d.ts +76 -0
  19. package/dist/evm-kJb3-oiR.js +117 -0
  20. package/dist/evm-kJb3-oiR.js.map +1 -0
  21. package/dist/evm.cjs +11 -0
  22. package/dist/evm.d.cts +3 -0
  23. package/dist/evm.d.ts +3 -0
  24. package/dist/evm.js +3 -0
  25. package/dist/index.cjs +530 -0
  26. package/dist/index.cjs.map +1 -0
  27. package/dist/index.d.cts +285 -0
  28. package/dist/index.d.ts +285 -0
  29. package/dist/index.js +506 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/messages-17Oup0-Z.js +208 -0
  32. package/dist/messages-17Oup0-Z.js.map +1 -0
  33. package/dist/messages-BzcdWlg1.cjs +243 -0
  34. package/dist/messages-BzcdWlg1.cjs.map +1 -0
  35. package/dist/messages-DsPvW8Oi.d.cts +29 -0
  36. package/dist/messages-DsPvW8Oi.d.ts +29 -0
  37. package/dist/shared-B8Wc7ViU.js +1472 -0
  38. package/dist/shared-B8Wc7ViU.js.map +1 -0
  39. package/dist/shared-CI8zhQiE.d.cts +218 -0
  40. package/dist/shared-CI8zhQiE.d.ts +218 -0
  41. package/dist/shared-nISrEktU.cjs +1777 -0
  42. package/dist/shared-nISrEktU.cjs.map +1 -0
  43. package/dist/solana-8eOwz0gM.d.cts +49 -0
  44. package/dist/solana-C2Xm7w8a.d.ts +49 -0
  45. package/dist/solana-C7JQEAec.js +87 -0
  46. package/dist/solana-C7JQEAec.js.map +1 -0
  47. package/dist/solana-DdEn24X4.cjs +98 -0
  48. package/dist/solana-DdEn24X4.cjs.map +1 -0
  49. package/dist/solana.cjs +10 -0
  50. package/dist/solana.d.cts +3 -0
  51. package/dist/solana.d.ts +3 -0
  52. package/dist/solana.js +3 -0
  53. package/dist/tron-Bo9HnvVE.js +158 -0
  54. package/dist/tron-Bo9HnvVE.js.map +1 -0
  55. package/dist/tron-CQIEqjCA.cjs +163 -0
  56. package/dist/tron-CQIEqjCA.cjs.map +1 -0
  57. package/dist/tron-YllfTmx6.d.ts +63 -0
  58. package/dist/tron-gG51KMnX.d.cts +63 -0
  59. package/dist/tron.cjs +11 -0
  60. package/dist/tron.d.cts +4 -0
  61. package/dist/tron.d.ts +4 -0
  62. package/dist/tron.js +4 -0
  63. package/dist/verify.cjs +445 -0
  64. package/dist/verify.cjs.map +1 -0
  65. package/dist/verify.d.cts +162 -0
  66. package/dist/verify.d.ts +162 -0
  67. package/dist/verify.js +438 -0
  68. package/dist/verify.js.map +1 -0
  69. package/evm/package.json +6 -0
  70. package/package.json +140 -0
  71. package/proto/tron/base.proto +16 -0
  72. package/proto/tron/message.proto +12 -0
  73. package/proto/tron/payload.proto +35 -0
  74. package/proto/tron/sign_transaction_result.proto +10 -0
  75. package/proto/tron/sync.proto +21 -0
  76. package/proto/tron/transaction.proto +17 -0
  77. package/proto/tron/tron_transaction.proto +31 -0
  78. package/proto/tron/verify_address.proto +10 -0
  79. package/solana/package.json +6 -0
  80. package/tron/package.json +6 -0
  81. package/verify/package.json +6 -0
@@ -0,0 +1,1472 @@
1
+ import { sha256 } from "@noble/hashes/sha2";
2
+ //#region src/core/errors.ts
3
+ /** Every error thrown by this SDK. `code` is stable API; `message` is not. */
4
+ var EraSdkError = class extends Error {
5
+ constructor(code, message, details) {
6
+ super(message);
7
+ this.name = "EraSdkError";
8
+ this.code = code;
9
+ if (details !== void 0) this.details = details;
10
+ }
11
+ };
12
+ //#endregion
13
+ //#region src/cbor/model.ts
14
+ const cbUint = (value) => {
15
+ const v = typeof value === "number" ? BigInt(value) : value;
16
+ if (v < 0n) throw new EraSdkError("invalid-props", "cbUint: negative value");
17
+ return {
18
+ kind: "uint",
19
+ value: v
20
+ };
21
+ };
22
+ const cbBytes = (value) => ({
23
+ kind: "bytes",
24
+ value
25
+ });
26
+ const cbText = (value) => ({
27
+ kind: "text",
28
+ value
29
+ });
30
+ const cbArray = (items) => ({
31
+ kind: "array",
32
+ items
33
+ });
34
+ const cbBool = (value) => ({
35
+ kind: "bool",
36
+ value
37
+ });
38
+ const cbTag = (tag, value) => ({
39
+ kind: "tag",
40
+ tag,
41
+ value
42
+ });
43
+ /** Integer-keyed map in the given entry order (the shape every ERA payload uses). */
44
+ const cbMap = (entries) => ({
45
+ kind: "map",
46
+ entries: entries.map(([k, v]) => [cbUint(k), v])
47
+ });
48
+ /** Strip any tag wrappers (tag-37 UUID echoes, tag-304 keypaths, ...). */
49
+ function stripTags(value) {
50
+ let v = value;
51
+ while (v.kind === "tag") v = v.value;
52
+ return v;
53
+ }
54
+ /** Look up an integer key in a map value. Tag-agnostic on the VALUE is the caller's choice. */
55
+ function mapGet(map, key) {
56
+ if (map.kind !== "map") return void 0;
57
+ const k = BigInt(key);
58
+ for (const [ek, ev] of map.entries) if (ek.kind === "uint" && ek.value === k) return ev;
59
+ }
60
+ function asUint(value) {
61
+ if (!value) return void 0;
62
+ const v = stripTags(value);
63
+ return v.kind === "uint" ? v.value : void 0;
64
+ }
65
+ function asBytes(value) {
66
+ if (!value) return void 0;
67
+ const v = stripTags(value);
68
+ return v.kind === "bytes" ? v.value : void 0;
69
+ }
70
+ function asText(value) {
71
+ if (!value) return void 0;
72
+ const v = stripTags(value);
73
+ return v.kind === "text" ? v.value : void 0;
74
+ }
75
+ function asArray(value) {
76
+ if (!value) return void 0;
77
+ const v = stripTags(value);
78
+ return v.kind === "array" ? v.items : void 0;
79
+ }
80
+ function asMap(value) {
81
+ if (!value) return void 0;
82
+ const v = stripTags(value);
83
+ return v.kind === "map" ? v : void 0;
84
+ }
85
+ function asBool(value) {
86
+ if (!value) return void 0;
87
+ const v = stripTags(value);
88
+ return v.kind === "bool" ? v.value : void 0;
89
+ }
90
+ //#endregion
91
+ //#region src/registry/keypath.ts
92
+ const PATH_LEVEL = /^(\d+)('?)$/;
93
+ const HARDENED_OFFSET = 2147483648;
94
+ /** Parse `m/44'/60'/0'/0/5` into levels. Throws `invalid-props` on anything else. */
95
+ function parsePath(path) {
96
+ if (!path.startsWith("m/")) throw new EraSdkError("invalid-props", `derivation path must start with "m/": ${path}`);
97
+ const segments = path.slice(2).split("/");
98
+ const levels = [];
99
+ for (const segment of segments) {
100
+ const match = PATH_LEVEL.exec(segment);
101
+ if (!match) throw new EraSdkError("invalid-props", `bad derivation path segment "${segment}"`);
102
+ const index = Number(match[1]);
103
+ if (!Number.isSafeInteger(index) || index >= HARDENED_OFFSET) throw new EraSdkError("invalid-props", `derivation index out of range in "${segment}"`);
104
+ levels.push({
105
+ index,
106
+ hardened: match[2] === "'"
107
+ });
108
+ }
109
+ if (levels.length === 0) throw new EraSdkError("invalid-props", "derivation path has no levels");
110
+ return levels;
111
+ }
112
+ function formatPath(levels) {
113
+ return `m/${levels.map((l) => `${l.index}${l.hardened ? "'" : ""}`).join("/")}`;
114
+ }
115
+ function pathEquals(a, b) {
116
+ if (a.length !== b.length) return false;
117
+ return a.every((l, i) => l.index === b[i].index && l.hardened === b[i].hardened);
118
+ }
119
+ /** Flat `[index, hardened, index, hardened, ...]` component list. */
120
+ function pathComponentsCbor(levels) {
121
+ const items = [];
122
+ for (const level of levels) items.push(cbUint(level.index), cbBool(level.hardened));
123
+ return cbArray(items);
124
+ }
125
+ /** A `crypto-keypath` (tag 304): `{1: components, 2: xfp}` (key 2 omitted when no xfp). */
126
+ function keypath304(levels, xfp) {
127
+ const entries = [[1, pathComponentsCbor(levels)]];
128
+ if (xfp !== void 0) entries.push([2, cbUint(xfp)]);
129
+ return cbTag(304, cbMap(entries));
130
+ }
131
+ /** Parse the flat component list of a `crypto-keypath` back into levels (null on malformed). */
132
+ function parsePathComponents(value) {
133
+ const items = asArray(value);
134
+ if (!items || items.length % 2 !== 0) return null;
135
+ const levels = [];
136
+ for (let i = 0; i < items.length; i += 2) {
137
+ const index = asUint(items[i]);
138
+ const hardened = asBool(items[i + 1]);
139
+ if (index === void 0 || hardened === void 0 || index >= BigInt(HARDENED_OFFSET)) return null;
140
+ levels.push({
141
+ index: Number(index),
142
+ hardened
143
+ });
144
+ }
145
+ return levels;
146
+ }
147
+ /** Normalize an xfp given as a u32 int or an 8-hex string into a u32 number. */
148
+ function normalizeXfp(xfp) {
149
+ if (typeof xfp === "number") {
150
+ if (!Number.isSafeInteger(xfp) || xfp < 0 || xfp > 4294967295) throw new EraSdkError("invalid-props", "xfp must be an unsigned 32-bit integer");
151
+ return xfp;
152
+ }
153
+ const hex = xfp.startsWith("0x") ? xfp.slice(2) : xfp;
154
+ if (!/^[0-9a-fA-F]{1,8}$/.test(hex)) throw new EraSdkError("invalid-props", "xfp string must be up to 8 hex characters");
155
+ return Number.parseInt(hex, 16);
156
+ }
157
+ /** Lowercase 8-hex form of an xfp (the display / Tron wire form). */
158
+ function xfpToHex(xfp) {
159
+ return xfp.toString(16).padStart(8, "0");
160
+ }
161
+ //#endregion
162
+ //#region src/core/bytes.ts
163
+ /** Byte helpers. `Uint8Array` end-to-end; no Buffer, no Node built-ins. */
164
+ function concatBytes(...arrays) {
165
+ let total = 0;
166
+ for (const a of arrays) total += a.length;
167
+ const out = new Uint8Array(total);
168
+ let offset = 0;
169
+ for (const a of arrays) {
170
+ out.set(a, offset);
171
+ offset += a.length;
172
+ }
173
+ return out;
174
+ }
175
+ /** Constant-shape byte equality (length check + full loop). */
176
+ function equalBytes(a, b) {
177
+ if (a.length !== b.length) return false;
178
+ let diff = 0;
179
+ for (let i = 0; i < a.length; i++) diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
180
+ return diff === 0;
181
+ }
182
+ /** Big-endian unsigned 32-bit. */
183
+ function u32be(value) {
184
+ const out = /* @__PURE__ */ new Uint8Array(4);
185
+ out[0] = value >>> 24 & 255;
186
+ out[1] = value >>> 16 & 255;
187
+ out[2] = value >>> 8 & 255;
188
+ out[3] = value & 255;
189
+ return out;
190
+ }
191
+ const HEX_CHARS = "0123456789abcdef";
192
+ function bytesToHex(bytes) {
193
+ let out = "";
194
+ for (const b of bytes) out += HEX_CHARS[b >>> 4] + HEX_CHARS[b & 15];
195
+ return out;
196
+ }
197
+ function hexToBytes(hex) {
198
+ let h = hex;
199
+ if (h.startsWith("0x") || h.startsWith("0X")) h = h.slice(2);
200
+ if (h.length % 2 !== 0) throw new Error("hex string has odd length");
201
+ const out = new Uint8Array(h.length / 2);
202
+ for (let i = 0; i < out.length; i++) {
203
+ const byte = Number.parseInt(h.slice(i * 2, i * 2 + 2), 16);
204
+ if (Number.isNaN(byte)) throw new Error("hex string has non-hex characters");
205
+ out[i] = byte;
206
+ }
207
+ return out;
208
+ }
209
+ function bytesToBigint(bytes) {
210
+ let out = 0n;
211
+ for (const b of bytes) out = out << 8n | BigInt(b);
212
+ return out;
213
+ }
214
+ /** UTF-8 encode without TextEncoder (absent on older Hermes). */
215
+ function utf8Encode(text) {
216
+ const out = [];
217
+ for (let i = 0; i < text.length; i++) {
218
+ let code = text.charCodeAt(i);
219
+ if (code < 128) out.push(code);
220
+ else if (code < 2048) out.push(192 | code >> 6, 128 | code & 63);
221
+ else if (code < 55296 || code >= 57344) out.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
222
+ else {
223
+ i++;
224
+ if (i >= text.length) throw new Error("unpaired surrogate in string");
225
+ const next = text.charCodeAt(i);
226
+ code = 65536 + ((code & 1023) << 10 | next & 1023);
227
+ out.push(240 | code >> 18, 128 | code >> 12 & 63, 128 | code >> 6 & 63, 128 | code & 63);
228
+ }
229
+ }
230
+ return new Uint8Array(out);
231
+ }
232
+ /**
233
+ * STRICT UTF-8 decode without TextDecoder (absent on older Hermes). Throws on
234
+ * malformed input, including overlong encodings, surrogate code points and
235
+ * values past U+10FFFF — a lenient decoder would let a hostile reply smuggle
236
+ * bytes that render as different text than they compare as.
237
+ */
238
+ function utf8Decode(bytes) {
239
+ let out = "";
240
+ let i = 0;
241
+ while (i < bytes.length) {
242
+ const b0 = bytes[i];
243
+ if (b0 < 128) {
244
+ out += String.fromCharCode(b0);
245
+ i += 1;
246
+ continue;
247
+ }
248
+ let extra;
249
+ let code;
250
+ let minCode;
251
+ if ((b0 & 224) === 192) {
252
+ extra = 1;
253
+ code = b0 & 31;
254
+ minCode = 128;
255
+ } else if ((b0 & 240) === 224) {
256
+ extra = 2;
257
+ code = b0 & 15;
258
+ minCode = 2048;
259
+ } else if ((b0 & 248) === 240) {
260
+ extra = 3;
261
+ code = b0 & 7;
262
+ minCode = 65536;
263
+ } else throw new Error("malformed UTF-8");
264
+ if (i + extra >= bytes.length) throw new Error("truncated UTF-8");
265
+ for (let k = 1; k <= extra; k++) {
266
+ const bk = bytes[i + k];
267
+ if ((bk & 192) !== 128) throw new Error("malformed UTF-8 continuation");
268
+ code = code << 6 | bk & 63;
269
+ }
270
+ if (code < minCode) throw new Error("overlong UTF-8 encoding");
271
+ if (code >= 55296 && code <= 57343) throw new Error("UTF-8 encodes a surrogate");
272
+ if (code > 1114111) throw new Error("UTF-8 code point out of range");
273
+ if (code > 65535) {
274
+ code -= 65536;
275
+ out += String.fromCharCode(55296 + (code >> 10), 56320 + (code & 1023));
276
+ } else out += String.fromCharCode(code);
277
+ i += 1 + extra;
278
+ }
279
+ return out;
280
+ }
281
+ /** ASCII decode (used for replies that carry text as raw bytes). Throws on non-ASCII. */
282
+ function asciiDecode(bytes) {
283
+ let out = "";
284
+ for (const b of bytes) {
285
+ if (b > 127) throw new Error("non-ASCII byte");
286
+ out += String.fromCharCode(b);
287
+ }
288
+ return out;
289
+ }
290
+ //#endregion
291
+ //#region src/cbor/encode.ts
292
+ /**
293
+ * Deterministic CBOR encoder: definite lengths only, minimal-width integer
294
+ * heads, map entries in insertion order. This matches, byte for byte, what the
295
+ * reference implementation produces and what the device firmware parses — the
296
+ * exact bytes are pinned by golden-vector tests, which is why this encoder is
297
+ * hand-rolled rather than delegated to a dependency's release cadence.
298
+ *
299
+ * It deliberately cannot emit floats, indefinite lengths or exotic simple
300
+ * values: the protocol never uses them.
301
+ */
302
+ function cborEncode(value) {
303
+ const parts = [];
304
+ writeValue(value, parts, 0);
305
+ return concatBytes(...parts);
306
+ }
307
+ const MAX_DEPTH$1 = 16;
308
+ function writeValue(value, parts, depth) {
309
+ if (depth > MAX_DEPTH$1) throw new EraSdkError("malformed-cbor", "cbor encode: nesting too deep");
310
+ switch (value.kind) {
311
+ case "uint":
312
+ parts.push(head(0, value.value));
313
+ return;
314
+ case "nint":
315
+ if (value.value < 0n) throw new EraSdkError("malformed-cbor", "nint holds the magnitude");
316
+ parts.push(head(1, value.value));
317
+ return;
318
+ case "bytes":
319
+ parts.push(head(2, BigInt(value.value.length)), value.value);
320
+ return;
321
+ case "text": {
322
+ const utf8 = utf8Encode(value.value);
323
+ parts.push(head(3, BigInt(utf8.length)), utf8);
324
+ return;
325
+ }
326
+ case "array":
327
+ parts.push(head(4, BigInt(value.items.length)));
328
+ for (const item of value.items) writeValue(item, parts, depth + 1);
329
+ return;
330
+ case "map":
331
+ parts.push(head(5, BigInt(value.entries.length)));
332
+ for (const [k, v] of value.entries) {
333
+ writeValue(k, parts, depth + 1);
334
+ writeValue(v, parts, depth + 1);
335
+ }
336
+ return;
337
+ case "tag":
338
+ parts.push(head(6, BigInt(value.tag)));
339
+ writeValue(value.value, parts, depth + 1);
340
+ return;
341
+ case "bool":
342
+ parts.push(new Uint8Array([value.value ? 245 : 244]));
343
+ return;
344
+ case "null":
345
+ parts.push(new Uint8Array([246]));
346
+ return;
347
+ }
348
+ }
349
+ /** Major-type head with a minimal-width argument. */
350
+ function head(major, arg) {
351
+ if (arg < 0n) throw new EraSdkError("malformed-cbor", "cbor head: negative argument");
352
+ const m = major << 5;
353
+ if (arg < 24n) return new Uint8Array([m | Number(arg)]);
354
+ if (arg <= 255n) return new Uint8Array([m | 24, Number(arg)]);
355
+ if (arg <= 65535n) {
356
+ const n = Number(arg);
357
+ return new Uint8Array([
358
+ m | 25,
359
+ n >>> 8,
360
+ n & 255
361
+ ]);
362
+ }
363
+ if (arg <= 4294967295n) {
364
+ const n = Number(arg);
365
+ return new Uint8Array([
366
+ m | 26,
367
+ n >>> 24 & 255,
368
+ n >>> 16 & 255,
369
+ n >>> 8 & 255,
370
+ n & 255
371
+ ]);
372
+ }
373
+ if (arg <= 18446744073709551615n) {
374
+ const out = /* @__PURE__ */ new Uint8Array(9);
375
+ out[0] = m | 27;
376
+ let v = arg;
377
+ for (let i = 8; i >= 1; i--) {
378
+ out[i] = Number(v & 255n);
379
+ v >>= 8n;
380
+ }
381
+ return out;
382
+ }
383
+ throw new EraSdkError("malformed-cbor", "cbor head: argument exceeds 64 bits");
384
+ }
385
+ //#endregion
386
+ //#region src/cbor/decode.ts
387
+ /**
388
+ * Hardened CBOR decoder for scanned (attacker-controlled) payloads.
389
+ *
390
+ * Policy, enforced as defaults rather than options:
391
+ * - definite lengths only (indefinite refused);
392
+ * - no floats, no simple values beyond bool/null;
393
+ * - duplicate map keys refused;
394
+ * - nesting depth capped;
395
+ * - lengths bounds-checked before any allocation;
396
+ * - trailing bytes after the top-level item refused.
397
+ *
398
+ * Unknown tags are surfaced as `tag` wrappers, never dropped — the tag-37
399
+ * request-id echo is compared tag-agnostically by the callers.
400
+ */
401
+ function cborDecode(bytes) {
402
+ const reader = new Reader(bytes);
403
+ const value = reader.readValue(0);
404
+ if (reader.offset !== bytes.length) throw err("trailing bytes after the top-level item");
405
+ return value;
406
+ }
407
+ const MAX_DEPTH = 16;
408
+ function err(message) {
409
+ return new EraSdkError("malformed-cbor", `cbor: ${message}`);
410
+ }
411
+ var Reader = class {
412
+ constructor(bytes) {
413
+ this.bytes = bytes;
414
+ this.offset = 0;
415
+ }
416
+ readValue(depth) {
417
+ if (depth > MAX_DEPTH) throw err("nesting too deep");
418
+ const initial = this.readByte();
419
+ const major = initial >>> 5;
420
+ const info = initial & 31;
421
+ switch (major) {
422
+ case 0: return {
423
+ kind: "uint",
424
+ value: this.readArg(info)
425
+ };
426
+ case 1: return {
427
+ kind: "nint",
428
+ value: this.readArg(info)
429
+ };
430
+ case 2: {
431
+ const len = this.readLength(info);
432
+ return {
433
+ kind: "bytes",
434
+ value: this.readBytes(len)
435
+ };
436
+ }
437
+ case 3: {
438
+ const len = this.readLength(info);
439
+ const raw = this.readBytes(len);
440
+ let text;
441
+ try {
442
+ text = utf8Decode(raw);
443
+ } catch {
444
+ throw err("text string is not valid UTF-8");
445
+ }
446
+ return {
447
+ kind: "text",
448
+ value: text
449
+ };
450
+ }
451
+ case 4: {
452
+ const len = this.readLength(info);
453
+ if (len > this.bytes.length - this.offset) throw err("array length exceeds input");
454
+ const items = [];
455
+ for (let i = 0; i < len; i++) items.push(this.readValue(depth + 1));
456
+ return {
457
+ kind: "array",
458
+ items
459
+ };
460
+ }
461
+ case 5: {
462
+ const len = this.readLength(info);
463
+ if (len * 2 > this.bytes.length - this.offset) throw err("map length exceeds input");
464
+ const entries = [];
465
+ const seenKeys = /* @__PURE__ */ new Set();
466
+ for (let i = 0; i < len; i++) {
467
+ const key = this.readValue(depth + 1);
468
+ const keyId = bytesToHex(cborEncode(key));
469
+ if (seenKeys.has(keyId)) throw err("duplicate map key");
470
+ seenKeys.add(keyId);
471
+ entries.push([key, this.readValue(depth + 1)]);
472
+ }
473
+ return {
474
+ kind: "map",
475
+ entries
476
+ };
477
+ }
478
+ case 6: {
479
+ const tag = this.readArg(info);
480
+ if (tag > 4294967295n) throw err("tag exceeds 32 bits");
481
+ return {
482
+ kind: "tag",
483
+ tag: Number(tag),
484
+ value: this.readValue(depth + 1)
485
+ };
486
+ }
487
+ case 7:
488
+ if (info === 20) return {
489
+ kind: "bool",
490
+ value: false
491
+ };
492
+ if (info === 21) return {
493
+ kind: "bool",
494
+ value: true
495
+ };
496
+ if (info === 22) return { kind: "null" };
497
+ throw err(`unsupported simple/float value (info ${info})`);
498
+ default: throw err("unreachable major type");
499
+ }
500
+ }
501
+ readByte() {
502
+ const b = this.bytes[this.offset];
503
+ if (b === void 0) throw err("truncated input");
504
+ this.offset += 1;
505
+ return b;
506
+ }
507
+ /** Argument of a head. Refuses indefinite (31) and reserved (28-30). */
508
+ readArg(info) {
509
+ if (info < 24) return BigInt(info);
510
+ if (info === 24) return BigInt(this.readByte());
511
+ if (info === 25) {
512
+ const hi = this.readByte();
513
+ return BigInt(hi << 8 | this.readByte());
514
+ }
515
+ if (info === 26) {
516
+ let v = 0n;
517
+ for (let i = 0; i < 4; i++) v = v << 8n | BigInt(this.readByte());
518
+ return v;
519
+ }
520
+ if (info === 27) {
521
+ let v = 0n;
522
+ for (let i = 0; i < 8; i++) v = v << 8n | BigInt(this.readByte());
523
+ return v;
524
+ }
525
+ if (info === 31) throw err("indefinite lengths are refused");
526
+ throw err(`reserved additional info ${info}`);
527
+ }
528
+ readLength(info) {
529
+ const len = this.readArg(info);
530
+ if (len > BigInt(this.bytes.length - this.offset)) throw err("length exceeds input");
531
+ return Number(len);
532
+ }
533
+ readBytes(length) {
534
+ const end = this.offset + length;
535
+ const out = this.bytes.slice(this.offset, end);
536
+ this.offset = end;
537
+ return out;
538
+ }
539
+ };
540
+ //#endregion
541
+ //#region src/ur/crc32.ts
542
+ /** IEEE CRC-32 (polynomial 0xEDB88320), table-driven, result as unsigned. */
543
+ const TABLE = (() => {
544
+ const table = /* @__PURE__ */ new Uint32Array(256);
545
+ for (let i = 0; i < 256; i++) {
546
+ let c = i;
547
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
548
+ table[i] = c >>> 0;
549
+ }
550
+ return table;
551
+ })();
552
+ function crc32(bytes) {
553
+ let crc = 4294967295;
554
+ for (const byte of bytes) crc = crc >>> 8 ^ TABLE[(crc ^ byte) & 255];
555
+ return (crc ^ 4294967295) >>> 0;
556
+ }
557
+ //#endregion
558
+ //#region src/ur/bytewords.ts
559
+ /**
560
+ * Bytewords codec (minimal style only), per BCR-2020-012.
561
+ *
562
+ * Decode hardening (each of these used to turn malformed input into plausible
563
+ * bytes in naive implementations):
564
+ * - a letter pair that is not a byteword is a refusal, never a fallback byte;
565
+ * - a body shorter than the four CRC words plus one byte is a refusal;
566
+ * - the trailing CRC32 (big-endian) is verified and stripped.
567
+ *
568
+ * The checksum is unkeyed and is not an authentication control — whoever
569
+ * prints the QR prints the CRC too. What it buys is that garbage stops being
570
+ * accepted as data, which frame dedup and reassembly downstream both assume.
571
+ */
572
+ const BYTE_WORDS = "ableacidalsoapexaquaarchatomauntawayaxisbackbaldbarnbeltbetabiasbluebodybragbrewbulbbuzzcalmcashcatschefcityclawcodecolacookcostcruxcurlcuspcyandarkdatadaysdelidicedietdoordowndrawdropdrumdulldutyeacheasyechoedgeepicevenexamexiteyesfactfairfernfigsfilmfishfizzflapflewfluxfoxyfreefrogfuelfundgalagamegeargemsgiftgirlglowgoodgraygrimgurugushgyrohalfhanghardhawkheathelphighhillholyhopehornhutsicedideaidleinchinkyintoirisironitemjadejazzjoinjoltjowljudojugsjumpjunkjurykeepkenokeptkeyskickkilnkingkitekiwiknoblamblavalazyleaflegsliarlimplionlistlogoloudloveluaulucklungmainmanymathmazememomenumeowmildmintmissmonknailnavyneednewsnextnoonnotenumbobeyoboeomitonyxopenovalowlspaidpartpeckplaypluspoempoolposepuffpumapurrquadquizraceramprealredorichroadrockroofrubyruinrunsrustsafesagascarsetssilkskewslotsoapsolosongstubsurfswantacotasktaxitenttiedtimetinytoiltombtoystriptunatwinuglyundouniturgeuservastveryvetovialvibeviewvisavoidvowswallwandwarmwaspwavewaxywebswhatwhenwhizwolfworkyankyawnyellyogayurtzapszerozestzinczonezoom";
573
+ const DIM = 26;
574
+ const A = "a".charCodeAt(0);
575
+ /** Lookup keyed on (first letter, last letter); -1 = not a byteword. */
576
+ const LOOKUP = (() => {
577
+ const table = (/* @__PURE__ */ new Int16Array(676)).fill(-1);
578
+ for (let i = 0; i < 256; i++) {
579
+ const word = BYTE_WORDS.slice(i * 4, i * 4 + 4);
580
+ const x = word.charCodeAt(0) - A;
581
+ const y = word.charCodeAt(3) - A;
582
+ table[y * DIM + x] = i;
583
+ }
584
+ return table;
585
+ })();
586
+ function bytewordsEncode(data) {
587
+ const buf = concatBytes(data, u32be(crc32(data)));
588
+ let out = "";
589
+ for (const byte of buf) {
590
+ const word = BYTE_WORDS.slice(byte * 4, byte * 4 + 4);
591
+ out += word[0] + word[3];
592
+ }
593
+ return out;
594
+ }
595
+ function bytewordsDecode(body) {
596
+ if (body.length % 2 !== 0) throw new EraSdkError("malformed-bytewords", "bytewords: odd number of letters");
597
+ const words = new Uint8Array(body.length / 2);
598
+ for (let i = 0; i < words.length; i++) {
599
+ const x = body.charCodeAt(i * 2) - A;
600
+ const y = body.charCodeAt(i * 2 + 1) - A;
601
+ if (x < 0 || x >= DIM || y < 0 || y >= DIM) throw new EraSdkError("malformed-bytewords", "bytewords: letter out of range");
602
+ const value = LOOKUP[y * DIM + x];
603
+ if (value < 0) throw new EraSdkError("malformed-bytewords", "bytewords: not a byteword");
604
+ words[i] = value;
605
+ }
606
+ if (words.length < 5) throw new EraSdkError("malformed-bytewords", "bytewords: shorter than a checksum plus one byte");
607
+ const bodyBytes = words.slice(0, words.length - 4);
608
+ const declared = (words[words.length - 4] << 24 | words[words.length - 3] << 16 | words[words.length - 2] << 8 | words[words.length - 1]) >>> 0;
609
+ if (crc32(bodyBytes) !== declared) throw new EraSdkError("checksum-mismatch", "bytewords: checksum mismatch");
610
+ return bodyBytes;
611
+ }
612
+ //#endregion
613
+ //#region src/ur/ur.ts
614
+ /** An immutable Uniform Resource: a registry type string plus its CBOR payload. */
615
+ var Ur = class {
616
+ constructor(type, cbor) {
617
+ if (!/^[a-z][a-z0-9-]*$/.test(type)) throw new EraSdkError("invalid-props", `"${type}" is not a valid UR type`);
618
+ this.type = type;
619
+ this.cbor = cbor;
620
+ }
621
+ /** The whole UR as one single-part `ur:` string, lowercase (the loggable form). */
622
+ toString() {
623
+ return `ur:${this.type}/${bytewordsEncode(this.cbor)}`;
624
+ }
625
+ /** The single-part wire form, uppercase (QR alphanumeric mode). */
626
+ toWireString() {
627
+ return this.toString().toUpperCase();
628
+ }
629
+ };
630
+ const UR_GRAMMAR = /^ur:([a-z-]+)(\/(\d+-\d+))?\/([a-z]+)$/;
631
+ /**
632
+ * Parse one `ur:` string into (type, sequence, decoded payload).
633
+ *
634
+ * An ABSENT sequence segment means a single-part UR. A segment that is present
635
+ * but unreadable (a number too wide, `0-0`) is a malformed frame and throws —
636
+ * promoting it to "single-part" would send a broken fragment down the branch
637
+ * that completes a scan.
638
+ */
639
+ function parseUrString(text) {
640
+ const lower = text.toLowerCase();
641
+ const match = UR_GRAMMAR.exec(lower);
642
+ if (!match) throw new EraSdkError("not-a-ur", "not a ur: string");
643
+ const type = match[1];
644
+ const seqSegment = match[3];
645
+ const payload = bytewordsDecode(match[4]);
646
+ if (seqSegment === void 0) return {
647
+ type,
648
+ seq: null,
649
+ payload
650
+ };
651
+ const [numText, lengthText] = seqSegment.split("-");
652
+ const num = Number(numText);
653
+ const length = Number(lengthText);
654
+ if (!Number.isSafeInteger(num) || !Number.isSafeInteger(length) || num <= 0 || length <= 0) throw new EraSdkError("malformed-sequence", "unreadable ur sequence segment");
655
+ return {
656
+ type,
657
+ seq: {
658
+ num,
659
+ length
660
+ },
661
+ payload
662
+ };
663
+ }
664
+ /** The `ur:<type>/` prefix of a frame, without decoding the bytewords body. */
665
+ const TYPE_PREFIX = /^ur:([a-z][a-z0-9-]*)\//;
666
+ function urTypeOf(text) {
667
+ const match = TYPE_PREFIX.exec(text.toLowerCase());
668
+ return match ? match[1] : null;
669
+ }
670
+ //#endregion
671
+ //#region src/core/rand.ts
672
+ /**
673
+ * 16 unpredictable bytes for a sign request id.
674
+ *
675
+ * A CSPRNG output, deliberately NOT a v4/v8 UUID: a UUID spends bits on the
676
+ * wall clock and version fields, leaking the time of signing into the QR and
677
+ * shrinking the unguessable part. The id is what a reply must echo to prove it
678
+ * answers THIS request; it is formatted as a UUID string only where the wire
679
+ * demands one (Tron's `signId`).
680
+ */
681
+ function randomRequestId(randomBytes) {
682
+ if (randomBytes) {
683
+ const out = randomBytes(16);
684
+ if (!(out instanceof Uint8Array) || out.length !== 16) throw new EraSdkError("no-secure-random", "randomBytes(16) did not return 16 bytes");
685
+ return out;
686
+ }
687
+ const crypto = globalThis.crypto;
688
+ if (crypto?.getRandomValues) {
689
+ const out = /* @__PURE__ */ new Uint8Array(16);
690
+ crypto.getRandomValues(out);
691
+ return out;
692
+ }
693
+ throw new EraSdkError("no-secure-random", "no secure random source: install react-native-get-random-values (React Native) or pass randomBytes in the EraConnect config");
694
+ }
695
+ /** Render 16 bytes as a lowercase hyphenated UUID string (8-4-4-4-12). */
696
+ function uuidStringify(bytes) {
697
+ if (bytes.length !== 16) throw new EraSdkError("invalid-props", "request id must be 16 bytes");
698
+ const hex = bytesToHex(bytes);
699
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
700
+ }
701
+ /** Accept a request id as 16 raw bytes or a hyphenated/plain 32-hex string. */
702
+ function normalizeRequestId(id) {
703
+ if (id instanceof Uint8Array) {
704
+ if (id.length !== 16) throw new EraSdkError("invalid-props", "request id must be 16 bytes");
705
+ return new Uint8Array(id);
706
+ }
707
+ const hex = id.replace(/-/g, "");
708
+ if (!/^[0-9a-fA-F]{32}$/.test(hex)) throw new EraSdkError("invalid-props", "request id string must be a 32-hex UUID");
709
+ return hexToBytes(hex.toLowerCase());
710
+ }
711
+ //#endregion
712
+ //#region src/ur/limits.ts
713
+ /**
714
+ * Bounds every field a scanned UR fragment can dictate, BEFORE that field is
715
+ * allowed to size an allocation or a loop.
716
+ *
717
+ * A QR in the camera frame is attacker-controlled input: a sticker on the
718
+ * device, a second screen, a poster. Without these bounds the fragment
719
+ * header's `seqLength` goes straight into array allocation and into a
720
+ * quadratic index shuffle, so ~60 characters of QR can ask the host for
721
+ * gigabytes or minutes of work — no gzip, no multi-frame assembly, one frame.
722
+ *
723
+ * The numbers are generous headroom over real device traffic, NOT tight
724
+ * protocol bounds: a cap that refuses a genuine reply is worse than the
725
+ * denial of service it prevents.
726
+ */
727
+ const UrLimits = {
728
+ /** Largest reassembled UR payload, in bytes. */
729
+ maxMessageBytes: 65536,
730
+ /** Largest number of source fragments a multi-part UR may declare. */
731
+ maxFragmentCount: 2048,
732
+ /** Largest single fragment payload, in bytes (QR v40 tops out at 2953). */
733
+ maxFragmentBytes: 4096,
734
+ /** Largest value for any u32 header field (`seqNum`, `checksum`). */
735
+ maxUint32: 4294967295
736
+ };
737
+ /**
738
+ * Whether a fragment header describes a UR that could exist.
739
+ *
740
+ * The two inequalities are the BC-UR relation
741
+ * `seqLength == ceil(messageLength / fragmentLength)` written without
742
+ * division — exactly what both fountain encoders produce. They stop a header
743
+ * from claiming thousands of fragments for a twenty-byte message.
744
+ *
745
+ * `seqLength >= 2`, not 1: a "multi-part" UR with a single source fragment is
746
+ * something neither encoder can produce (both short-circuit to a single-part
747
+ * UR), and it would defeat the two-fragment stream-binding rule with two
748
+ * static images (`1-1` and `2-1` differ only in seqNum and both resolve to
749
+ * fragment 0).
750
+ */
751
+ function headerIsConsistent(header) {
752
+ const { seqNum, seqLength, messageLength, checksum, fragmentLength } = header;
753
+ if (seqNum < 1 || seqNum > UrLimits.maxUint32) return false;
754
+ if (checksum < 0 || checksum > UrLimits.maxUint32) return false;
755
+ if (seqLength < 2 || seqLength > UrLimits.maxFragmentCount) return false;
756
+ if (fragmentLength < 1 || fragmentLength > UrLimits.maxFragmentBytes) return false;
757
+ if (messageLength < 1 || messageLength > UrLimits.maxMessageBytes) return false;
758
+ if (messageLength > seqLength * fragmentLength) return false;
759
+ if (messageLength <= (seqLength - 1) * fragmentLength) return false;
760
+ return true;
761
+ }
762
+ //#endregion
763
+ //#region src/ur/xoshiro.ts
764
+ /**
765
+ * Xoshiro256** seeded from a 32-byte digest, with the exact
766
+ * `(x >>> 11) * 2^-53` double conversion the BC-UR fountain code uses.
767
+ *
768
+ * The draw sequence IS the wire protocol: the device runs the same PRNG over
769
+ * the same seed to derive which source fragments a fountain frame covers.
770
+ */
771
+ const MASK64 = (1n << 64n) - 1n;
772
+ function rotl(x, k) {
773
+ return (x << k | x >> 64n - k) & MASK64;
774
+ }
775
+ var Xoshiro256ss = class {
776
+ /** Seed from a 32-byte digest split into four big-endian u64 words. */
777
+ constructor(digest) {
778
+ if (digest.length !== 32) throw new Error("xoshiro seed must be 32 bytes");
779
+ const word = (offset) => {
780
+ let v = 0n;
781
+ for (let i = 0; i < 8; i++) v = v << 8n | BigInt(digest[offset + i]);
782
+ return v;
783
+ };
784
+ this.s0 = word(0);
785
+ this.s1 = word(8);
786
+ this.s2 = word(16);
787
+ this.s3 = word(24);
788
+ if ((this.s0 | this.s1 | this.s2 | this.s3) === 0n) throw new Error("xoshiro seed must not be all zeros");
789
+ }
790
+ nextRaw64() {
791
+ const result = rotl(this.s1 * 5n & MASK64, 7n) * 9n & MASK64;
792
+ const t = this.s1 << 17n & MASK64;
793
+ this.s2 ^= this.s0;
794
+ this.s3 ^= this.s1;
795
+ this.s1 ^= this.s2;
796
+ this.s0 ^= this.s3;
797
+ this.s2 ^= t;
798
+ this.s3 = rotl(this.s3, 45n);
799
+ return result;
800
+ }
801
+ /** Uniform double in [0, 1): top 53 bits of the raw draw. Exact — no precision loss. */
802
+ nextDouble() {
803
+ return Number(this.nextRaw64() >> 11n) * 2 ** -53;
804
+ }
805
+ };
806
+ //#endregion
807
+ //#region src/ur/sampler.ts
808
+ /**
809
+ * Which source fragments the fountain frame `seqNum` of `seqLength` covers.
810
+ *
811
+ * For `seqNum <= seqLength` the frame is the source fragment itself. Above
812
+ * that, the BC-UR fountain sampler runs: seed = sha256(seqNum || checksum)
813
+ * (both big-endian u32), Xoshiro256** drives an alias-method degree chooser
814
+ * over `1/(i+1)` weights, then a full draw-without-replacement permutation of
815
+ * which the first `degree` indexes are taken.
816
+ *
817
+ * Every draw below happens in the exact order of the reference
818
+ * implementation. The draw order IS the wire protocol — a different (even
819
+ * "equivalent") shuffle makes the device's fountain frames undecodable.
820
+ */
821
+ function chooseFragmentIndexes(seqNum, seqLength, checksum) {
822
+ if (seqLength < 1 || seqLength > UrLimits.maxFragmentCount) throw new RangeError(`seqLength ${seqLength} outside 1..${UrLimits.maxFragmentCount}; cannot build fountain indexes for a UR this large`);
823
+ if (seqNum <= seqLength) return [seqNum - 1];
824
+ const rng = new Xoshiro256ss(sha256(concatBytes(u32be(seqNum), u32be(checksum))));
825
+ const scaled = new Array(seqLength);
826
+ let sum = 0;
827
+ for (let i = 0; i < seqLength; i++) sum += 1 / (i + 1);
828
+ for (let i = 0; i < seqLength; i++) scaled[i] = 1 / (i + 1) * seqLength / sum;
829
+ const prob = new Array(seqLength).fill(0);
830
+ const alias = new Array(seqLength).fill(0);
831
+ const small = [];
832
+ const large = [];
833
+ for (let i = seqLength - 1; i >= 0; i--) (scaled[i] < 1 ? small : large).push(i);
834
+ while (small.length > 0 && large.length > 0) {
835
+ const less = small.pop();
836
+ const more = large.pop();
837
+ prob[less] = scaled[less];
838
+ alias[less] = more;
839
+ scaled[more] = scaled[more] + scaled[less] - 1;
840
+ (scaled[more] < 1 ? small : large).push(more);
841
+ }
842
+ while (large.length > 0) prob[large.pop()] = 1;
843
+ while (small.length > 0) prob[small.pop()] = 1;
844
+ const c = Math.floor(rng.nextDouble() * prob.length);
845
+ const degree = (rng.nextDouble() < prob[c] ? c : alias[c]) + 1;
846
+ const remaining = [];
847
+ for (let i = 0; i < seqLength; i++) remaining.push(i);
848
+ const permutation = [];
849
+ while (remaining.length > 0) {
850
+ const index = Math.floor(rng.nextDouble() * remaining.length);
851
+ permutation.push(remaining.splice(index, 1)[0]);
852
+ }
853
+ return permutation.slice(0, degree);
854
+ }
855
+ //#endregion
856
+ //#region src/ur/fragment.ts
857
+ const isSimple = (fragment) => fragment.indexes.length === 1;
858
+ /** Fragment CBOR: the definite 5-array `[seqNum, seqLen, msgLen, checksum, bytes]`. */
859
+ function fragmentCbor(seqNum, seqLength, messageLength, checksum, part) {
860
+ return cborEncode(cbArray([
861
+ cbUint(seqNum),
862
+ cbUint(seqLength),
863
+ cbUint(messageLength),
864
+ cbUint(checksum),
865
+ cbBytes(part)
866
+ ]));
867
+ }
868
+ /**
869
+ * Parse and validate a fragment payload, or return null.
870
+ *
871
+ * Every field here is chosen by whoever printed the QR, and three of them size
872
+ * allocations or loops downstream — so the bounds are checked as a set BEFORE
873
+ * the (quadratic) fountain index derivation pays for anything.
874
+ */
875
+ function tryParseFragment(type, payload) {
876
+ let decoded;
877
+ try {
878
+ decoded = cborDecode(payload);
879
+ } catch {
880
+ return null;
881
+ }
882
+ if (decoded.kind !== "array" || decoded.items.length !== 5) return null;
883
+ const seqNum = uintInRange(decoded.items[0]);
884
+ const seqLength = uintInRange(decoded.items[1]);
885
+ const messageLength = uintInRange(decoded.items[2]);
886
+ const checksum = uintInRange(decoded.items[3]);
887
+ const partValue = decoded.items[4];
888
+ if (seqNum === null || seqLength === null || messageLength === null || checksum === null || partValue?.kind !== "bytes") return null;
889
+ const part = partValue.value;
890
+ if (!headerIsConsistent({
891
+ seqNum,
892
+ seqLength,
893
+ messageLength,
894
+ checksum,
895
+ fragmentLength: part.length
896
+ })) return null;
897
+ return {
898
+ type,
899
+ seqNum,
900
+ seqLength,
901
+ messageLength,
902
+ checksum,
903
+ part,
904
+ indexes: chooseFragmentIndexes(seqNum, seqLength, checksum)
905
+ };
906
+ }
907
+ /** A CBOR uint in [0, 2^32), or null for anything else. */
908
+ function uintInRange(value) {
909
+ if (value?.kind !== "uint") return null;
910
+ const big = value.value;
911
+ if (big < 0n || big > BigInt(UrLimits.maxUint32)) return null;
912
+ return Number(big);
913
+ }
914
+ //#endregion
915
+ //#region src/ur/encoder.ts
916
+ /**
917
+ * BC-UR fountain encoder.
918
+ *
919
+ * Partitioning picks the LARGEST fragment length `<= maxFragmentLength` that
920
+ * evenly covers the payload (`ceil(len/count)` for the smallest sufficient
921
+ * `count`), and the last fragment is zero-padded to the common length — both
922
+ * exactly as the reference encoders do, because the receiving side's header
923
+ * consistency check assumes this relation.
924
+ *
925
+ * A payload that fits one fragment is emitted as the plain single-part
926
+ * `ur:<type>/<body>` form on every call — never as a `1-1` sequence.
927
+ */
928
+ var UrFountainEncoder = class {
929
+ constructor(ur, maxFragmentLength = 180, minFragmentLength = 10) {
930
+ this.seqNum = 0;
931
+ if (ur.cbor.length === 0) throw new EraSdkError("invalid-props", "cannot encode an empty UR payload");
932
+ if (maxFragmentLength < minFragmentLength || maxFragmentLength <= 0 || minFragmentLength <= 0) throw new EraSdkError("invalid-props", "invalid fragment length bounds");
933
+ this.ur = ur;
934
+ this.checksum = crc32(ur.cbor);
935
+ this.fragments = partition(ur.cbor, maxFragmentLength, minFragmentLength);
936
+ }
937
+ get isSinglePart() {
938
+ return this.fragments.length <= 1;
939
+ }
940
+ /** How many source fragments the payload was split into (1 for single-part). */
941
+ get fragmentCount() {
942
+ return this.fragments.length;
943
+ }
944
+ /** Next wire frame, uppercase. Single-part payloads return the same string every call. */
945
+ nextPart() {
946
+ if (this.isSinglePart) return this.ur.toWireString();
947
+ this.seqNum += 1;
948
+ const indexes = chooseFragmentIndexes(this.seqNum, this.fragments.length, this.checksum);
949
+ const first = this.fragments[0];
950
+ const mixed = new Uint8Array(first.length);
951
+ for (const index of indexes) {
952
+ const fragment = this.fragments[index];
953
+ for (let i = 0; i < mixed.length; i++) mixed[i] = mixed[i] ^ (fragment[i] ?? 0);
954
+ }
955
+ const body = fragmentCbor(this.seqNum, this.fragments.length, this.ur.cbor.length, this.checksum, mixed);
956
+ return `ur:${this.ur.type}/${this.seqNum}-${this.fragments.length}/${bytewordsEncode(body)}`.toUpperCase();
957
+ }
958
+ };
959
+ /** Largest `ceil(len/count) <= maxLength` split, last fragment zero-padded. */
960
+ function partition(payload, maxLength, minLength) {
961
+ const maxCount = Math.ceil(payload.length / minLength);
962
+ let fragmentLength = payload.length;
963
+ for (let count = 1; count <= maxCount; count++) {
964
+ fragmentLength = Math.ceil(payload.length / count);
965
+ if (fragmentLength <= maxLength) break;
966
+ }
967
+ const fragments = [];
968
+ for (let offset = 0; offset < payload.length; offset += fragmentLength) {
969
+ const slice = payload.slice(offset, offset + fragmentLength);
970
+ if (slice.length < fragmentLength) {
971
+ const padded = new Uint8Array(fragmentLength);
972
+ padded.set(slice);
973
+ fragments.push(padded);
974
+ } else fragments.push(slice);
975
+ }
976
+ return fragments;
977
+ }
978
+ //#endregion
979
+ //#region src/qr/animated-ur.ts
980
+ const DEFAULT_FRAGMENT_LENGTH = 180;
981
+ /**
982
+ * Frame source for rendering a UR as an animated QR.
983
+ *
984
+ * Drive `nextFrame()` from your own ticker (~8 fps is the battle-tested
985
+ * default) and hand each string to your QR component. Frames are UPPERCASE so
986
+ * the QR encoder can use alphanumeric mode (~45% denser than byte mode).
987
+ */
988
+ var AnimatedUr = class {
989
+ constructor(ur, options) {
990
+ this.encoder = new UrFountainEncoder(ur, options?.maxFragmentLength ?? 180);
991
+ }
992
+ /** Whether the payload fits one QR (no animation needed). */
993
+ get isSingleFrame() {
994
+ return this.encoder.isSinglePart;
995
+ }
996
+ /** The UR registry type being sent, e.g. `eth-sign-request`. */
997
+ get urType() {
998
+ return this.encoder.ur.type;
999
+ }
1000
+ /** How many source fragments the payload was split into. */
1001
+ get fragmentCount() {
1002
+ return this.encoder.fragmentCount;
1003
+ }
1004
+ /** Next wire frame (uppercase). Single-frame payloads return the same string every call. */
1005
+ nextFrame() {
1006
+ return this.encoder.nextPart();
1007
+ }
1008
+ /** The whole request as ONE lowercase `ur:` string — the loggable form, not what is on screen. */
1009
+ toString() {
1010
+ return this.encoder.ur.toString();
1011
+ }
1012
+ };
1013
+ //#endregion
1014
+ //#region src/ur/decoder.ts
1015
+ /**
1016
+ * BC-UR fountain decoder with hostile-input stream binding.
1017
+ *
1018
+ * The naive decoder pins its expectations to the FIRST fragment it ever sees
1019
+ * and drops everything that disagrees. That is right while the only thing in
1020
+ * front of the camera is the device — and it is exactly how one hostile QR (a
1021
+ * sticker, a poster, a second screen) used to end the whole session: it bound
1022
+ * first, and the device's real answer could never assemble.
1023
+ *
1024
+ * The cure is to make binding harder, not reversible:
1025
+ *
1026
+ * - a stream binds only PROVISIONALLY on its first fragment, and is
1027
+ * CONFIRMED only when a second, distinct fragment of the same stream
1028
+ * arrives (same fingerprint, different seqNum). A static QR is one
1029
+ * fragment forever and can never confirm itself;
1030
+ * - a provisional binding is dropped after 32 non-matching frames — a
1031
+ * genuine stream confirms on its very next frame, so this cannot be aimed
1032
+ * at one;
1033
+ * - a CONFIRMED binding is never evicted. Any recovery path is an eviction
1034
+ * path, so there is none. A rogue fragment that poisons the XOR costs the
1035
+ * accumulated progress (rescan one animation pass), never the binding;
1036
+ * - a single-part UR cannot complete the scan while a confirmed multi-part
1037
+ * assembly holds received fragments.
1038
+ *
1039
+ * What this does not defend against is an attacker who owns the camera
1040
+ * outright — if the only well-formed UR in view is theirs, it assembles. The
1041
+ * layers above (type pinning per request, request-id echo, verification
1042
+ * helpers) are what refuse that.
1043
+ */
1044
+ var UrDecoder = class UrDecoder {
1045
+ constructor() {
1046
+ this.boundType = "";
1047
+ this.seqLength = 0;
1048
+ this.expectedMessageLength = 0;
1049
+ this.expectedChecksum = 0;
1050
+ this.expectedFragmentLength = 0;
1051
+ this.confirmed = false;
1052
+ this.framesSinceBinding = 0;
1053
+ this.bindingSeqNum = 0;
1054
+ this.expectedIndexes = [];
1055
+ this.receivedIndexes = [];
1056
+ this.mixedParts = [];
1057
+ this.queuedParts = [];
1058
+ this.simpleParts = [];
1059
+ this.payload = null;
1060
+ this.completedType = "";
1061
+ this.lastRefusal = null;
1062
+ }
1063
+ get isComplete() {
1064
+ return this.payload !== null;
1065
+ }
1066
+ /** The type of the bound (or completed) stream; empty until one binds. */
1067
+ get type() {
1068
+ return this.payload !== null ? this.completedType : this.boundType;
1069
+ }
1070
+ get partsExpected() {
1071
+ return this.expectedIndexes.length;
1072
+ }
1073
+ get partsReceived() {
1074
+ return this.receivedIndexes.length;
1075
+ }
1076
+ /** Assembly progress in [0, 1]. */
1077
+ get progress() {
1078
+ if (this.isComplete) return 1;
1079
+ if (this.expectedIndexes.length === 0) return 0;
1080
+ return this.receivedIndexes.length / this.expectedIndexes.length;
1081
+ }
1082
+ /** The assembled UR. Throws until `isComplete`. */
1083
+ result() {
1084
+ if (this.payload === null) throw new EraSdkError("incomplete-scan", "UR not fully assembled yet");
1085
+ return new Ur(this.completedType, this.payload);
1086
+ }
1087
+ /**
1088
+ * Feed one scanned frame. Returns true once the UR is fully assembled.
1089
+ *
1090
+ * Throws EraSdkError for frames that are not parseable URs at all
1091
+ * (`not-a-ur`, `malformed-bytewords`, `checksum-mismatch`,
1092
+ * `malformed-sequence`); refusals of parseable frames set [lastRefusal]
1093
+ * and return false.
1094
+ */
1095
+ receivePart(text) {
1096
+ if (this.isComplete) return false;
1097
+ this.lastRefusal = null;
1098
+ const parsed = parseUrString(text);
1099
+ if (parsed.seq === null) {
1100
+ if (parsed.payload.length === 0 || parsed.payload.length > UrLimits.maxMessageBytes) {
1101
+ this.lastRefusal = {
1102
+ code: "limit-exceeded",
1103
+ message: `single-part payload of ${parsed.payload.length} bytes is outside 1..${UrLimits.maxMessageBytes}`
1104
+ };
1105
+ return false;
1106
+ }
1107
+ if (this.confirmed && this.receivedIndexes.length > 0) {
1108
+ this.lastRefusal = {
1109
+ code: "fragment-mismatch",
1110
+ message: `a single-part UR arrived while a "${this.boundType}" assembly was under way`
1111
+ };
1112
+ return false;
1113
+ }
1114
+ this.completedType = parsed.type;
1115
+ this.payload = parsed.payload;
1116
+ return true;
1117
+ }
1118
+ const fragment = tryParseFragment(parsed.type, parsed.payload);
1119
+ if (fragment === null) {
1120
+ this.lastRefusal = {
1121
+ code: "limit-exceeded",
1122
+ message: "fragment header is malformed or outside the UrLimits bounds"
1123
+ };
1124
+ return false;
1125
+ }
1126
+ if (fragment.seqNum !== parsed.seq.num || fragment.seqLength !== parsed.seq.length) {
1127
+ this.lastRefusal = {
1128
+ code: "fragment-mismatch",
1129
+ message: "fragment header disagrees with the ur: path sequence"
1130
+ };
1131
+ return false;
1132
+ }
1133
+ if (!this.checkBinding(fragment)) return false;
1134
+ this.queuedParts.push(fragment);
1135
+ while (!this.isComplete && this.queuedParts.length > 0) this.processQueuedItem();
1136
+ return this.isComplete;
1137
+ }
1138
+ fingerprintOf(type, seqLength, messageLength, checksum, fragmentLength) {
1139
+ return `${type}|${seqLength}|${messageLength}|${checksum}|${fragmentLength}`;
1140
+ }
1141
+ /** Decide whether the fragment belongs to the bound stream; bind/confirm/drop per the rules above. */
1142
+ checkBinding(fragment) {
1143
+ const fingerprint = this.fingerprintOf(fragment.type, fragment.seqLength, fragment.messageLength, fragment.checksum, fragment.part.length);
1144
+ if (this.boundType !== "") {
1145
+ if (fingerprint === this.fingerprintOf(this.boundType, this.seqLength, this.expectedMessageLength, this.expectedChecksum, this.expectedFragmentLength)) {
1146
+ if (!this.confirmed && fragment.seqNum !== this.bindingSeqNum) this.confirmed = true;
1147
+ return true;
1148
+ }
1149
+ if (this.confirmed) {
1150
+ this.lastRefusal = {
1151
+ code: "fragment-mismatch",
1152
+ message: "fragment belongs to a different stream than the confirmed assembly"
1153
+ };
1154
+ return false;
1155
+ }
1156
+ this.framesSinceBinding += 1;
1157
+ if (this.framesSinceBinding < UrDecoder.framesBeforeDroppingProvisional) {
1158
+ this.lastRefusal = {
1159
+ code: "fragment-mismatch",
1160
+ message: "fragment belongs to a different stream than the provisional binding"
1161
+ };
1162
+ return false;
1163
+ }
1164
+ this.discardBinding();
1165
+ }
1166
+ this.boundType = fragment.type;
1167
+ this.seqLength = fragment.seqLength;
1168
+ this.expectedMessageLength = fragment.messageLength;
1169
+ this.expectedChecksum = fragment.checksum;
1170
+ this.expectedFragmentLength = fragment.part.length;
1171
+ this.bindingSeqNum = fragment.seqNum;
1172
+ this.confirmed = false;
1173
+ this.framesSinceBinding = 0;
1174
+ this.expectedIndexes.length = 0;
1175
+ for (let i = 0; i < fragment.seqLength; i++) this.expectedIndexes.push(i);
1176
+ return true;
1177
+ }
1178
+ /** Drop a binding that never proved itself (provisional only). */
1179
+ discardBinding() {
1180
+ this.boundType = "";
1181
+ this.seqLength = 0;
1182
+ this.expectedMessageLength = 0;
1183
+ this.expectedChecksum = 0;
1184
+ this.expectedFragmentLength = 0;
1185
+ this.confirmed = false;
1186
+ this.framesSinceBinding = 0;
1187
+ this.bindingSeqNum = 0;
1188
+ this.expectedIndexes.length = 0;
1189
+ this.receivedIndexes.length = 0;
1190
+ this.mixedParts = [];
1191
+ this.queuedParts.length = 0;
1192
+ this.simpleParts.length = 0;
1193
+ }
1194
+ /**
1195
+ * Throw away the accumulation, KEEPING the binding.
1196
+ *
1197
+ * Reached when the reassembled payload does not hash to the stream's own
1198
+ * declared checksum — a rogue fragment that copied the visible header and
1199
+ * poisoned the XOR. Unbinding here would hand back the eviction primitive
1200
+ * the binding rule denies, so only the collected fragments are discarded:
1201
+ * one pass of the animation for the genuine sender, one fragment per pass
1202
+ * for the attacker, forever.
1203
+ */
1204
+ discardAccumulation() {
1205
+ this.expectedIndexes.length = 0;
1206
+ if (this.seqLength > 0) for (let i = 0; i < this.seqLength; i++) this.expectedIndexes.push(i);
1207
+ this.receivedIndexes.length = 0;
1208
+ this.mixedParts = [];
1209
+ this.queuedParts.length = 0;
1210
+ this.simpleParts.length = 0;
1211
+ }
1212
+ processQueuedItem() {
1213
+ const part = this.queuedParts.shift();
1214
+ if (!part) return;
1215
+ if (isSimple(part)) this.processSimplePart(part);
1216
+ else this.processMixedPart(part);
1217
+ }
1218
+ processSimplePart(fragment) {
1219
+ const fragmentIndex = fragment.indexes[0];
1220
+ if (this.receivedIndexes.includes(fragmentIndex)) return;
1221
+ this.simpleParts.push(fragment);
1222
+ this.receivedIndexes.push(fragmentIndex);
1223
+ if (sameMembers(this.receivedIndexes, this.expectedIndexes)) {
1224
+ const sorted = [...this.simpleParts].sort((a, b) => a.indexes[0] - b.indexes[0]);
1225
+ let joinedLength = 0;
1226
+ for (const p of sorted) joinedLength += p.part.length;
1227
+ const joined = new Uint8Array(joinedLength);
1228
+ let offset = 0;
1229
+ for (const p of sorted) {
1230
+ joined.set(p.part, offset);
1231
+ offset += p.part.length;
1232
+ }
1233
+ if (joined.length < this.expectedMessageLength) {
1234
+ this.discardAccumulation();
1235
+ return;
1236
+ }
1237
+ const candidate = joined.slice(0, this.expectedMessageLength);
1238
+ if (crc32(candidate) !== this.expectedChecksum) {
1239
+ this.discardAccumulation();
1240
+ return;
1241
+ }
1242
+ this.completedType = this.boundType;
1243
+ this.payload = candidate;
1244
+ } else this.reduceMixedBy(fragment);
1245
+ }
1246
+ processMixedPart(fragment) {
1247
+ if (this.mixedParts.some((e) => sameMembers([...e.indexes], [...fragment.indexes]))) return;
1248
+ if (this.mixedParts.length >= UrLimits.maxFragmentCount) return;
1249
+ let simple = fragment;
1250
+ for (const s of this.simpleParts) simple = this.reducePartByPart(simple, s);
1251
+ let part = simple;
1252
+ for (const m of this.mixedParts) part = this.reducePartByPart(part, m);
1253
+ if (isSimple(part)) this.queuedParts.push(part);
1254
+ else {
1255
+ this.reduceMixedBy(part);
1256
+ this.mixedParts.push(part);
1257
+ }
1258
+ }
1259
+ reduceMixedBy(fragment) {
1260
+ const newMixed = [];
1261
+ for (const item of this.mixedParts) {
1262
+ const reduced = this.reducePartByPart(item, fragment);
1263
+ if (isSimple(reduced)) this.queuedParts.push(item);
1264
+ else newMixed.push(reduced);
1265
+ }
1266
+ this.mixedParts = newMixed;
1267
+ }
1268
+ reducePartByPart(a, b) {
1269
+ if (!b.indexes.every((e) => a.indexes.includes(e))) return a;
1270
+ const newIndexes = a.indexes.filter((e) => !b.indexes.includes(e));
1271
+ const newLength = Math.max(a.part.length, b.part.length);
1272
+ const newPart = new Uint8Array(newLength);
1273
+ for (let i = 0; i < newLength; i++) newPart[i] = (a.part[i] ?? 0) ^ (b.part[i] ?? 0);
1274
+ return {
1275
+ type: a.type,
1276
+ seqNum: a.seqNum,
1277
+ seqLength: a.seqLength,
1278
+ messageLength: this.expectedMessageLength,
1279
+ checksum: crc32(a.part),
1280
+ part: newPart,
1281
+ indexes: newIndexes
1282
+ };
1283
+ }
1284
+ };
1285
+ UrDecoder.framesBeforeDroppingProvisional = 32;
1286
+ /** Order-insensitive membership equality (mirrors the reference `arraysEqual`). */
1287
+ function sameMembers(a, b) {
1288
+ if (a.length !== b.length) return false;
1289
+ return a.every((e) => b.includes(e));
1290
+ }
1291
+ //#endregion
1292
+ //#region src/scan/ur-scanner.ts
1293
+ /**
1294
+ * Accumulates camera frames into a UR. Synchronous and non-throwing on the
1295
+ * feed path (safe to call from camera callbacks); malformed frames come back
1296
+ * as typed rejections, never exceptions.
1297
+ */
1298
+ var UrScanner = class UrScanner {
1299
+ constructor(options) {
1300
+ this.decoder = new UrDecoder();
1301
+ this.seen = /* @__PURE__ */ new Set();
1302
+ this.rejection = null;
1303
+ this.expectedTypes = options?.expectedTypes ? new Set(options.expectedTypes) : null;
1304
+ }
1305
+ get isComplete() {
1306
+ return this.decoder.isComplete;
1307
+ }
1308
+ get progress() {
1309
+ return this.decoder.progress;
1310
+ }
1311
+ /** The UR type of the bound stream, or null until one binds. */
1312
+ get urType() {
1313
+ return this.decoder.type === "" ? null : this.decoder.type;
1314
+ }
1315
+ get framesReceived() {
1316
+ return this.decoder.partsReceived;
1317
+ }
1318
+ get framesExpected() {
1319
+ return this.decoder.partsExpected;
1320
+ }
1321
+ get lastRejection() {
1322
+ return this.rejection;
1323
+ }
1324
+ /** Feed one scanned frame. */
1325
+ receivePart(frame) {
1326
+ if (this.decoder.isComplete) return {
1327
+ kind: "complete",
1328
+ ur: this.decoder.result()
1329
+ };
1330
+ if (this.seen.has(frame)) return { kind: "duplicate" };
1331
+ const type = urTypeOf(frame);
1332
+ if (type === null) return this.reject("not-a-ur", "not a UR frame");
1333
+ if (this.expectedTypes && !this.expectedTypes.has(type)) {
1334
+ const shown = type.length > 32 ? `${type.slice(0, 32)}…` : type;
1335
+ return this.reject("wrong-ur-type", `ignored a "${shown}" frame; expected ${[...this.expectedTypes].join(" or ")}`);
1336
+ }
1337
+ if (this.seen.size < UrScanner.maxRememberedFrames) this.seen.add(frame);
1338
+ let complete;
1339
+ try {
1340
+ complete = this.decoder.receivePart(frame);
1341
+ } catch (e) {
1342
+ const code = e instanceof EraSdkError ? e.code : "not-a-ur";
1343
+ return this.reject(code, "unreadable UR frame");
1344
+ }
1345
+ if (this.decoder.lastRefusal) return this.reject(this.decoder.lastRefusal.code, this.decoder.lastRefusal.message);
1346
+ if (complete) {
1347
+ this.rejection = null;
1348
+ return {
1349
+ kind: "complete",
1350
+ ur: this.decoder.result()
1351
+ };
1352
+ }
1353
+ return {
1354
+ kind: "progress",
1355
+ progress: this.decoder.progress,
1356
+ framesReceived: this.decoder.partsReceived,
1357
+ framesExpected: this.decoder.partsExpected
1358
+ };
1359
+ }
1360
+ /** The assembled UR. Throws `incomplete-scan` until done. */
1361
+ result() {
1362
+ return this.decoder.result();
1363
+ }
1364
+ reject(code, message) {
1365
+ const previous = this.rejection;
1366
+ this.rejection = previous && previous.code === code && previous.message === message ? {
1367
+ code,
1368
+ message,
1369
+ repeated: previous.repeated + 1
1370
+ } : {
1371
+ code,
1372
+ message,
1373
+ repeated: 1
1374
+ };
1375
+ return {
1376
+ kind: "rejected",
1377
+ rejection: this.rejection
1378
+ };
1379
+ }
1380
+ };
1381
+ UrScanner.maxRememberedFrames = 4096;
1382
+ /** A scanner whose completed UR parses into a typed result (a chain signature). */
1383
+ var TypedUrScanner = class extends UrScanner {
1384
+ constructor(options, parseResult) {
1385
+ super(options);
1386
+ this.parseResult = parseResult;
1387
+ }
1388
+ /** Assemble + parse + validate (UR type, request-id echo) in one call. */
1389
+ parse() {
1390
+ return this.parseResult(this.result());
1391
+ }
1392
+ };
1393
+ //#endregion
1394
+ //#region src/chains/shared.ts
1395
+ const DEFAULT_ORIGIN = "ERA Connect";
1396
+ function resolveContext(config) {
1397
+ return {
1398
+ origin: config?.origin ?? "ERA Connect",
1399
+ randomBytes: config?.randomBytes ?? void 0,
1400
+ maxFragmentLength: config?.maxFragmentLength ?? 180
1401
+ };
1402
+ }
1403
+ function makeSignRequest(args) {
1404
+ const { ur, requestId, replyTypes, context, parse } = args;
1405
+ return {
1406
+ ur,
1407
+ requestId,
1408
+ replyTypes,
1409
+ warnings: args.warnings ?? [],
1410
+ toAnimated: (options) => new AnimatedUr(ur, { maxFragmentLength: options?.maxFragmentLength ?? context.maxFragmentLength ?? 180 }),
1411
+ scanner: () => new TypedUrScanner({ expectedTypes: replyTypes }, parse)
1412
+ };
1413
+ }
1414
+ /** Mint or normalize a request id. */
1415
+ function resolveRequestId(context, requestId) {
1416
+ return requestId === void 0 ? randomRequestId(context.randomBytes) : normalizeRequestId(requestId);
1417
+ }
1418
+ /** Accept a reply as a `Ur` object or a single-part `ur:` string. */
1419
+ function toUr(input) {
1420
+ if (typeof input !== "string") return input;
1421
+ const parsed = parseUrString(input);
1422
+ if (parsed.seq !== null) throw new EraSdkError("invalid-props", "multi-part UR string: assemble it with the request scanner first");
1423
+ return new Ur(parsed.type, parsed.payload);
1424
+ }
1425
+ function requireUrType(ur, expected, what) {
1426
+ if (!expected.includes(ur.type)) {
1427
+ const shown = ur.type.length > 32 ? `${ur.type.slice(0, 32)}…` : ur.type;
1428
+ throw new EraSdkError("wrong-ur-type", `unexpected ${what} UR type "${shown}", expected ${expected.join(" or ")}`, {
1429
+ received: shown,
1430
+ expected
1431
+ });
1432
+ }
1433
+ }
1434
+ function requireReplyMap(ur, what) {
1435
+ let decoded;
1436
+ try {
1437
+ decoded = cborDecode(ur.cbor);
1438
+ } catch (e) {
1439
+ throw new EraSdkError("malformed-cbor", `${what} is not readable CBOR: ${e.message}`);
1440
+ }
1441
+ const map = asMap(decoded);
1442
+ if (!map) throw new EraSdkError("malformed-reply", `${what} is not a CBOR map`);
1443
+ return map;
1444
+ }
1445
+ /**
1446
+ * The reply must echo the request id byte for byte.
1447
+ *
1448
+ * BYTES, not CBOR values: the device wraps the echo in the UUID tag (37) while
1449
+ * requests may send it untagged, so a value-level comparison would reject
1450
+ * every genuine reply. An absent echo is a reply that did not come from the
1451
+ * request in hand (the device echoes unconditionally when the request carried
1452
+ * an id) and is refused rather than tolerated.
1453
+ */
1454
+ function requireRequestIdEcho(map, key, expected, what) {
1455
+ const echoed = mapGet(map, key);
1456
+ const value = echoed === void 0 ? void 0 : stripTags(echoed);
1457
+ if (value?.kind !== "bytes") throw new EraSdkError("malformed-reply", `${what} does not echo the request id (key ${key})`);
1458
+ if (expected !== void 0 && !equalBytes(value.value, expected)) throw new EraSdkError("request-id-mismatch", `${what} echoes a different request id — it answers another sign request, not this one`);
1459
+ return value.value;
1460
+ }
1461
+ /** A signature whose length is inside `[min, max]`, or a typed refusal. */
1462
+ function requireSignatureBytes(value, what, min, max) {
1463
+ const v = value === void 0 ? void 0 : stripTags(value);
1464
+ if (v?.kind !== "bytes") throw new EraSdkError("malformed-reply", `${what} is missing the signature (key 2)`);
1465
+ const length = v.value.length;
1466
+ if (length < min || length > max) throw new EraSdkError("malformed-reply", `${what} signature is ${length} bytes, expected ${min === max ? `${min}` : `${min}-${max}`}`);
1467
+ return v.value;
1468
+ }
1469
+ //#endregion
1470
+ export { utf8Encode as A, asMap as B, bytesToBigint as C, hexToBytes as D, equalBytes as E, parsePathComponents as F, cbMap as G, asUint as H, pathEquals as I, cbUint as J, cbTag as K, xfpToHex as L, keypath304 as M, normalizeXfp as N, u32be as O, parsePath as P, asArray as R, asciiDecode as S, concatBytes as T, cbArray as U, asText as V, cbBytes as W, stripTags as X, mapGet as Y, EraSdkError as Z, Ur as _, requireSignatureBytes as a, cborDecode as b, resolveRequestId as c, UrScanner as d, AnimatedUr as f, uuidStringify as g, normalizeRequestId as h, requireRequestIdEcho as i, formatPath as j, utf8Decode as k, toUr as l, UrLimits as m, makeSignRequest as n, requireUrType as o, DEFAULT_FRAGMENT_LENGTH as p, cbText as q, requireReplyMap as r, resolveContext as s, DEFAULT_ORIGIN as t, TypedUrScanner as u, parseUrString as v, bytesToHex as w, cborEncode as x, crc32 as y, asBytes as z };
1471
+
1472
+ //# sourceMappingURL=shared-B8Wc7ViU.js.map