@lukso/transaction-decoder 1.0.1-dev.0f1bea5

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 (110) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +486 -0
  3. package/dist/browser.cjs +6912 -0
  4. package/dist/browser.cjs.map +1 -0
  5. package/dist/browser.d.cts +6 -0
  6. package/dist/browser.d.ts +6 -0
  7. package/dist/browser.js +131 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/cdn/transaction-decoder.global.js +296 -0
  10. package/dist/cdn/transaction-decoder.global.js.map +1 -0
  11. package/dist/chunk-GGBHTWJL.js +437 -0
  12. package/dist/chunk-GGBHTWJL.js.map +1 -0
  13. package/dist/chunk-GXZOF3QY.js +839 -0
  14. package/dist/chunk-GXZOF3QY.js.map +1 -0
  15. package/dist/chunk-LJ6ES5XF.js +776 -0
  16. package/dist/chunk-LJ6ES5XF.js.map +1 -0
  17. package/dist/chunk-XVHJWV5U.js +4925 -0
  18. package/dist/chunk-XVHJWV5U.js.map +1 -0
  19. package/dist/data.cjs +5518 -0
  20. package/dist/data.cjs.map +1 -0
  21. package/dist/data.d.cts +43 -0
  22. package/dist/data.d.ts +43 -0
  23. package/dist/data.js +55 -0
  24. package/dist/data.js.map +1 -0
  25. package/dist/index-BzXh7poJ.d.cts +524 -0
  26. package/dist/index-BzXh7poJ.d.ts +524 -0
  27. package/dist/index.cjs +6912 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +756 -0
  30. package/dist/index.d.ts +756 -0
  31. package/dist/index.js +131 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/server.cjs +5644 -0
  34. package/dist/server.cjs.map +1 -0
  35. package/dist/server.d.cts +217 -0
  36. package/dist/server.d.ts +217 -0
  37. package/dist/server.js +644 -0
  38. package/dist/server.js.map +1 -0
  39. package/dist/utils-CBAkjQh3.d.cts +108 -0
  40. package/dist/utils-xT9-km0r.d.ts +108 -0
  41. package/package.json +101 -0
  42. package/src/browser.ts +13 -0
  43. package/src/client/resolveAddresses.ts +157 -0
  44. package/src/core/addressCollector.ts +153 -0
  45. package/src/core/addressResolver.ts +135 -0
  46. package/src/core/dataModel.ts +888 -0
  47. package/src/core/instance.ts +33 -0
  48. package/src/core/integrateDecoder.ts +325 -0
  49. package/src/data.ts +70 -0
  50. package/src/decoder/GENERATOR_PROPOSAL.md +182 -0
  51. package/src/decoder/THREE_PHASE_EXAMPLE.md +108 -0
  52. package/src/decoder/aggregation.ts +218 -0
  53. package/src/decoder/browserCache.ts +237 -0
  54. package/src/decoder/cache/README.md +126 -0
  55. package/src/decoder/cache/index.ts +44 -0
  56. package/src/decoder/cache.ts +139 -0
  57. package/src/decoder/constants.ts +125 -0
  58. package/src/decoder/decodeTransaction.ts +292 -0
  59. package/src/decoder/errors.ts +95 -0
  60. package/src/decoder/events.ts +192 -0
  61. package/src/decoder/functionSignature.ts +344 -0
  62. package/src/decoder/getDataFromExternalSources.ts +248 -0
  63. package/src/decoder/graphqlWS.ts +22 -0
  64. package/src/decoder/interfaces.ts +185 -0
  65. package/src/decoder/keyValue.ts +5 -0
  66. package/src/decoder/kvCache.ts +241 -0
  67. package/src/decoder/lruCache.ts +184 -0
  68. package/src/decoder/lsp7Mint.test.ts +179 -0
  69. package/src/decoder/lsp7TransferBatch.test.ts +105 -0
  70. package/src/decoder/plugins/RegistryAbi.ts +562 -0
  71. package/src/decoder/plugins/enhanceBurntPix.ts +132 -0
  72. package/src/decoder/plugins/enhanceGraffiti.ts +70 -0
  73. package/src/decoder/plugins/enhanceLSP0ERC725Account.ts +179 -0
  74. package/src/decoder/plugins/enhanceLSP26FollowerSystem.ts +88 -0
  75. package/src/decoder/plugins/enhanceLSP6KeyManager.ts +231 -0
  76. package/src/decoder/plugins/enhanceLSP7DigitalAsset.ts +165 -0
  77. package/src/decoder/plugins/enhanceLSP8IdentifiableDigitalAsset.ts +170 -0
  78. package/src/decoder/plugins/enhanceLSP9Vault.ts +57 -0
  79. package/src/decoder/plugins/enhanceRetrieveAbi.ts +85 -0
  80. package/src/decoder/plugins/enhanceSetData.ts +135 -0
  81. package/src/decoder/plugins/index.ts +99 -0
  82. package/src/decoder/plugins/schemaDefault.ts +318 -0
  83. package/src/decoder/plugins/standardPlugin.ts +202 -0
  84. package/src/decoder/registry.ts +322 -0
  85. package/src/decoder/singleGQL.ts +293 -0
  86. package/src/decoder/transaction.ts +198 -0
  87. package/src/decoder/types.ts +465 -0
  88. package/src/decoder/utils.ts +212 -0
  89. package/src/example/usage.ts +172 -0
  90. package/src/index.ts +174 -0
  91. package/src/server/addressResolver.ts +68 -0
  92. package/src/server/caches.ts +209 -0
  93. package/src/server/decodeTransactionSync.ts +156 -0
  94. package/src/server/decodeTransactionsBatch.ts +207 -0
  95. package/src/server/finishDecoding.ts +116 -0
  96. package/src/server/index.ts +81 -0
  97. package/src/server/lsp23Resolver.test.ts +46 -0
  98. package/src/server/lsp23Resolver.ts +419 -0
  99. package/src/server/types.ts +168 -0
  100. package/src/server.ts +22 -0
  101. package/src/shared/addressResolver.ts +651 -0
  102. package/src/shared/cache.ts +144 -0
  103. package/src/shared/constants.ts +21 -0
  104. package/src/stubs/tty.ts +13 -0
  105. package/src/stubs/util.ts +42 -0
  106. package/src/types/index.ts +154 -0
  107. package/src/types/provider.ts +46 -0
  108. package/src/umd.ts +13 -0
  109. package/src/utils/debug.ts +49 -0
  110. package/src/utils/json-bigint.ts +47 -0
@@ -0,0 +1,839 @@
1
+ import {
2
+ __name,
3
+ collectDataKeys,
4
+ decodeTransaction,
5
+ isAsyncOperationEnabled,
6
+ pluginRegistry
7
+ } from "./chunk-XVHJWV5U.js";
8
+
9
+ // src/core/dataModel.ts
10
+ import { batch, effect, signal } from "@preact/signals-core";
11
+ import { hexToBigInt, isHex, size, slice } from "viem";
12
+ function deepFreeze(obj) {
13
+ if (obj === null || typeof obj !== "object" || Object.isFrozen(obj)) {
14
+ return obj;
15
+ }
16
+ Object.freeze(obj);
17
+ for (const prop of Object.getOwnPropertyNames(obj)) {
18
+ const value = obj[prop];
19
+ if (value !== null && typeof value === "object") {
20
+ deepFreeze(value);
21
+ }
22
+ }
23
+ return obj;
24
+ }
25
+ __name(deepFreeze, "deepFreeze");
26
+ var DataModel = class {
27
+ static {
28
+ __name(this, "DataModel");
29
+ }
30
+ // Nested map structure: Address -> (TokenId | null) -> Signal
31
+ dataSignals = /* @__PURE__ */ new Map();
32
+ // Transaction signals: Hash -> (DecoderIndex | null) -> Signal
33
+ transactionSignals = /* @__PURE__ */ new Map();
34
+ // Keep track of unique transaction hashes in order
35
+ transactionOrder = [];
36
+ options;
37
+ // Track pending resolved data updates
38
+ pendingResolvedUpdate = false;
39
+ constructor(options = {}) {
40
+ this.options = options;
41
+ }
42
+ /**
43
+ * Extract a 20-byte address from a potentially 32-byte hex value
44
+ * If the input is 32 bytes, validates it's zero-padded and takes the rightmost 20 bytes
45
+ * If the input is 20 bytes, returns it as-is
46
+ */
47
+ extractAddress(hex) {
48
+ if (!isHex(hex)) {
49
+ throw new Error(`Invalid hex value: ${hex}`);
50
+ }
51
+ const bytes = size(hex);
52
+ if (bytes === 32) {
53
+ const first12Bytes = slice(hex, 0, 12);
54
+ if (hexToBigInt(first12Bytes) !== 0n) {
55
+ throw new Error(
56
+ `Invalid 32-byte address: first 12 bytes must be zero for a padded address, got ${first12Bytes}`
57
+ );
58
+ }
59
+ return slice(hex, 12, 32);
60
+ }
61
+ if (bytes === 20) {
62
+ return hex;
63
+ }
64
+ throw new Error(`Invalid address length: ${bytes} bytes`);
65
+ }
66
+ /**
67
+ * Get or create a signal for a specific key
68
+ */
69
+ getOrCreateSignal(key) {
70
+ let sig = this.dataSignals.get(key);
71
+ if (!sig) {
72
+ sig = signal({
73
+ loading: false,
74
+ data: void 0,
75
+ error: void 0,
76
+ lastUpdated: void 0
77
+ });
78
+ this.dataSignals.set(key, sig);
79
+ if (this.options.onMissingKeys) {
80
+ setTimeout(() => {
81
+ const missing = this.getMissingKeys();
82
+ if (missing.length > 0) {
83
+ this.options.onMissingKeys?.(missing);
84
+ }
85
+ }, 0);
86
+ }
87
+ }
88
+ return sig;
89
+ }
90
+ /**
91
+ * Extract transaction key from transaction JSON
92
+ */
93
+ getTransactionKey(transaction) {
94
+ if (!transaction || typeof transaction !== "object") {
95
+ throw new Error("Transaction must be an object");
96
+ }
97
+ const tx = transaction;
98
+ if (!tx.hash && !tx.transactionHash) {
99
+ throw new Error("Transaction must have hash or transactionHash");
100
+ }
101
+ return {
102
+ hash: tx.hash || tx.transactionHash,
103
+ decoderIndex: tx.decoderIndex ? tx.decoderIndex : void 0
104
+ };
105
+ }
106
+ /**
107
+ * Get or create the inner map for a transaction hash
108
+ */
109
+ getOrCreateTransactionMap(hash) {
110
+ const normalizedHash = hash.toLowerCase();
111
+ let map = this.transactionSignals.get(normalizedHash);
112
+ if (!map) {
113
+ map = /* @__PURE__ */ new Map();
114
+ this.transactionSignals.set(normalizedHash, map);
115
+ }
116
+ return map;
117
+ }
118
+ /**
119
+ * Add one or more transactions to the model
120
+ * Collects all addresses from all transactions and marks them as loading
121
+ */
122
+ addTransactions(jsonTransactions) {
123
+ const transactions = Array.isArray(jsonTransactions) ? jsonTransactions : [jsonTransactions];
124
+ const isSingle = !Array.isArray(jsonTransactions);
125
+ const allAddresses = /* @__PURE__ */ new Set();
126
+ const transactionAddresses = [];
127
+ for (const tx of transactions) {
128
+ const addresses = collectDataKeys(tx);
129
+ transactionAddresses.push(addresses);
130
+ for (const addr of addresses) {
131
+ allAddresses.add(addr);
132
+ }
133
+ }
134
+ const uniqueAddresses = Array.from(allAddresses);
135
+ if (uniqueAddresses.length > 0) {
136
+ this.setLoading(uniqueAddresses);
137
+ }
138
+ const results = transactions.map((tx, index) => {
139
+ const key = this.getTransactionKey(tx);
140
+ const normalizedHash = key.hash.toLowerCase();
141
+ const decoderIndex = key.decoderIndex || null;
142
+ const isNewHash = !this.transactionSignals.has(normalizedHash);
143
+ const txMap = this.getOrCreateTransactionMap(normalizedHash);
144
+ if (txMap.has(decoderIndex)) {
145
+ throw new Error(
146
+ `Transaction already exists: ${normalizedHash}:${decoderIndex || 0}`
147
+ );
148
+ }
149
+ const frozenData = deepFreeze(
150
+ structuredClone(tx)
151
+ );
152
+ const sig = signal({
153
+ data: frozenData,
154
+ loading: false,
155
+ addresses: Object.freeze([...transactionAddresses[index]]),
156
+ error: void 0,
157
+ lastUpdated: Date.now(),
158
+ resolvedData: frozenData,
159
+ // Start with the same frozen data
160
+ addressesResolved: false
161
+ });
162
+ txMap.set(decoderIndex, sig);
163
+ if (isNewHash) {
164
+ this.transactionOrder.push(normalizedHash);
165
+ }
166
+ if (this.options.onNewTransaction) {
167
+ this.options.onNewTransaction(tx);
168
+ }
169
+ return sig;
170
+ });
171
+ return isSingle ? results[0] : results;
172
+ }
173
+ /**
174
+ * Get an existing transaction signal (returns undefined if not found)
175
+ */
176
+ getTransaction(jsonTransaction) {
177
+ const key = this.getTransactionKey(jsonTransaction);
178
+ const normalizedHash = key.hash.toLowerCase();
179
+ const decoderIndex = key.decoderIndex || null;
180
+ const txMap = this.transactionSignals.get(normalizedHash);
181
+ if (!txMap) {
182
+ return void 0;
183
+ }
184
+ return txMap.get(decoderIndex);
185
+ }
186
+ /**
187
+ * Get transaction by hash and decoder index
188
+ */
189
+ getTransactionByKey(hash, decoderIndex) {
190
+ const normalizedHash = hash.toLowerCase();
191
+ const txMap = this.transactionSignals.get(normalizedHash);
192
+ if (!txMap) {
193
+ return void 0;
194
+ }
195
+ return txMap.get(decoderIndex || null);
196
+ }
197
+ /**
198
+ * Update a transaction's data and re-collect addresses
199
+ * Useful after async decoding completes
200
+ */
201
+ updateTransactionData(hash, newData, decoderIndex) {
202
+ const normalizedHash = hash.toLowerCase();
203
+ const txMap = this.transactionSignals.get(normalizedHash);
204
+ if (!txMap) return;
205
+ const sig = txMap.get(decoderIndex ?? null);
206
+ if (!sig) return;
207
+ const newAddresses = collectDataKeys(newData, true, [
208
+ ...sig.value.addresses
209
+ ]);
210
+ const frozenData = deepFreeze(structuredClone(newData));
211
+ sig.value = {
212
+ ...sig.value,
213
+ data: frozenData,
214
+ addresses: Object.freeze([...newAddresses]),
215
+ lastUpdated: Date.now(),
216
+ // Start with the current data, will be enhanced when addresses load
217
+ resolvedData: frozenData,
218
+ addressesResolved: false
219
+ };
220
+ this.setLoading(newAddresses);
221
+ queueMicrotask(() => {
222
+ this.updateResolvedTransactionData();
223
+ });
224
+ }
225
+ /**
226
+ * Get all decoded transactions for a hash by index (insertion order)
227
+ */
228
+ getTransactionsByIndex(index) {
229
+ if (index < 0 || index >= this.transactionOrder.length) {
230
+ return void 0;
231
+ }
232
+ const hash = this.transactionOrder[index];
233
+ return this.transactionSignals.get(hash);
234
+ }
235
+ /**
236
+ * Get transaction hash by index
237
+ */
238
+ getTransactionHashByIndex(index) {
239
+ return this.transactionOrder[index];
240
+ }
241
+ /**
242
+ * Get number of unique transaction hashes
243
+ */
244
+ getTransactionCount() {
245
+ return this.transactionOrder.length;
246
+ }
247
+ /**
248
+ * Get number of decoded transactions for a specific hash
249
+ */
250
+ getDecodedCount(hash) {
251
+ const normalizedHash = hash.toLowerCase();
252
+ const txMap = this.transactionSignals.get(normalizedHash);
253
+ return txMap ? txMap.size : 0;
254
+ }
255
+ /**
256
+ * Get all decoded transactions for a specific hash
257
+ */
258
+ getDecodedTransactions(hash) {
259
+ const normalizedHash = hash.toLowerCase();
260
+ const txMap = this.transactionSignals.get(normalizedHash);
261
+ return txMap ? Array.from(txMap.values()) : [];
262
+ }
263
+ /**
264
+ * Get address signal (alias for getSignal for clearer API)
265
+ */
266
+ getAddress(address) {
267
+ return this.getSignal(address);
268
+ }
269
+ /**
270
+ * Inject data into the model
271
+ * Can be called multiple times to progressively add/update data
272
+ */
273
+ injectData(dataList) {
274
+ batch(() => {
275
+ for (const data of dataList) {
276
+ const key = data.tokenId ? `${data.address}:${data.tokenId}` : data.address;
277
+ const sig = this.getOrCreateSignal(key);
278
+ sig.value = {
279
+ loading: false,
280
+ data: deepFreeze(structuredClone(data)),
281
+ error: void 0,
282
+ lastUpdated: Date.now()
283
+ };
284
+ }
285
+ });
286
+ this.updateResolvedTransactionData();
287
+ }
288
+ /**
289
+ * Update a single item
290
+ */
291
+ updateData(data) {
292
+ const key = data.tokenId ? `${data.address}:${data.tokenId}` : data.address;
293
+ const sig = this.getOrCreateSignal(key);
294
+ sig.value = {
295
+ loading: false,
296
+ data: deepFreeze(structuredClone(data)),
297
+ error: void 0,
298
+ lastUpdated: Date.now()
299
+ };
300
+ if (!this.pendingResolvedUpdate) {
301
+ this.pendingResolvedUpdate = true;
302
+ queueMicrotask(() => {
303
+ this.pendingResolvedUpdate = false;
304
+ this.updateResolvedTransactionData();
305
+ });
306
+ }
307
+ }
308
+ /**
309
+ * Mark keys as loading
310
+ */
311
+ setLoading(keys) {
312
+ batch(() => {
313
+ for (const key of keys) {
314
+ const sig = this.getOrCreateSignal(key);
315
+ sig.value = { ...sig.value, loading: true };
316
+ }
317
+ });
318
+ }
319
+ /**
320
+ * Mark a key as errored
321
+ */
322
+ setError(key, error) {
323
+ const sig = this.getOrCreateSignal(key);
324
+ sig.value = {
325
+ loading: false,
326
+ data: void 0,
327
+ error,
328
+ lastUpdated: Date.now()
329
+ };
330
+ }
331
+ /**
332
+ * Get signal for a key (creates one if doesn't exist)
333
+ */
334
+ getSignal(key) {
335
+ return this.getOrCreateSignal(key);
336
+ }
337
+ /**
338
+ * Subscribe to key updates
339
+ */
340
+ subscribe(key, callback) {
341
+ const sig = this.getSignal(key);
342
+ return effect(() => callback(sig.value));
343
+ }
344
+ /**
345
+ * Get current state of a key
346
+ */
347
+ getState(key) {
348
+ return this.getSignal(key).value;
349
+ }
350
+ /**
351
+ * Get all keys that have no data
352
+ */
353
+ getMissingKeys() {
354
+ const missingKeys = [];
355
+ for (const [key] of this.dataSignals) {
356
+ missingKeys.push(key);
357
+ }
358
+ return missingKeys;
359
+ }
360
+ /**
361
+ * Get all keys currently loading
362
+ */
363
+ getLoadingKeys() {
364
+ const loadingKeys = [];
365
+ for (const [key, sig] of this.dataSignals) {
366
+ if (sig.value.loading) {
367
+ loadingKeys.push(key);
368
+ }
369
+ }
370
+ return loadingKeys;
371
+ }
372
+ /**
373
+ * Check if we have data for a key
374
+ */
375
+ hasData(key) {
376
+ const sig = this.dataSignals.get(key);
377
+ return sig ? sig.value.data !== void 0 : false;
378
+ }
379
+ /**
380
+ * Clear all data
381
+ */
382
+ clear() {
383
+ batch(() => {
384
+ for (const sig of this.dataSignals.values()) {
385
+ sig.value = {
386
+ loading: false,
387
+ data: void 0,
388
+ error: void 0,
389
+ lastUpdated: void 0
390
+ };
391
+ }
392
+ for (const txMap of this.transactionSignals.values()) {
393
+ for (const sig of txMap.values()) {
394
+ sig.value = {
395
+ ...sig.value,
396
+ loading: false,
397
+ error: void 0
398
+ };
399
+ }
400
+ }
401
+ });
402
+ }
403
+ /**
404
+ * Remove specific keys from cache
405
+ */
406
+ remove(keys) {
407
+ for (const key of keys) {
408
+ this.dataSignals.delete(key);
409
+ }
410
+ }
411
+ /**
412
+ * Get all cached keys
413
+ */
414
+ getAllKeys() {
415
+ const keys = [];
416
+ for (const [key] of this.dataSignals) {
417
+ keys.push(key);
418
+ }
419
+ return Object.freeze(keys);
420
+ }
421
+ /**
422
+ * Get all data as a plain object (for debugging/serialization)
423
+ */
424
+ getAllData() {
425
+ const result = {};
426
+ for (const [key, sig] of this.dataSignals) {
427
+ result[key] = sig.value;
428
+ }
429
+ return Object.freeze(result);
430
+ }
431
+ /**
432
+ * Get all transaction data (for debugging)
433
+ */
434
+ getAllTransactions() {
435
+ const result = {};
436
+ for (const [hash, txMap] of this.transactionSignals) {
437
+ for (const [decoderIndex, sig] of txMap) {
438
+ const key = decoderIndex === null ? hash : `${hash}:${decoderIndex}`;
439
+ result[key] = sig.value;
440
+ }
441
+ }
442
+ return Object.freeze(result);
443
+ }
444
+ /**
445
+ * Get all transactions in order (returns all decoded transactions grouped by hash)
446
+ */
447
+ getTransactionsInOrder() {
448
+ const result = [];
449
+ for (const hash of this.transactionOrder) {
450
+ const txMap = this.transactionSignals.get(hash);
451
+ if (txMap) {
452
+ result.push({
453
+ hash,
454
+ transactions: Array.from(txMap.values())
455
+ });
456
+ }
457
+ }
458
+ return result;
459
+ }
460
+ /**
461
+ * Create a resolved version of transaction data with all addresses populated
462
+ */
463
+ createResolvedTransactionData(transactionData, addresses) {
464
+ const resolved = structuredClone(transactionData);
465
+ const addressMap = /* @__PURE__ */ new Map();
466
+ for (const key of addresses) {
467
+ const addressData = this.getData(key);
468
+ if (addressData) {
469
+ addressMap.set(key.toLowerCase(), addressData);
470
+ }
471
+ }
472
+ this.replaceAddressesWithPaths(resolved, addressMap);
473
+ return deepFreeze(resolved);
474
+ }
475
+ /**
476
+ * Replace addresses using path information (similar to collectAddressesWithPaths)
477
+ */
478
+ replaceAddressesWithPaths(data, addressMap) {
479
+ function traverse(obj, path = [], parent) {
480
+ if (typeof obj === "string" && obj.startsWith("0x")) {
481
+ const isPaddedAddress = /^0x0*([a-fA-F0-9]{40})$/.test(obj);
482
+ if (isPaddedAddress || isHex(obj) && size(obj) === 20) {
483
+ const address = isPaddedAddress ? obj.replace(/^0x0*([a-fA-F0-9]{40})$/, "0x$1") : obj;
484
+ if (address.slice(2).split("").filter((c) => c === "0").length > 10) {
485
+ return;
486
+ }
487
+ const currentKey = path[path.length - 1];
488
+ const tokenId = parent && !Array.isArray(parent) && "tokenId" in parent && parent.tokenId ? parent.tokenId : void 0;
489
+ let addressData;
490
+ if (tokenId) {
491
+ const compositeKey = `${address.toLowerCase()}_${tokenId.toLowerCase()}`;
492
+ addressData = addressMap.get(compositeKey);
493
+ } else {
494
+ addressData = addressMap.get(address.toLowerCase());
495
+ }
496
+ if (addressData && parent) {
497
+ if (Array.isArray(parent) && typeof currentKey === "number") {
498
+ parent[currentKey] = addressData;
499
+ } else if (!Array.isArray(parent) && typeof currentKey === "string") {
500
+ parent[currentKey] = addressData;
501
+ }
502
+ }
503
+ }
504
+ return;
505
+ }
506
+ if (!obj || typeof obj !== "object") return;
507
+ if (Array.isArray(obj)) {
508
+ for (let index = 0; index < obj.length; index++) {
509
+ traverse(obj[index], path.concat([index]), obj);
510
+ }
511
+ } else {
512
+ const record = obj;
513
+ for (const [key, value] of Object.entries(record)) {
514
+ traverse(value, path.concat([key]), record);
515
+ }
516
+ }
517
+ }
518
+ __name(traverse, "traverse");
519
+ traverse(data);
520
+ }
521
+ /**
522
+ * Update resolved transaction data for all transactions where addresses are loaded
523
+ */
524
+ updateResolvedTransactionData() {
525
+ for (const [_hash, txMap] of this.transactionSignals) {
526
+ for (const [_decoderIndex, signal3] of txMap) {
527
+ const currentState = signal3.value;
528
+ if (currentState.addressesResolved || currentState.addresses.length === 0) {
529
+ continue;
530
+ }
531
+ let allAddressesLoaded = true;
532
+ for (const addressKey of currentState.addresses) {
533
+ const addressState = this.getState(addressKey);
534
+ if (addressState.loading || !addressState.data) {
535
+ allAddressesLoaded = false;
536
+ break;
537
+ }
538
+ }
539
+ if (allAddressesLoaded) {
540
+ const resolvedData = this.createResolvedTransactionData(
541
+ currentState.data,
542
+ currentState.addresses
543
+ );
544
+ signal3.value = {
545
+ ...currentState,
546
+ resolvedData,
547
+ addressesResolved: true,
548
+ lastUpdated: Date.now()
549
+ };
550
+ }
551
+ }
552
+ }
553
+ }
554
+ /**
555
+ * Get data by key - convenience method that handles both 20 and 32 byte addresses
556
+ */
557
+ getData(key) {
558
+ return this.getState(key).data;
559
+ }
560
+ /**
561
+ * Check if a key is loading
562
+ */
563
+ isLoading(key) {
564
+ return this.getState(key).loading;
565
+ }
566
+ /**
567
+ * Get error for a key
568
+ */
569
+ getError(key) {
570
+ return this.getState(key).error;
571
+ }
572
+ };
573
+ function createConsumerProxy(model) {
574
+ const consumerMethods = [
575
+ // Transaction read methods
576
+ "getTransaction",
577
+ "getTransactionByKey",
578
+ "getTransactionsByIndex",
579
+ "getTransactionHashByIndex",
580
+ "getTransactionCount",
581
+ "getDecodedCount",
582
+ "getDecodedTransactions",
583
+ "getTransactionsInOrder",
584
+ // Address read methods
585
+ "getAddress",
586
+ "getSignal",
587
+ "subscribe",
588
+ "getState",
589
+ "hasData",
590
+ "getData",
591
+ "isLoading",
592
+ "getError",
593
+ // Collection read methods
594
+ "getAllKeys",
595
+ "getAllData",
596
+ "getAllTransactions"
597
+ ];
598
+ const proxy = new Proxy(model, {
599
+ get(target, prop, receiver) {
600
+ if (typeof prop === "string" && consumerMethods.includes(prop)) {
601
+ const value = Reflect.get(target, prop, receiver);
602
+ if (typeof value === "function") {
603
+ return value.bind(target);
604
+ }
605
+ return value;
606
+ }
607
+ return void 0;
608
+ },
609
+ set() {
610
+ return false;
611
+ },
612
+ deleteProperty() {
613
+ return false;
614
+ },
615
+ defineProperty() {
616
+ return false;
617
+ },
618
+ setPrototypeOf() {
619
+ return false;
620
+ }
621
+ });
622
+ return proxy;
623
+ }
624
+ __name(createConsumerProxy, "createConsumerProxy");
625
+ function createDataModel(options) {
626
+ const model = new DataModel(options);
627
+ Object.freeze(DataModel.prototype);
628
+ Object.freeze(DataModel);
629
+ return model;
630
+ }
631
+ __name(createDataModel, "createDataModel");
632
+
633
+ // src/core/instance.ts
634
+ var dataModelInstance = new DataModel();
635
+ Object.freeze(DataModel.prototype);
636
+ Object.freeze(DataModel);
637
+ var dataModel = dataModelInstance;
638
+ var consumerModel = createConsumerProxy(dataModelInstance);
639
+ function createGlobalInstance() {
640
+ if (typeof window !== "undefined") {
641
+ const consumerProxy = createConsumerProxy(dataModelInstance);
642
+ Object.defineProperty(window, "TransactionDecoder", {
643
+ value: consumerProxy,
644
+ writable: false,
645
+ configurable: false,
646
+ enumerable: true
647
+ });
648
+ }
649
+ }
650
+ __name(createGlobalInstance, "createGlobalInstance");
651
+
652
+ // src/decoder/decodeTransaction.ts
653
+ import { signal as signal2 } from "@preact/signals-core";
654
+
655
+ // src/shared/constants.ts
656
+ var ERROR_CODES = {
657
+ INVALID_TRANSACTION: "INVALID_TRANSACTION",
658
+ DECODING_FAILED: "DECODING_FAILED",
659
+ NETWORK_ERROR: "NETWORK_ERROR",
660
+ RATE_LIMIT: "RATE_LIMIT",
661
+ UNAUTHORIZED: "UNAUTHORIZED",
662
+ NOT_FOUND: "NOT_FOUND"
663
+ };
664
+
665
+ // src/decoder/decodeTransaction.ts
666
+ async function decodeTransaction2(transaction, options) {
667
+ const isBatch = Array.isArray(transaction);
668
+ const transactions = isBatch ? transaction : [transaction];
669
+ const results = await decodeTransactionBatch(transactions, options);
670
+ if (isBatch) {
671
+ return results;
672
+ }
673
+ return results[0];
674
+ }
675
+ __name(decodeTransaction2, "decodeTransaction");
676
+ async function decodeTransactionBatch(transactions, options) {
677
+ const overridePluginNames = options.plugins?.map((p) => p.name).filter((name) => typeof name === "string") || [];
678
+ const overrideSchemaNames = options.schemaPlugins?.map((p) => p.name).filter((name) => typeof name === "string") || [];
679
+ const registeredPlugins = await pluginRegistry.getAll({
680
+ excludeNames: overridePluginNames
681
+ });
682
+ const registeredSchemaPlugins = pluginRegistry.getAllSchema(overrideSchemaNames);
683
+ const allPlugins = [...registeredPlugins, ...options.plugins || []];
684
+ const allSchemaPlugins = [
685
+ ...registeredSchemaPlugins,
686
+ ...options.schemaPlugins || []
687
+ ];
688
+ const syncOptions = {
689
+ ...options,
690
+ plugins: allPlugins.filter(({ usesAsync }) => !usesAsync),
691
+ schemaPlugins: allSchemaPlugins,
692
+ async: false
693
+ };
694
+ const results = await Promise.all(
695
+ transactions.map(async (tx) => {
696
+ const initialResult = await decodeTransaction(tx, syncOptions);
697
+ const initialData = deepFreeze(initialResult || createErrorResult(tx));
698
+ const txSignal = signal2({
699
+ loading: false,
700
+ data: initialData,
701
+ decodingStatus: initialResult ? "decoded" : "failed",
702
+ addresses: collectDataKeys(tx),
703
+ addressesResolved: false,
704
+ lastUpdated: Date.now()
705
+ });
706
+ return {
707
+ transaction: tx,
708
+ immediate: initialData,
709
+ signal: txSignal
710
+ };
711
+ })
712
+ );
713
+ const hasAsyncPlugins = true;
714
+ const pluginsEnabled = isAsyncOperationEnabled(
715
+ options.async,
716
+ 1 /* ENABLE_PLUGINS */
717
+ );
718
+ if (hasAsyncPlugins && pluginsEnabled) {
719
+ const asyncOptions = {
720
+ ...options,
721
+ plugins: allPlugins,
722
+ schemaPlugins: allSchemaPlugins,
723
+ async: true
724
+ };
725
+ for (const { transaction, signal: txSignal } of results) {
726
+ decodeTransaction(transaction, asyncOptions).then((enhanced) => {
727
+ if (enhanced) {
728
+ txSignal.value = {
729
+ ...txSignal.value,
730
+ data: deepFreeze(enhanced),
731
+ decodingStatus: "enhanced",
732
+ addresses: collectDataKeys(enhanced),
733
+ lastUpdated: Date.now()
734
+ };
735
+ }
736
+ }).catch((error) => {
737
+ console.error("Async decode error:", error);
738
+ txSignal.value = {
739
+ ...txSignal.value,
740
+ decodingStatus: "failed",
741
+ error: error instanceof Error ? error.message : "Unknown error",
742
+ loading: false
743
+ };
744
+ });
745
+ }
746
+ }
747
+ const addressResolveEnabled = isAsyncOperationEnabled(
748
+ options.async,
749
+ 2 /* ENABLE_ADDRESS_RESOLVE */
750
+ );
751
+ if (options.addressResolver && addressResolveEnabled) {
752
+ const allAddresses = /* @__PURE__ */ new Set();
753
+ for (const { signal: txSignal } of results) {
754
+ for (const addr of txSignal.value.addresses) {
755
+ allAddresses.add(addr);
756
+ }
757
+ }
758
+ if (allAddresses.size > 0) {
759
+ options.addressResolver.resolveAddresses(Array.from(allAddresses)).then(() => {
760
+ for (const { signal: txSignal } of results) {
761
+ if (txSignal.value.decodingStatus !== "failed") {
762
+ txSignal.value = {
763
+ ...txSignal.value,
764
+ addressesResolved: true,
765
+ decodingStatus: "complete",
766
+ lastUpdated: Date.now()
767
+ };
768
+ }
769
+ }
770
+ }).catch((error) => {
771
+ console.error("Address resolution error:", error);
772
+ });
773
+ }
774
+ } else if (!hasAsyncPlugins || !pluginsEnabled && !addressResolveEnabled) {
775
+ for (const { signal: txSignal } of results) {
776
+ if (txSignal.value.decodingStatus !== "failed") {
777
+ txSignal.value = {
778
+ ...txSignal.value,
779
+ decodingStatus: "complete"
780
+ };
781
+ }
782
+ }
783
+ }
784
+ return results.map((r) => ({
785
+ immediate: r.immediate,
786
+ signal: r.signal
787
+ }));
788
+ }
789
+ __name(decodeTransactionBatch, "decodeTransactionBatch");
790
+ function createErrorResult(transaction) {
791
+ return {
792
+ ...transaction,
793
+ resultType: "error",
794
+ isDecoded: false,
795
+ errorType: "ERROR" /* ERROR */,
796
+ sig: transaction.input?.slice(0, 10),
797
+ error: {
798
+ code: ERROR_CODES.DECODING_FAILED,
799
+ message: "Failed to decode transaction",
800
+ details: new Error("Decoder returned undefined")
801
+ }
802
+ };
803
+ }
804
+ __name(createErrorResult, "createErrorResult");
805
+ async function decodeTransactionAsync(transaction, options) {
806
+ const isBatch = Array.isArray(transaction);
807
+ const result = await decodeTransaction2(transaction, options);
808
+ const results = isBatch ? result : [result];
809
+ const finalResults = await Promise.all(
810
+ results.map(
811
+ ({ signal: signal3 }) => new Promise((resolve) => {
812
+ const checkComplete = /* @__PURE__ */ __name(() => {
813
+ const state = signal3.value;
814
+ if (state.decodingStatus === "complete" || state.decodingStatus === "failed") {
815
+ resolve(state.data);
816
+ } else {
817
+ setTimeout(checkComplete, 10);
818
+ }
819
+ }, "checkComplete");
820
+ checkComplete();
821
+ })
822
+ )
823
+ );
824
+ if (isBatch) {
825
+ return finalResults;
826
+ }
827
+ return finalResults[0];
828
+ }
829
+ __name(decodeTransactionAsync, "decodeTransactionAsync");
830
+
831
+ export {
832
+ createDataModel,
833
+ dataModel,
834
+ consumerModel,
835
+ createGlobalInstance,
836
+ decodeTransaction2 as decodeTransaction,
837
+ decodeTransactionAsync
838
+ };
839
+ //# sourceMappingURL=chunk-GXZOF3QY.js.map