@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,144 @@
1
+ import type { DataKey, EnhancedInfo } from '../types'
2
+
3
+ /**
4
+ * Address identity cache interface
5
+ * Can be implemented with different backends (LRU, Redis, etc.)
6
+ */
7
+ export interface AddressIdentityCache {
8
+ /**
9
+ * Get cached address data
10
+ */
11
+ get(
12
+ key: DataKey
13
+ ): EnhancedInfo | undefined | Promise<EnhancedInfo | undefined>
14
+
15
+ /**
16
+ * Set address data in cache
17
+ */
18
+ set(key: DataKey, value: EnhancedInfo): void | Promise<void>
19
+
20
+ /**
21
+ * Check if address is in cache
22
+ */
23
+ has(key: DataKey): boolean | Promise<boolean>
24
+
25
+ /**
26
+ * Get multiple addresses at once
27
+ */
28
+ getMany?(
29
+ keys: readonly DataKey[]
30
+ ): Map<DataKey, EnhancedInfo> | Promise<Map<DataKey, EnhancedInfo>>
31
+
32
+ /**
33
+ * Set multiple addresses at once
34
+ */
35
+ setMany?(entries: Array<[DataKey, EnhancedInfo]>): void | Promise<void>
36
+
37
+ /**
38
+ * Clear all cached data
39
+ */
40
+ clear?(): void | Promise<void>
41
+ }
42
+
43
+ /**
44
+ * Type guard to check if value is a promise
45
+ */
46
+ function isPromise<T>(value: T | Promise<T>): value is Promise<T> {
47
+ return value instanceof Promise
48
+ }
49
+
50
+ /**
51
+ * Helper to convert DataKey to cache key string
52
+ */
53
+ export function getDataKeyCacheKey(key: DataKey): string {
54
+ return key.toLowerCase()
55
+ }
56
+
57
+ /**
58
+ * Convert a DataKey to the standardized string format
59
+ * @param dataKey - A hex string (address or address:tokenId)
60
+ * @returns The same string
61
+ */
62
+ export function dataKeyToString(dataKey: DataKey): string {
63
+ return dataKey
64
+ }
65
+
66
+ /**
67
+ * Parse a string to a DataKey
68
+ * @param str - String in format "address" or "address:tokenId"
69
+ * @returns DataKey as a hex string
70
+ */
71
+ export function parseDataKey(str: string): DataKey {
72
+ // Just return the string as-is since DataKey is now always a string
73
+ return str as DataKey
74
+ }
75
+
76
+ /**
77
+ * Create a simple in-memory address cache
78
+ */
79
+ export function createMemoryAddressIdentityCache(
80
+ ttlMs: number = 1000 * 60 * 5 // 5 minutes default
81
+ ): AddressIdentityCache {
82
+ const cache = new Map<string, { data: EnhancedInfo; expires: number }>()
83
+
84
+ return {
85
+ get(key: DataKey): EnhancedInfo | undefined {
86
+ const cacheKey = getDataKeyCacheKey(key)
87
+ const entry = cache.get(cacheKey)
88
+
89
+ if (!entry) return undefined
90
+
91
+ if (Date.now() > entry.expires) {
92
+ cache.delete(cacheKey)
93
+ return undefined
94
+ }
95
+
96
+ return entry.data
97
+ },
98
+
99
+ set(key: DataKey, value: EnhancedInfo): void {
100
+ const cacheKey = getDataKeyCacheKey(key)
101
+ cache.set(cacheKey, {
102
+ data: value,
103
+ expires: Date.now() + ttlMs,
104
+ })
105
+ },
106
+
107
+ has(key: DataKey): boolean {
108
+ const cacheKey = getDataKeyCacheKey(key)
109
+ const entry = cache.get(cacheKey)
110
+
111
+ if (!entry) return false
112
+
113
+ if (Date.now() > entry.expires) {
114
+ cache.delete(cacheKey)
115
+ return false
116
+ }
117
+
118
+ return true
119
+ },
120
+
121
+ getMany(keys: DataKey[]): Map<DataKey, EnhancedInfo> {
122
+ const results = new Map<DataKey, EnhancedInfo>()
123
+
124
+ for (const key of keys) {
125
+ const data = this.get(key)
126
+ if (data && !isPromise(data)) {
127
+ results.set(key, data)
128
+ }
129
+ }
130
+
131
+ return results
132
+ },
133
+
134
+ setMany(entries: Array<[DataKey, EnhancedInfo]>): void {
135
+ for (const [key, value] of entries) {
136
+ this.set(key, value)
137
+ }
138
+ },
139
+
140
+ clear(): void {
141
+ cache.clear()
142
+ },
143
+ }
144
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared constants
3
+ */
4
+
5
+ export const DECODER_VERSION = '0.1.0'
6
+
7
+ export const DEFAULT_CONFIG = {
8
+ endpoint: 'https://api.lukso.network/decoder',
9
+ batchSize: 100,
10
+ retryAttempts: 3,
11
+ timeout: 30000,
12
+ } as const
13
+
14
+ export const ERROR_CODES = {
15
+ INVALID_TRANSACTION: 'INVALID_TRANSACTION',
16
+ DECODING_FAILED: 'DECODING_FAILED',
17
+ NETWORK_ERROR: 'NETWORK_ERROR',
18
+ RATE_LIMIT: 'RATE_LIMIT',
19
+ UNAUTHORIZED: 'UNAUTHORIZED',
20
+ NOT_FOUND: 'NOT_FOUND',
21
+ } as const
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Stub for Node.js tty module in edge/worker environments
3
+ */
4
+
5
+ export const isatty = () => false
6
+ export const ReadStream = class ReadStream {}
7
+ export const WriteStream = class WriteStream {}
8
+
9
+ export default {
10
+ isatty,
11
+ ReadStream,
12
+ WriteStream,
13
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Stub for Node.js util module in edge/worker environments
3
+ * Only includes what debug module might use
4
+ */
5
+
6
+ export const inspect = (obj: any) => {
7
+ try {
8
+ return JSON.stringify(obj, null, 2)
9
+ } catch {
10
+ return String(obj)
11
+ }
12
+ }
13
+
14
+ export const format = (f: string, ...args: any[]) => {
15
+ let i = 0
16
+ return f.replace(/%[sdj%]/g, (x) => {
17
+ if (x === '%%') return '%'
18
+ if (i >= args.length) return x
19
+ switch (x) {
20
+ case '%s':
21
+ return String(args[i++])
22
+ case '%d':
23
+ return Number(args[i++]).toString()
24
+ case '%j':
25
+ try {
26
+ return JSON.stringify(args[i++])
27
+ } catch {
28
+ return '[Circular]'
29
+ }
30
+ default:
31
+ return x
32
+ }
33
+ })
34
+ }
35
+
36
+ export const debuglog = () => () => {}
37
+
38
+ export default {
39
+ inspect,
40
+ format,
41
+ debuglog,
42
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Core types for @lukso/decoder
3
+ */
4
+
5
+ import type { Signal } from '@preact/signals-core'
6
+ import type { Hex } from 'viem'
7
+ import type { DecoderResult, EnhancedInfo } from '../decoder/types'
8
+
9
+ // Re-export decoder types
10
+ export type { DecoderResult, EnhancedInfo } from '../decoder/types'
11
+ export { AsyncOperations } from '../decoder/types'
12
+
13
+ // Key is always a hex string - for tokens it's in the format "address:tokenId"
14
+ export type DataKey = Hex
15
+
16
+ // Helper type to make all properties deeply readonly
17
+ type DeepReadonly<T> = T extends (infer R)[]
18
+ ? DeepReadonlyArray<R>
19
+ : T extends (...args: unknown[]) => unknown
20
+ ? T
21
+ : T extends object
22
+ ? DeepReadonlyObject<T>
23
+ : T
24
+
25
+ interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}
26
+
27
+ type DeepReadonlyObject<T> = {
28
+ readonly [P in keyof T]: DeepReadonly<T[P]>
29
+ }
30
+
31
+ /**
32
+ * State wrapper for address/asset information
33
+ */
34
+ export interface AddressState {
35
+ loading: boolean
36
+ data?: DeepReadonly<EnhancedInfo>
37
+ error?: string
38
+ lastUpdated?: number
39
+ }
40
+
41
+ /**
42
+ * Transaction decoding status
43
+ * - raw: No decoding attempted yet
44
+ * - decoded: Sync decoding complete (phase 1)
45
+ * - enhanced: ABI retrieval complete (phase 2)
46
+ * - complete: Address resolution complete (phase 3)
47
+ * - failed: Decoding failed
48
+ */
49
+ export type DecodingStatus =
50
+ | 'raw'
51
+ | 'decoded'
52
+ | 'enhanced'
53
+ | 'complete'
54
+ | 'failed'
55
+
56
+ /**
57
+ * State wrapper for decoded transactions
58
+ */
59
+ export interface TransactionState {
60
+ loading: boolean
61
+ data: DeepReadonly<DecoderResult>
62
+ addresses: ReadonlyArray<DataKey>
63
+ error?: string
64
+ lastUpdated?: number
65
+ decodingStatus?: DecodingStatus
66
+ addressesResolved?: boolean
67
+ resolvedData?: DeepReadonly<DecoderResult> // Transaction with all addresses populated
68
+ }
69
+
70
+ /**
71
+ * Options for creating a data model instance
72
+ */
73
+ export interface DataModelOptions {
74
+ onMissingKeys?: (keys: DataKey[]) => void
75
+ onNewTransaction?: (transaction: unknown) => void
76
+ }
77
+
78
+ /**
79
+ * Read-only interface for consumers (views, components)
80
+ * This is the interface available on window.transactionDecoder
81
+ */
82
+ export interface IDataModelConsumer {
83
+ // Transaction read methods
84
+ getTransaction(jsonTransaction: unknown): Signal<TransactionState> | undefined
85
+ getTransactionByKey(
86
+ hash: Hex,
87
+ decoderIndex?: number
88
+ ): Signal<TransactionState> | undefined
89
+ getTransactionsByIndex(
90
+ index: number
91
+ ): Map<number | null, Signal<TransactionState>> | undefined
92
+ getTransactionHashByIndex(index: number): Hex | undefined
93
+ getTransactionCount(): number
94
+ getDecodedCount(hash: Hex): number
95
+ getDecodedTransactions(hash: Hex): Array<Signal<TransactionState>>
96
+ getTransactionsInOrder(): Array<{
97
+ hash: Hex
98
+ transactions: Array<Signal<TransactionState>>
99
+ }>
100
+
101
+ // Address read methods
102
+ getAddress(address: DataKey): Signal<AddressState>
103
+ getSignal(key: DataKey): Signal<AddressState>
104
+ subscribe(key: DataKey, callback: (state: AddressState) => void): () => void
105
+ getState(key: DataKey): AddressState
106
+ hasData(key: DataKey): boolean
107
+ getData(key: DataKey): DeepReadonly<EnhancedInfo> | undefined
108
+ isLoading(key: DataKey): boolean
109
+ getError(key: DataKey): string | undefined
110
+
111
+ // Collection read methods
112
+ getAllKeys(): ReadonlyArray<DataKey>
113
+ getAllData(): Readonly<Record<string, AddressState>>
114
+ getAllTransactions(): Readonly<Record<string, TransactionState>>
115
+ }
116
+
117
+ /**
118
+ * Full interface for data management (used by data providers)
119
+ * Includes all consumer methods plus data modification methods
120
+ */
121
+ export interface IDataModel extends IDataModelConsumer {
122
+ // Transaction management methods
123
+ addTransactions<T extends unknown | unknown[]>(
124
+ jsonTransactions: T
125
+ ): T extends unknown[]
126
+ ? Array<Signal<TransactionState>>
127
+ : Signal<TransactionState>
128
+ updateTransactionData(
129
+ hash: Hex,
130
+ newData: DecoderResult,
131
+ decoderIndex?: number
132
+ ): void
133
+
134
+ // Address management methods
135
+ injectData(dataList: EnhancedInfo[]): void
136
+ updateData(data: EnhancedInfo): void
137
+ setLoading(keys: DataKey[]): void
138
+ setError(key: DataKey, error: string): void
139
+
140
+ // Collection management methods
141
+ getMissingKeys(): DataKey[]
142
+ getLoadingKeys(): DataKey[]
143
+
144
+ // Management methods
145
+ clear(): void
146
+ remove(keys: DataKey[]): void
147
+ }
148
+
149
+ // Global window augmentation (only set by UMD builds or manual createGlobalInstance() call)
150
+ declare global {
151
+ interface Window {
152
+ TransactionDecoder?: IDataModelConsumer
153
+ }
154
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Types for data providers
3
+ */
4
+
5
+ import type { Address, Hex } from 'viem'
6
+ import type { TransactionState } from '.'
7
+
8
+ export interface TransactionInput {
9
+ hash: Hex
10
+ chainId: number
11
+ from: Address
12
+ to?: Address
13
+ value: string | bigint
14
+ data: Hex
15
+ blockNumber?: string | bigint
16
+ timestamp?: number
17
+ status?: 'pending' | 'success' | 'failed'
18
+ metadata?: TransactionState
19
+ }
20
+
21
+ export interface TransactionUpdate {
22
+ hash: Hex
23
+ chainId: number
24
+ status?: 'pending' | 'success' | 'failed'
25
+ blockNumber?: string | bigint
26
+ timestamp?: number
27
+ metadata?: Partial<TransactionState>
28
+ }
29
+
30
+ export interface ProviderConfig {
31
+ apiKey?: string
32
+ endpoint?: string
33
+ batchSize?: number
34
+ retryAttempts?: number
35
+ timeout?: number
36
+ }
37
+
38
+ export interface SubmissionResult {
39
+ success: boolean
40
+ transactionHash: Hex
41
+ message?: string
42
+ error?: {
43
+ code: string
44
+ message: string
45
+ }
46
+ }
package/src/umd.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * UMD entry point for @lukso/transaction-decoder
3
+ * This file automatically sets up window.TransactionDecoder for CDN usage
4
+ */
5
+
6
+ // Import the instance setup function
7
+ import { createGlobalInstance } from './core/instance'
8
+
9
+ // Re-export everything from the main entry
10
+ export * from './index'
11
+
12
+ // Automatically create the global instance for UMD builds
13
+ createGlobalInstance()
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Debug wrapper for edge/worker environments
3
+ * This avoids the tty dependency in the debug module
4
+ */
5
+
6
+ const debugInstances = new Map<string, boolean>()
7
+
8
+ // Simple debug implementation that doesn't rely on Node.js modules
9
+ export function createDebug(namespace: string) {
10
+ // Check if this namespace is enabled
11
+ const DEBUG = (typeof process !== 'undefined' && process.env?.DEBUG) || ''
12
+
13
+ // Simple pattern matching
14
+ const isEnabled = () => {
15
+ if (!DEBUG) return false
16
+ if (DEBUG === '*') return true
17
+
18
+ const patterns = DEBUG.split(',').map((p) => p.trim())
19
+ for (const pattern of patterns) {
20
+ if (pattern === namespace) return true
21
+ if (pattern.endsWith('*') && namespace.startsWith(pattern.slice(0, -1)))
22
+ return true
23
+ if (pattern.startsWith('-')) {
24
+ const negPattern = pattern.slice(1)
25
+ if (negPattern === namespace) return false
26
+ if (
27
+ negPattern.endsWith('*') &&
28
+ namespace.startsWith(negPattern.slice(0, -1))
29
+ )
30
+ return false
31
+ }
32
+ }
33
+ return false
34
+ }
35
+
36
+ debugInstances.set(namespace, isEnabled())
37
+
38
+ return (...args: any[]) => {
39
+ if (!debugInstances.get(namespace)) return
40
+
41
+ const timestamp = new Date().toISOString()
42
+ const prefix = `[${timestamp}] ${namespace}`
43
+
44
+ // In Cloudflare Workers, console.log is the only option
45
+ console.log(prefix, ...args)
46
+ }
47
+ }
48
+
49
+ export default createDebug
@@ -0,0 +1,47 @@
1
+ /**
2
+ * JSON serializer/deserializer that preserves BigInt types
3
+ *
4
+ * This implementation uses an 'n' suffix to indicate BigInt values,
5
+ * ensuring that values that were originally BigInt remain BigInt,
6
+ * and values that were originally numbers remain numbers.
7
+ *
8
+ * Example:
9
+ * - BigInt(123) serializes to "123n"
10
+ * - Number(123) serializes to 123
11
+ *
12
+ * This is important for blockchain data where some values must be BigInt
13
+ * (e.g., gas, value, nonce) while others should remain as numbers
14
+ * (e.g., array indices, status codes).
15
+ */
16
+
17
+ export const JSONbigString = {
18
+ /**
19
+ * Stringify an object, converting BigInt values to strings with 'n' suffix
20
+ */
21
+ stringify: (obj: any, replacer?: any, space?: string | number): string => {
22
+ return JSON.stringify(
23
+ obj,
24
+ (key, value) => {
25
+ if (typeof value === 'bigint') {
26
+ return value.toString() + 'n'
27
+ }
28
+ return value
29
+ },
30
+ space
31
+ )
32
+ },
33
+
34
+ /**
35
+ * Parse a JSON string, converting strings ending with 'n' back to BigInt
36
+ */
37
+ parse: (text: string): any => {
38
+ return JSON.parse(text, (key, value) => {
39
+ if (typeof value === 'string' && /^\d+n$/.test(value)) {
40
+ return BigInt(value.slice(0, -1))
41
+ }
42
+ return value
43
+ })
44
+ },
45
+ }
46
+
47
+ export default JSONbigString