@bsv/wallet-toolbox-client 2.1.25 → 2.1.26

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 (72) hide show
  1. package/out/src/mockchain/MockChainMigrations.d.ts.map +1 -1
  2. package/out/src/mockchain/MockChainStorage.js +3 -3
  3. package/out/src/mockchain/MockChainStorage.js.map +1 -1
  4. package/out/src/mockchain/MockMiner.js +1 -1
  5. package/out/src/mockchain/MockMiner.js.map +1 -1
  6. package/out/src/mockchain/MockServices.js +14 -13
  7. package/out/src/mockchain/MockServices.js.map +1 -1
  8. package/out/src/monitor/Monitor.js +8 -6
  9. package/out/src/monitor/Monitor.js.map +1 -1
  10. package/out/src/sdk/PrivilegedKeyManager.d.ts.map +1 -1
  11. package/out/src/sdk/PrivilegedKeyManager.js +6 -3
  12. package/out/src/sdk/PrivilegedKeyManager.js.map +1 -1
  13. package/out/src/sdk/WalletError.d.ts.map +1 -1
  14. package/out/src/sdk/WalletError.js +19 -18
  15. package/out/src/sdk/WalletError.js.map +1 -1
  16. package/out/src/sdk/WalletErrorFromJson.js +1 -1
  17. package/out/src/sdk/WalletErrorFromJson.js.map +1 -1
  18. package/out/src/sdk/WalletStorage.interfaces.d.ts +59 -59
  19. package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
  20. package/out/src/services/ServiceCollection.d.ts.map +1 -1
  21. package/out/src/services/ServiceCollection.js +3 -4
  22. package/out/src/services/ServiceCollection.js.map +1 -1
  23. package/out/src/services/Services.d.ts.map +1 -1
  24. package/out/src/services/Services.js +27 -25
  25. package/out/src/services/Services.js.map +1 -1
  26. package/out/src/storage/StorageIdb.d.ts.map +1 -1
  27. package/out/src/storage/StorageIdb.js +99 -94
  28. package/out/src/storage/StorageIdb.js.map +1 -1
  29. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  30. package/out/src/storage/StorageProvider.js +35 -31
  31. package/out/src/storage/StorageProvider.js.map +1 -1
  32. package/out/src/storage/StorageReader.js +7 -7
  33. package/out/src/storage/StorageReader.js.map +1 -1
  34. package/out/src/storage/StorageReaderWriter.d.ts +0 -1
  35. package/out/src/storage/StorageReaderWriter.d.ts.map +1 -1
  36. package/out/src/storage/StorageReaderWriter.js +0 -3
  37. package/out/src/storage/StorageReaderWriter.js.map +1 -1
  38. package/out/src/storage/StorageSyncReader.js +1 -1
  39. package/out/src/storage/StorageSyncReader.js.map +1 -1
  40. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  41. package/out/src/storage/WalletStorageManager.js +22 -21
  42. package/out/src/storage/WalletStorageManager.js.map +1 -1
  43. package/out/src/storage/index.client.d.ts +3 -0
  44. package/out/src/storage/index.client.d.ts.map +1 -1
  45. package/out/src/storage/index.client.js +3 -0
  46. package/out/src/storage/index.client.js.map +1 -1
  47. package/out/src/storage/portable/index.d.ts +55 -0
  48. package/out/src/storage/portable/index.d.ts.map +1 -0
  49. package/out/src/storage/portable/index.js +830 -0
  50. package/out/src/storage/portable/index.js.map +1 -0
  51. package/out/src/storage/storageProviderHelpers.js +2 -2
  52. package/out/src/storage/storageProviderHelpers.js.map +1 -1
  53. package/out/src/utility/ScriptTemplateBRC29.d.ts.map +1 -1
  54. package/out/src/utility/ScriptTemplateBRC29.js +3 -2
  55. package/out/src/utility/ScriptTemplateBRC29.js.map +1 -1
  56. package/out/src/utility/brc114ActionTimeLabels.js +1 -1
  57. package/out/src/utility/brc114ActionTimeLabels.js.map +1 -1
  58. package/out/src/utility/identityUtils.d.ts.map +1 -1
  59. package/out/src/utility/identityUtils.js +5 -5
  60. package/out/src/utility/identityUtils.js.map +1 -1
  61. package/out/src/utility/index.client.d.ts +1 -0
  62. package/out/src/utility/index.client.d.ts.map +1 -1
  63. package/out/src/utility/index.client.js +1 -0
  64. package/out/src/utility/index.client.js.map +1 -1
  65. package/out/src/utility/stampLog.js +3 -3
  66. package/out/src/utility/stampLog.js.map +1 -1
  67. package/out/src/utility/utilityHelpers.d.ts.map +1 -1
  68. package/out/src/utility/utilityHelpers.js +2 -2
  69. package/out/src/utility/utilityHelpers.js.map +1 -1
  70. package/out/src/wab-client/WABClient.d.ts +2 -2
  71. package/out/src/wab-client/WABClient.d.ts.map +1 -1
  72. package/package.json +1 -1
@@ -0,0 +1,830 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/triple-slash-reference */
3
+ /// <reference path="../../types/bsv-sdk-aesgcm.d.ts" />
4
+ /* eslint-enable @typescript-eslint/triple-slash-reference */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.exportBRC38 = exportBRC38;
7
+ exports.exportBRC38Json = exportBRC38Json;
8
+ exports.parseBRC38Json = parseBRC38Json;
9
+ exports.importBRC38 = importBRC38;
10
+ exports.exportBRC39 = exportBRC39;
11
+ exports.importBRC39 = importBRC39;
12
+ exports.encryptBRC39 = encryptBRC39;
13
+ exports.decryptBRC39 = decryptBRC39;
14
+ const sdk_1 = require("@bsv/sdk");
15
+ const AESGCM_1 = require("@bsv/sdk/primitives/AESGCM");
16
+ const hash_wasm_1 = require("hash-wasm");
17
+ const EntityBase_1 = require("../schema/entities/EntityBase");
18
+ const utilityHelpers_1 = require("../../utility/utilityHelpers");
19
+ const BRC38_TITLE = 'User Wallet Data Format';
20
+ const BRC39_MAGIC = [0x57, 0x44, 0x41, 0x54]; // WDAT
21
+ const BRC39_HEADER_LENGTH = 33;
22
+ const BRC39_TAG_LENGTH = 16;
23
+ const BRC39_DEFAULT_ITERATIONS = 7;
24
+ const BRC39_DEFAULT_MEMORY_KIB = 131072;
25
+ const BRC39_DEFAULT_PARALLELISM = 1;
26
+ const BRC39_HASH_LENGTH = 32;
27
+ const BRC39_SALT_LENGTH = 32;
28
+ const BRC39_NONCE_LENGTH = 32;
29
+ const tableNames = [
30
+ 'provenTxs',
31
+ 'provenTxReqs',
32
+ 'outputBaskets',
33
+ 'transactions',
34
+ 'commissions',
35
+ 'outputs',
36
+ 'outputTags',
37
+ 'outputTagMaps',
38
+ 'txLabels',
39
+ 'txLabelMaps',
40
+ 'certificates',
41
+ 'certificateFields',
42
+ 'syncStates'
43
+ ];
44
+ const SYNC_CHUNK_ENTITY_ORDER = [
45
+ 'provenTx',
46
+ 'outputBasket',
47
+ 'outputTag',
48
+ 'txLabel',
49
+ 'transaction',
50
+ 'output',
51
+ 'txLabelMap',
52
+ 'outputTagMap',
53
+ 'certificate',
54
+ 'certificateField',
55
+ 'commission',
56
+ 'provenTxReq'
57
+ ];
58
+ const binaryFieldsByKind = {
59
+ commission: ['lockingScript'],
60
+ output: ['lockingScript'],
61
+ provenTx: ['merklePath', 'rawTx'],
62
+ provenTxReq: ['rawTx', 'inputBEEF'],
63
+ transaction: ['inputBEEF', 'rawTx']
64
+ };
65
+ const jsonFieldsByKind = {
66
+ provenTxReq: ['history', 'notify'],
67
+ syncState: ['syncMap', 'errorLocal', 'errorOther']
68
+ };
69
+ const dateFieldsByKind = {
70
+ settings: ['created_at', 'updated_at'],
71
+ user: ['created_at', 'updated_at'],
72
+ provenTx: ['created_at', 'updated_at'],
73
+ provenTxReq: ['created_at', 'updated_at'],
74
+ outputBasket: ['created_at', 'updated_at'],
75
+ transaction: ['created_at', 'updated_at'],
76
+ commission: ['created_at', 'updated_at'],
77
+ output: ['created_at', 'updated_at'],
78
+ outputTag: ['created_at', 'updated_at'],
79
+ outputTagMap: ['created_at', 'updated_at'],
80
+ txLabel: ['created_at', 'updated_at'],
81
+ txLabelMap: ['created_at', 'updated_at'],
82
+ certificate: ['created_at', 'updated_at'],
83
+ certificateField: ['created_at', 'updated_at'],
84
+ syncState: ['created_at', 'updated_at', 'when']
85
+ };
86
+ async function exportBRC38(storage, identityKey) {
87
+ const sourceStorage = await storage.makeAvailable();
88
+ const user = (0, utilityHelpers_1.verifyTruthy)(await storage.findUserByIdentityKey(identityKey));
89
+ const userId = user.userId;
90
+ const transactions = await storage.findTransactions({ partial: { userId } });
91
+ const transactionIds = new Set(transactions.map(t => t.transactionId));
92
+ const transactionTxids = new Set(transactions.map(t => t.txid).filter((txid) => txid != null));
93
+ const provenTxReqs = (await storage.getProvenTxReqsForUser({ userId })).filter(r => transactionTxids.has(r.txid));
94
+ const provenTxIds = new Set();
95
+ for (const tx of transactions)
96
+ if (tx.provenTxId != null)
97
+ provenTxIds.add(tx.provenTxId);
98
+ for (const req of provenTxReqs)
99
+ if (req.provenTxId != null)
100
+ provenTxIds.add(req.provenTxId);
101
+ const provenTxs = [];
102
+ for (const provenTxId of Array.from(provenTxIds).sort(compareNumber)) {
103
+ const proven = (0, utilityHelpers_1.verifyOneOrNone)(await storage.findProvenTxs({ partial: { provenTxId } }));
104
+ if (proven != null)
105
+ provenTxs.push(proven);
106
+ }
107
+ const outputBaskets = await storage.findOutputBaskets({ partial: { userId } });
108
+ const commissions = await storage.findCommissions({ partial: { userId } });
109
+ const outputs = await storage.findOutputs({ partial: { userId } });
110
+ const outputTags = await storage.findOutputTags({ partial: { userId } });
111
+ const outputTagMaps = (await storage.getOutputTagMapsForUser({ userId }))
112
+ .filter(m => outputs.some(o => o.outputId === m.outputId));
113
+ const txLabels = await storage.findTxLabels({ partial: { userId } });
114
+ const txLabelMaps = (await storage.getTxLabelMapsForUser({ userId }))
115
+ .filter(m => transactionIds.has(m.transactionId));
116
+ const certificates = await storage.findCertificates({ partial: { userId } });
117
+ const certificateFields = await storage.findCertificateFields({ partial: { userId } });
118
+ const syncStates = await storage.findSyncStates({ partial: { userId } });
119
+ const data = {
120
+ brc: 38,
121
+ title: BRC38_TITLE,
122
+ formatVersion: 1,
123
+ exportedAt: isoDate(new Date()),
124
+ sourceStorage: portableRow('settings', sourceStorage),
125
+ user: portableRow('user', user),
126
+ tables: {
127
+ provenTxs: provenTxs.map(r => portableRow('provenTx', r)),
128
+ provenTxReqs: provenTxReqs.map(r => portableRow('provenTxReq', r)),
129
+ outputBaskets: outputBaskets.map(r => portableRow('outputBasket', r)),
130
+ transactions: transactions.map(r => portableRow('transaction', r)),
131
+ commissions: commissions.map(r => portableRow('commission', r)),
132
+ outputs: outputs.map(r => portableRow('output', r)),
133
+ outputTags: outputTags.map(r => portableRow('outputTag', r)),
134
+ outputTagMaps: outputTagMaps.map(r => portableRow('outputTagMap', r)),
135
+ txLabels: txLabels.map(r => portableRow('txLabel', r)),
136
+ txLabelMaps: txLabelMaps.map(r => portableRow('txLabelMap', r)),
137
+ certificates: certificates.map(r => {
138
+ const row = portableRow('certificate', r);
139
+ delete row.fields;
140
+ return row;
141
+ }),
142
+ certificateFields: certificateFields.map(r => portableRow('certificateField', r)),
143
+ syncStates: syncStates.map(r => portableRow('syncState', r))
144
+ }
145
+ };
146
+ sortBRC38Tables(data.tables);
147
+ validateBRC38(data);
148
+ return data;
149
+ }
150
+ async function exportBRC38Json(storage, identityKey) {
151
+ return canonicalize(await exportBRC38(storage, identityKey));
152
+ }
153
+ function parseBRC38Json(json) {
154
+ let data;
155
+ try {
156
+ data = JSON.parse(json);
157
+ }
158
+ catch (e) {
159
+ throw new Error(`Invalid BRC-38 JSON: ${e.message}`);
160
+ }
161
+ return validateBRC38(data);
162
+ }
163
+ async function importBRC38(storage, documentOrJson, options) {
164
+ const data = typeof documentOrJson === 'string' ? parseBRC38Json(documentOrJson) : validateBRC38(documentOrJson);
165
+ const targetSettings = await storage.makeAvailable();
166
+ const decoded = decodeBRC38(data);
167
+ if (decoded.sourceStorage.chain !== targetSettings.chain) {
168
+ throw new Error(`BRC-38 chain mismatch: payload is ${decoded.sourceStorage.chain}, target is ${targetSettings.chain}`);
169
+ }
170
+ if (options.mode === 'restore')
171
+ return await restoreBRC38(storage, decoded);
172
+ if (options.mode === 'merge')
173
+ return await mergeBRC38(storage, decoded, targetSettings);
174
+ throw new Error(`Unsupported BRC-38 import mode: ${String(options.mode)}`);
175
+ }
176
+ async function exportBRC39(storage, identityKey, password, options) {
177
+ return await encryptBRC39(await exportBRC38(storage, identityKey), password, options);
178
+ }
179
+ async function importBRC39(storage, bytes, password, options) {
180
+ return await importBRC38(storage, await decryptBRC39(bytes, password), options);
181
+ }
182
+ async function encryptBRC39(documentOrJson, password, options) {
183
+ var _a, _b, _c;
184
+ const data = typeof documentOrJson === 'string' ? parseBRC38Json(documentOrJson) : validateBRC38(documentOrJson);
185
+ const plaintext = new Uint8Array(sdk_1.Utils.toArray(canonicalize(data), 'utf8'));
186
+ const salt = new Uint8Array((0, sdk_1.Random)(BRC39_SALT_LENGTH));
187
+ const nonce = new Uint8Array((0, sdk_1.Random)(BRC39_NONCE_LENGTH));
188
+ const iterations = (_a = options === null || options === void 0 ? void 0 : options.iterations) !== null && _a !== void 0 ? _a : BRC39_DEFAULT_ITERATIONS;
189
+ const memoryKiB = (_b = options === null || options === void 0 ? void 0 : options.memoryKiB) !== null && _b !== void 0 ? _b : BRC39_DEFAULT_MEMORY_KIB;
190
+ const parallelism = (_c = options === null || options === void 0 ? void 0 : options.parallelism) !== null && _c !== void 0 ? _c : BRC39_DEFAULT_PARALLELISM;
191
+ validateKdfParams(iterations, memoryKiB, parallelism, BRC39_HASH_LENGTH);
192
+ validateExportKdfParams(iterations, memoryKiB);
193
+ const key = await deriveBRC39Key(password, salt, iterations, memoryKiB, parallelism);
194
+ const { result, authenticationTag } = (0, AESGCM_1.AESGCM)(plaintext, nonce, key);
195
+ const header = new Uint8Array(BRC39_HEADER_LENGTH + salt.length + nonce.length);
196
+ header.set(BRC39_MAGIC, 0);
197
+ header[4] = 1;
198
+ header[5] = 1;
199
+ header[6] = 38;
200
+ header[7] = 1;
201
+ header[8] = 0;
202
+ header[9] = salt.length;
203
+ header[10] = nonce.length;
204
+ writeUInt32BE(header, 11, iterations);
205
+ writeUInt32BE(header, 15, memoryKiB);
206
+ header[19] = parallelism;
207
+ header[20] = BRC39_HASH_LENGTH;
208
+ header.set(salt, BRC39_HEADER_LENGTH);
209
+ header.set(nonce, BRC39_HEADER_LENGTH + salt.length);
210
+ return Array.from(concatBytes(header, result, authenticationTag));
211
+ }
212
+ async function decryptBRC39(bytes, password) {
213
+ const file = new Uint8Array(bytes);
214
+ if (file.length < BRC39_HEADER_LENGTH + BRC39_TAG_LENGTH + 2)
215
+ throw new Error('Invalid BRC-39 file: too short');
216
+ for (let i = 0; i < BRC39_MAGIC.length; i++) {
217
+ if (file[i] !== BRC39_MAGIC[i])
218
+ throw new Error('Invalid BRC-39 file: bad magic');
219
+ }
220
+ if (file[4] !== 1)
221
+ throw new Error('Unsupported BRC-39 format version');
222
+ if (file[5] !== 1)
223
+ throw new Error('Unsupported BRC-39 protector type');
224
+ if (file[6] !== 38)
225
+ throw new Error('Unsupported BRC-39 inner format');
226
+ if (file[7] !== 1)
227
+ throw new Error('Unsupported BRC-39 KDF type');
228
+ if (file[8] !== 0)
229
+ throw new Error('Invalid BRC-39 flags');
230
+ const saltLength = file[9];
231
+ const nonceLength = file[10];
232
+ const iterations = readUInt32BE(file, 11);
233
+ const memoryKiB = readUInt32BE(file, 15);
234
+ const parallelism = file[19];
235
+ const hashLength = file[20];
236
+ for (let i = 21; i < BRC39_HEADER_LENGTH; i++) {
237
+ if (file[i] !== 0)
238
+ throw new Error('Invalid BRC-39 reserved bytes');
239
+ }
240
+ if (saltLength === 0)
241
+ throw new Error('Invalid BRC-39 salt length');
242
+ if (nonceLength === 0)
243
+ throw new Error('Invalid BRC-39 nonce length');
244
+ validateKdfParams(iterations, memoryKiB, parallelism, hashLength);
245
+ const payloadStart = BRC39_HEADER_LENGTH + saltLength + nonceLength;
246
+ if (file.length <= payloadStart + BRC39_TAG_LENGTH)
247
+ throw new Error('Invalid BRC-39 ciphertext');
248
+ const salt = file.slice(BRC39_HEADER_LENGTH, BRC39_HEADER_LENGTH + saltLength);
249
+ const nonce = file.slice(BRC39_HEADER_LENGTH + saltLength, payloadStart);
250
+ const ciphertext = file.slice(payloadStart, file.length - BRC39_TAG_LENGTH);
251
+ const tag = file.slice(file.length - BRC39_TAG_LENGTH);
252
+ const key = await deriveBRC39Key(password, salt, iterations, memoryKiB, parallelism);
253
+ const plaintext = (0, AESGCM_1.AESGCMDecrypt)(ciphertext, nonce, tag, key);
254
+ if (plaintext == null)
255
+ throw new Error('BRC-39 authentication failed');
256
+ return parseBRC38Json(sdk_1.Utils.toUTF8(Array.from(plaintext)));
257
+ }
258
+ function validateBRC38(value) {
259
+ rejectNulls(value, 'document');
260
+ if (!isObject(value))
261
+ throw new Error('BRC-38 document must be an object');
262
+ const data = value;
263
+ if (data.brc !== 38)
264
+ throw new Error('BRC-38 document brc must equal 38');
265
+ if (data.title !== BRC38_TITLE)
266
+ throw new Error('BRC-38 title must equal User Wallet Data Format');
267
+ if (data.formatVersion !== 1)
268
+ throw new Error('BRC-38 formatVersion must equal 1');
269
+ assertIsoDate(data.exportedAt, 'exportedAt');
270
+ if (!isObject(data.sourceStorage))
271
+ throw new Error('BRC-38 sourceStorage must be an object');
272
+ if (!isObject(data.user))
273
+ throw new Error('BRC-38 user must be an object');
274
+ if (!isObject(data.tables))
275
+ throw new Error('BRC-38 tables must be an object');
276
+ for (const name of tableNames) {
277
+ if (!Array.isArray(data.tables[name]))
278
+ throw new Error(`BRC-38 tables.${name} must be an array`);
279
+ }
280
+ validatePortableRows('settings', [data.sourceStorage], 'sourceStorage');
281
+ validatePortableRows('user', [data.user], 'user');
282
+ validatePortableRows('provenTx', data.tables.provenTxs, 'provenTxs');
283
+ validatePortableRows('provenTxReq', data.tables.provenTxReqs, 'provenTxReqs');
284
+ validatePortableRows('outputBasket', data.tables.outputBaskets, 'outputBaskets');
285
+ validatePortableRows('transaction', data.tables.transactions, 'transactions');
286
+ validatePortableRows('commission', data.tables.commissions, 'commissions');
287
+ validatePortableRows('output', data.tables.outputs, 'outputs');
288
+ validatePortableRows('outputTag', data.tables.outputTags, 'outputTags');
289
+ validatePortableRows('outputTagMap', data.tables.outputTagMaps, 'outputTagMaps');
290
+ validatePortableRows('txLabel', data.tables.txLabels, 'txLabels');
291
+ validatePortableRows('txLabelMap', data.tables.txLabelMaps, 'txLabelMaps');
292
+ validatePortableRows('certificate', data.tables.certificates, 'certificates');
293
+ validatePortableRows('certificateField', data.tables.certificateFields, 'certificateFields');
294
+ validatePortableRows('syncState', data.tables.syncStates, 'syncStates');
295
+ validateRelationships(data);
296
+ return data;
297
+ }
298
+ function decodeBRC38(data) {
299
+ return {
300
+ sourceStorage: fromPortableRow('settings', data.sourceStorage),
301
+ user: fromPortableRow('user', data.user),
302
+ provenTxs: data.tables.provenTxs.map(r => fromPortableRow('provenTx', r)),
303
+ provenTxReqs: data.tables.provenTxReqs.map(r => fromPortableRow('provenTxReq', r)),
304
+ outputBaskets: data.tables.outputBaskets.map(r => fromPortableRow('outputBasket', r)),
305
+ transactions: data.tables.transactions.map(r => fromPortableRow('transaction', r)),
306
+ commissions: data.tables.commissions.map(r => fromPortableRow('commission', r)),
307
+ outputs: data.tables.outputs.map(r => fromPortableRow('output', r)),
308
+ outputTags: data.tables.outputTags.map(r => fromPortableRow('outputTag', r)),
309
+ outputTagMaps: data.tables.outputTagMaps.map(r => fromPortableRow('outputTagMap', r)),
310
+ txLabels: data.tables.txLabels.map(r => fromPortableRow('txLabel', r)),
311
+ txLabelMaps: data.tables.txLabelMaps.map(r => fromPortableRow('txLabelMap', r)),
312
+ certificates: data.tables.certificates.map(r => fromPortableRow('certificate', r)),
313
+ certificateFields: data.tables.certificateFields.map(r => fromPortableRow('certificateField', r)),
314
+ syncStates: data.tables.syncStates.map(r => fromPortableRow('syncState', r))
315
+ };
316
+ }
317
+ async function restoreBRC38(storage, data) {
318
+ await assertRestoreTargetEmpty(storage);
319
+ await storage.transaction(async (trx) => {
320
+ await storage.insertUser({ ...data.user }, trx);
321
+ for (const row of data.provenTxs)
322
+ await storage.insertProvenTx({ ...row }, trx);
323
+ for (const row of data.outputBaskets)
324
+ await storage.insertOutputBasket({ ...row }, trx);
325
+ for (const row of data.outputTags)
326
+ await storage.insertOutputTag({ ...row }, trx);
327
+ for (const row of data.txLabels)
328
+ await storage.insertTxLabel({ ...row }, trx);
329
+ for (const row of data.transactions)
330
+ await storage.insertTransaction({ ...row }, trx);
331
+ for (const row of data.outputs)
332
+ await storage.insertOutput({ ...row }, trx);
333
+ for (const row of data.txLabelMaps)
334
+ await storage.insertTxLabelMap({ ...row }, trx);
335
+ for (const row of data.outputTagMaps)
336
+ await storage.insertOutputTagMap({ ...row }, trx);
337
+ for (const row of data.certificates)
338
+ await storage.insertCertificate({ ...row }, trx);
339
+ for (const row of data.certificateFields)
340
+ await storage.insertCertificateField({ ...row }, trx);
341
+ for (const row of data.commissions)
342
+ await storage.insertCommission({ ...row }, trx);
343
+ for (const row of data.provenTxReqs)
344
+ await storage.insertProvenTxReq({ ...row }, trx);
345
+ for (const row of data.syncStates)
346
+ await storage.insertSyncState({ ...row }, trx);
347
+ });
348
+ return {
349
+ mode: 'restore',
350
+ identityKey: data.user.identityKey,
351
+ userId: data.user.userId,
352
+ inserts: 1 + countDecodedRows(data),
353
+ updates: 0
354
+ };
355
+ }
356
+ async function mergeBRC38(storage, data, targetSettings) {
357
+ const { user: targetUser } = await storage.findOrInsertUser(data.user.identityKey);
358
+ await storage.findOrInsertSyncStateAuth({ identityKey: data.user.identityKey, userId: targetUser.userId }, data.sourceStorage.storageIdentityKey, data.sourceStorage.storageName);
359
+ const chunk = {
360
+ fromStorageIdentityKey: data.sourceStorage.storageIdentityKey,
361
+ toStorageIdentityKey: targetSettings.storageIdentityKey,
362
+ userIdentityKey: data.user.identityKey,
363
+ user: { ...data.user, activeStorage: targetUser.activeStorage },
364
+ provenTxs: data.provenTxs.map(r => ({ ...r })),
365
+ outputBaskets: data.outputBaskets.map(r => ({ ...r })),
366
+ outputTags: data.outputTags.map(r => ({ ...r })),
367
+ txLabels: data.txLabels.map(r => ({ ...r })),
368
+ transactions: data.transactions.map(r => ({ ...r })),
369
+ outputs: data.outputs.map(r => ({ ...r })),
370
+ txLabelMaps: data.txLabelMaps.map(r => ({ ...r })),
371
+ outputTagMaps: data.outputTagMaps.map(r => ({ ...r })),
372
+ certificates: data.certificates.map(r => ({ ...r })),
373
+ certificateFields: data.certificateFields.map(r => ({ ...r })),
374
+ commissions: data.commissions.map(r => ({ ...r })),
375
+ provenTxReqs: data.provenTxReqs.map(r => ({ ...r }))
376
+ };
377
+ const args = {
378
+ fromStorageIdentityKey: chunk.fromStorageIdentityKey,
379
+ toStorageIdentityKey: chunk.toStorageIdentityKey,
380
+ identityKey: data.user.identityKey,
381
+ maxRoughSize: Number.MAX_SAFE_INTEGER,
382
+ maxItems: Number.MAX_SAFE_INTEGER,
383
+ offsets: SYNC_CHUNK_ENTITY_ORDER.map(name => ({ name, offset: 0 }))
384
+ };
385
+ const first = await storage.processSyncChunk(args, chunk);
386
+ const done = await storage.processSyncChunk(args, {
387
+ fromStorageIdentityKey: chunk.fromStorageIdentityKey,
388
+ toStorageIdentityKey: chunk.toStorageIdentityKey,
389
+ userIdentityKey: data.user.identityKey,
390
+ provenTxs: [],
391
+ outputBaskets: [],
392
+ outputTags: [],
393
+ txLabels: [],
394
+ transactions: [],
395
+ outputs: [],
396
+ txLabelMaps: [],
397
+ outputTagMaps: [],
398
+ certificates: [],
399
+ certificateFields: [],
400
+ commissions: [],
401
+ provenTxReqs: []
402
+ });
403
+ const currentSyncState = (0, utilityHelpers_1.verifyOne)(await storage.findSyncStates({
404
+ partial: {
405
+ userId: targetUser.userId,
406
+ storageIdentityKey: data.sourceStorage.storageIdentityKey,
407
+ storageName: data.sourceStorage.storageName
408
+ }
409
+ }));
410
+ const importMap = normalizeSyncMap(JSON.parse(currentSyncState.syncMap));
411
+ const syncStateResult = await mergeImportedSyncStates(storage, data.syncStates, targetUser.userId, importMap, data.sourceStorage);
412
+ return {
413
+ mode: 'merge',
414
+ identityKey: data.user.identityKey,
415
+ userId: targetUser.userId,
416
+ inserts: first.inserts + done.inserts + syncStateResult.inserts,
417
+ updates: first.updates + done.updates + syncStateResult.updates
418
+ };
419
+ }
420
+ async function mergeImportedSyncStates(storage, syncStates, userId, importMap, sourceStorage) {
421
+ let inserts = 0;
422
+ let updates = 0;
423
+ for (const source of syncStates) {
424
+ const row = {
425
+ ...source,
426
+ userId,
427
+ syncMap: JSON.stringify(remapSyncMap(JSON.parse(source.syncMap), importMap))
428
+ };
429
+ const existing = (0, utilityHelpers_1.verifyOneOrNone)(await storage.findSyncStates({
430
+ partial: {
431
+ userId,
432
+ storageIdentityKey: row.storageIdentityKey,
433
+ storageName: row.storageName
434
+ }
435
+ }));
436
+ if (existing == null) {
437
+ row.syncStateId = 0;
438
+ await storage.insertSyncState(row);
439
+ inserts++;
440
+ }
441
+ else {
442
+ row.syncStateId = existing.syncStateId;
443
+ if (row.storageIdentityKey === sourceStorage.storageIdentityKey &&
444
+ row.storageName === sourceStorage.storageName) {
445
+ row.syncMap = existing.syncMap;
446
+ }
447
+ await storage.updateSyncState(existing.syncStateId, row);
448
+ updates++;
449
+ }
450
+ }
451
+ return { inserts, updates };
452
+ }
453
+ function remapSyncMap(source, importMap) {
454
+ const copy = normalizeSyncMap(source);
455
+ remapEntityIdMap(copy.provenTx.idMap, importMap.provenTx.idMap);
456
+ remapEntityIdMap(copy.outputBasket.idMap, importMap.outputBasket.idMap);
457
+ remapEntityIdMap(copy.transaction.idMap, importMap.transaction.idMap);
458
+ remapEntityIdMap(copy.provenTxReq.idMap, importMap.provenTxReq.idMap);
459
+ remapEntityIdMap(copy.txLabel.idMap, importMap.txLabel.idMap);
460
+ remapEntityIdMap(copy.output.idMap, importMap.output.idMap);
461
+ remapEntityIdMap(copy.outputTag.idMap, importMap.outputTag.idMap);
462
+ remapEntityIdMap(copy.certificate.idMap, importMap.certificate.idMap);
463
+ remapEntityIdMap(copy.commission.idMap, importMap.commission.idMap);
464
+ return copy;
465
+ }
466
+ function normalizeSyncMap(source) {
467
+ const normalized = (0, EntityBase_1.createSyncMap)();
468
+ if (!isObject(source))
469
+ return normalized;
470
+ for (const key of Object.keys(normalized)) {
471
+ const incoming = source[key];
472
+ if (!isObject(incoming))
473
+ continue;
474
+ const target = normalized[key];
475
+ if (typeof incoming.entityName === 'string')
476
+ target.entityName = incoming.entityName;
477
+ if (Number.isInteger(incoming.count))
478
+ target.count = incoming.count;
479
+ if (isObject(incoming.idMap)) {
480
+ target.idMap = {};
481
+ for (const [remoteId, localId] of Object.entries(incoming.idMap)) {
482
+ const parsedRemoteId = Number(remoteId);
483
+ if (Number.isInteger(parsedRemoteId) && Number.isInteger(localId)) {
484
+ target.idMap[parsedRemoteId] = localId;
485
+ }
486
+ }
487
+ }
488
+ if (typeof incoming.maxUpdated_at === 'string') {
489
+ const maxUpdatedAt = new Date(incoming.maxUpdated_at);
490
+ if (!Number.isNaN(maxUpdatedAt.getTime()))
491
+ target.maxUpdated_at = maxUpdatedAt;
492
+ }
493
+ else if (incoming.maxUpdated_at instanceof Date) {
494
+ target.maxUpdated_at = incoming.maxUpdated_at;
495
+ }
496
+ }
497
+ return normalized;
498
+ }
499
+ function remapEntityIdMap(idMap, importIdMap) {
500
+ for (const key of Object.keys(idMap)) {
501
+ const targetId = importIdMap[idMap[Number(key)]];
502
+ if (targetId != null)
503
+ idMap[Number(key)] = targetId;
504
+ }
505
+ }
506
+ async function assertRestoreTargetEmpty(storage) {
507
+ const counts = await Promise.all([
508
+ storage.countUsers({ partial: {} }),
509
+ storage.countProvenTxs({ partial: {} }),
510
+ storage.countProvenTxReqs({ partial: {} }),
511
+ storage.countOutputBaskets({ partial: {} }),
512
+ storage.countTransactions({ partial: {} }),
513
+ storage.countCommissions({ partial: {} }),
514
+ storage.countOutputs({ partial: {} }),
515
+ storage.countOutputTags({ partial: {} }),
516
+ storage.countOutputTagMaps({ partial: {} }),
517
+ storage.countTxLabels({ partial: {} }),
518
+ storage.countTxLabelMaps({ partial: {} }),
519
+ storage.countCertificates({ partial: {} }),
520
+ storage.countCertificateFields({ partial: {} }),
521
+ storage.countSyncStates({ partial: {} }),
522
+ storage.countMonitorEvents({ partial: {} })
523
+ ]);
524
+ if (counts.some(c => c > 0))
525
+ throw new Error('BRC-38 restore requires an empty target storage except settings');
526
+ }
527
+ function countDecodedRows(data) {
528
+ return data.provenTxs.length + data.provenTxReqs.length + data.outputBaskets.length + data.transactions.length +
529
+ data.commissions.length + data.outputs.length + data.outputTags.length + data.outputTagMaps.length +
530
+ data.txLabels.length + data.txLabelMaps.length + data.certificates.length + data.certificateFields.length +
531
+ data.syncStates.length;
532
+ }
533
+ function validateRelationships(data) {
534
+ const userId = requireNumber(data.user.userId, 'user.userId');
535
+ const txIds = ids(data.tables.transactions, 'transactionId', 'transactions');
536
+ const txidValues = new Set(data.tables.transactions.map(t => t.txid).filter((v) => typeof v === 'string'));
537
+ const provenTxIds = ids(data.tables.provenTxs, 'provenTxId', 'provenTxs');
538
+ const basketIds = ids(data.tables.outputBaskets, 'basketId', 'outputBaskets');
539
+ const outputIds = ids(data.tables.outputs, 'outputId', 'outputs');
540
+ const outputTagIds = ids(data.tables.outputTags, 'outputTagId', 'outputTags');
541
+ const txLabelIds = ids(data.tables.txLabels, 'txLabelId', 'txLabels');
542
+ const certificateIds = ids(data.tables.certificates, 'certificateId', 'certificates');
543
+ for (const row of data.tables.transactions) {
544
+ requireUserId(row, userId, 'transactions');
545
+ if (row.provenTxId != null && !provenTxIds.has(requireNumber(row.provenTxId, 'transaction.provenTxId'))) {
546
+ throw new Error('BRC-38 transaction.provenTxId does not reference an exported provenTx');
547
+ }
548
+ }
549
+ for (const row of data.tables.outputBaskets)
550
+ requireUserId(row, userId, 'outputBaskets');
551
+ for (const row of data.tables.outputTags)
552
+ requireUserId(row, userId, 'outputTags');
553
+ for (const row of data.tables.txLabels)
554
+ requireUserId(row, userId, 'txLabels');
555
+ for (const row of data.tables.certificates)
556
+ requireUserId(row, userId, 'certificates');
557
+ for (const row of data.tables.syncStates)
558
+ requireUserId(row, userId, 'syncStates');
559
+ for (const row of data.tables.outputs) {
560
+ requireUserId(row, userId, 'outputs');
561
+ if (!txIds.has(requireNumber(row.transactionId, 'output.transactionId'))) {
562
+ throw new Error('BRC-38 output.transactionId does not reference an exported transaction');
563
+ }
564
+ if (row.basketId != null && !basketIds.has(requireNumber(row.basketId, 'output.basketId'))) {
565
+ throw new Error('BRC-38 output.basketId does not reference an exported output basket');
566
+ }
567
+ if (row.spentBy != null && !txIds.has(requireNumber(row.spentBy, 'output.spentBy'))) {
568
+ throw new Error('BRC-38 output.spentBy does not reference an exported transaction');
569
+ }
570
+ }
571
+ for (const row of data.tables.commissions) {
572
+ requireUserId(row, userId, 'commissions');
573
+ if (!txIds.has(requireNumber(row.transactionId, 'commission.transactionId'))) {
574
+ throw new Error('BRC-38 commission.transactionId does not reference an exported transaction');
575
+ }
576
+ }
577
+ for (const row of data.tables.txLabelMaps) {
578
+ if (!txIds.has(requireNumber(row.transactionId, 'txLabelMap.transactionId'))) {
579
+ throw new Error('BRC-38 txLabelMap.transactionId does not reference an exported transaction');
580
+ }
581
+ if (!txLabelIds.has(requireNumber(row.txLabelId, 'txLabelMap.txLabelId'))) {
582
+ throw new Error('BRC-38 txLabelMap.txLabelId does not reference an exported transaction label');
583
+ }
584
+ }
585
+ for (const row of data.tables.outputTagMaps) {
586
+ if (!outputIds.has(requireNumber(row.outputId, 'outputTagMap.outputId'))) {
587
+ throw new Error('BRC-38 outputTagMap.outputId does not reference an exported output');
588
+ }
589
+ if (!outputTagIds.has(requireNumber(row.outputTagId, 'outputTagMap.outputTagId'))) {
590
+ throw new Error('BRC-38 outputTagMap.outputTagId does not reference an exported output tag');
591
+ }
592
+ }
593
+ for (const row of data.tables.certificateFields) {
594
+ requireUserId(row, userId, 'certificateFields');
595
+ if (!certificateIds.has(requireNumber(row.certificateId, 'certificateField.certificateId'))) {
596
+ throw new Error('BRC-38 certificateField.certificateId does not reference an exported certificate');
597
+ }
598
+ }
599
+ for (const row of data.tables.provenTxReqs) {
600
+ if (!txidValues.has(requireString(row.txid, 'provenTxReq.txid'))) {
601
+ throw new Error('BRC-38 provenTxReq.txid does not match an exported transaction');
602
+ }
603
+ if (row.provenTxId != null && !provenTxIds.has(requireNumber(row.provenTxId, 'provenTxReq.provenTxId'))) {
604
+ throw new Error('BRC-38 provenTxReq.provenTxId does not reference an exported provenTx');
605
+ }
606
+ }
607
+ }
608
+ function validatePortableRows(kind, rows, path) {
609
+ var _a, _b, _c;
610
+ const dateFields = new Set((_a = dateFieldsByKind[kind]) !== null && _a !== void 0 ? _a : []);
611
+ const binaryFields = new Set((_b = binaryFieldsByKind[kind]) !== null && _b !== void 0 ? _b : []);
612
+ const jsonFields = new Set((_c = jsonFieldsByKind[kind]) !== null && _c !== void 0 ? _c : []);
613
+ for (const [index, row] of rows.entries()) {
614
+ if (!isObject(row))
615
+ throw new Error(`BRC-38 ${path}[${index}] must be an object`);
616
+ for (const field of dateFields) {
617
+ if (field in row)
618
+ assertIsoDate(row[field], `${path}[${index}].${field}`);
619
+ }
620
+ for (const field of binaryFields) {
621
+ if (field in row)
622
+ assertBase64(row[field], `${path}[${index}].${field}`);
623
+ }
624
+ for (const field of jsonFields) {
625
+ if (field in row && !isObject(row[field]))
626
+ throw new Error(`BRC-38 ${path}[${index}].${field} must be an object`);
627
+ }
628
+ }
629
+ }
630
+ function portableRow(kind, row) {
631
+ var _a, _b;
632
+ const out = {};
633
+ const binaryFields = new Set((_a = binaryFieldsByKind[kind]) !== null && _a !== void 0 ? _a : []);
634
+ const jsonFields = new Set((_b = jsonFieldsByKind[kind]) !== null && _b !== void 0 ? _b : []);
635
+ for (const [key, value] of Object.entries(row)) {
636
+ if (value == null)
637
+ continue;
638
+ if (key === 'logger')
639
+ continue;
640
+ if (binaryFields.has(key)) {
641
+ out[key] = sdk_1.Utils.toBase64(value);
642
+ }
643
+ else if (jsonFields.has(key)) {
644
+ out[key] = typeof value === 'string' ? JSON.parse(value) : value;
645
+ }
646
+ else if (value instanceof Date) {
647
+ out[key] = isoDate(value);
648
+ }
649
+ else {
650
+ out[key] = value;
651
+ }
652
+ }
653
+ return out;
654
+ }
655
+ function fromPortableRow(kind, row) {
656
+ var _a, _b, _c;
657
+ const out = {};
658
+ const dateFields = new Set((_a = dateFieldsByKind[kind]) !== null && _a !== void 0 ? _a : []);
659
+ const binaryFields = new Set((_b = binaryFieldsByKind[kind]) !== null && _b !== void 0 ? _b : []);
660
+ const jsonFields = new Set((_c = jsonFieldsByKind[kind]) !== null && _c !== void 0 ? _c : []);
661
+ for (const [key, value] of Object.entries(row)) {
662
+ if (dateFields.has(key))
663
+ out[key] = new Date(value);
664
+ else if (binaryFields.has(key))
665
+ out[key] = sdk_1.Utils.toArray(value, 'base64');
666
+ else if (jsonFields.has(key))
667
+ out[key] = JSON.stringify(value);
668
+ else
669
+ out[key] = value;
670
+ }
671
+ return out;
672
+ }
673
+ function sortBRC38Tables(tables) {
674
+ tables.provenTxs.sort(byNumber('provenTxId'));
675
+ tables.provenTxReqs.sort(byNumber('provenTxReqId'));
676
+ tables.outputBaskets.sort(byNumber('basketId'));
677
+ tables.transactions.sort(byNumber('transactionId'));
678
+ tables.commissions.sort(byNumber('commissionId'));
679
+ tables.outputs.sort(byNumber('outputId'));
680
+ tables.outputTags.sort(byNumber('outputTagId'));
681
+ tables.outputTagMaps.sort(byNumber('outputId', 'outputTagId'));
682
+ tables.txLabels.sort(byNumber('txLabelId'));
683
+ tables.txLabelMaps.sort(byNumber('transactionId', 'txLabelId'));
684
+ tables.certificates.sort(byNumber('certificateId'));
685
+ tables.certificateFields.sort((a, b) => {
686
+ const certificateIdOrder = requireNumber(a.certificateId, 'certificateId') - requireNumber(b.certificateId, 'certificateId');
687
+ if (certificateIdOrder !== 0)
688
+ return certificateIdOrder;
689
+ return requireString(a.fieldName, 'fieldName').localeCompare(requireString(b.fieldName, 'fieldName'));
690
+ });
691
+ tables.syncStates.sort(byNumber('syncStateId'));
692
+ }
693
+ function byNumber(field, secondField) {
694
+ return (a, b) => {
695
+ const first = requireNumber(a[field], field) - requireNumber(b[field], field);
696
+ if (first !== 0 || secondField == null)
697
+ return first;
698
+ return requireNumber(a[secondField], secondField) - requireNumber(b[secondField], secondField);
699
+ };
700
+ }
701
+ function ids(rows, field, label) {
702
+ const set = new Set();
703
+ for (const row of rows) {
704
+ const id = requireNumber(row[field], `${label}.${field}`);
705
+ if (set.has(id))
706
+ throw new Error(`BRC-38 duplicate ${label}.${field}: ${id}`);
707
+ set.add(id);
708
+ }
709
+ return set;
710
+ }
711
+ function requireUserId(row, userId, label) {
712
+ if (requireNumber(row.userId, `${label}.userId`) !== userId)
713
+ throw new Error(`BRC-38 ${label}.userId does not match user.userId`);
714
+ }
715
+ function requireNumber(value, path) {
716
+ if (!Number.isInteger(value))
717
+ throw new Error(`BRC-38 ${path} must be an integer`);
718
+ return value;
719
+ }
720
+ function requireString(value, path) {
721
+ if (typeof value !== 'string')
722
+ throw new Error(`BRC-38 ${path} must be a string`);
723
+ return value;
724
+ }
725
+ function assertIsoDate(value, path) {
726
+ if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) {
727
+ throw new Error(`BRC-38 ${path} must be a UTC ISO timestamp`);
728
+ }
729
+ const date = new Date(value);
730
+ if (Number.isNaN(date.getTime()) || date.toISOString() !== value)
731
+ throw new Error(`BRC-38 ${path} is invalid`);
732
+ }
733
+ function assertBase64(value, path) {
734
+ if (typeof value !== 'string' || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
735
+ throw new Error(`BRC-38 ${path} must be padded base64`);
736
+ }
737
+ }
738
+ function rejectNulls(value, path) {
739
+ if (value === null)
740
+ throw new Error(`BRC-38 ${path} must omit null values`);
741
+ if (Array.isArray(value)) {
742
+ for (let i = 0; i < value.length; i++)
743
+ rejectNulls(value[i], `${path}[${i}]`);
744
+ }
745
+ else if (isObject(value)) {
746
+ for (const [key, child] of Object.entries(value))
747
+ rejectNulls(child, `${path}.${key}`);
748
+ }
749
+ }
750
+ function canonicalize(value) {
751
+ if (value === null || value === undefined)
752
+ throw new Error('Cannot canonicalize null or undefined');
753
+ if (typeof value === 'string')
754
+ return JSON.stringify(value);
755
+ if (typeof value === 'number') {
756
+ if (!Number.isFinite(value))
757
+ throw new Error('Cannot canonicalize non-finite number');
758
+ return JSON.stringify(value);
759
+ }
760
+ if (typeof value === 'boolean')
761
+ return value ? 'true' : 'false';
762
+ if (Array.isArray(value))
763
+ return `[${value.map(canonicalize).join(',')}]`;
764
+ if (isObject(value)) {
765
+ return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonicalize(value[key])}`).join(',')}}`;
766
+ }
767
+ throw new Error(`Unsupported JSON value type: ${typeof value}`);
768
+ }
769
+ function isoDate(date) {
770
+ return date.toISOString();
771
+ }
772
+ function isObject(value) {
773
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
774
+ }
775
+ function compareNumber(a, b) {
776
+ return a - b;
777
+ }
778
+ function concatBytes(...arrays) {
779
+ const total = arrays.reduce((sum, a) => sum + a.length, 0);
780
+ const out = new Uint8Array(total);
781
+ let offset = 0;
782
+ for (const array of arrays) {
783
+ out.set(array, offset);
784
+ offset += array.length;
785
+ }
786
+ return out;
787
+ }
788
+ async function deriveBRC39Key(password, salt, iterations, memoryKiB, parallelism) {
789
+ const normalized = password.normalize('NFC');
790
+ const hash = await (0, hash_wasm_1.argon2id)({
791
+ password: new Uint8Array(sdk_1.Utils.toArray(normalized, 'utf8')),
792
+ salt,
793
+ iterations,
794
+ memorySize: memoryKiB,
795
+ parallelism,
796
+ hashLength: BRC39_HASH_LENGTH,
797
+ outputType: 'binary'
798
+ });
799
+ return new Uint8Array(hash);
800
+ }
801
+ function validateKdfParams(iterations, memoryKiB, parallelism, hashLength) {
802
+ if (!Number.isInteger(iterations) || iterations <= 0)
803
+ throw new Error('Invalid BRC-39 Argon2id iterations');
804
+ if (!Number.isInteger(memoryKiB) || memoryKiB <= 0)
805
+ throw new Error('Invalid BRC-39 Argon2id memoryKiB');
806
+ if (!Number.isInteger(parallelism) || parallelism <= 0 || parallelism > 255)
807
+ throw new Error('Invalid BRC-39 Argon2id parallelism');
808
+ if (hashLength !== BRC39_HASH_LENGTH)
809
+ throw new Error('Invalid BRC-39 Argon2id hashLength');
810
+ }
811
+ function validateExportKdfParams(iterations, memoryKiB) {
812
+ if (iterations < BRC39_DEFAULT_ITERATIONS) {
813
+ throw new Error('BRC-39 export iterations must not be weaker than the canonical default');
814
+ }
815
+ if (memoryKiB < BRC39_DEFAULT_MEMORY_KIB) {
816
+ throw new Error('BRC-39 export memoryKiB must not be weaker than the canonical default');
817
+ }
818
+ }
819
+ function writeUInt32BE(target, offset, value) {
820
+ if (!Number.isInteger(value) || value < 0 || value > 0xffffffff)
821
+ throw new Error('BRC-39 integer out of range');
822
+ target[offset] = (value >>> 24) & 0xff;
823
+ target[offset + 1] = (value >>> 16) & 0xff;
824
+ target[offset + 2] = (value >>> 8) & 0xff;
825
+ target[offset + 3] = value & 0xff;
826
+ }
827
+ function readUInt32BE(source, offset) {
828
+ return ((source[offset] << 24) >>> 0) + (source[offset + 1] << 16) + (source[offset + 2] << 8) + source[offset + 3];
829
+ }
830
+ //# sourceMappingURL=index.js.map