@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,212 @@
1
+ import {
2
+ type Abi,
3
+ type AbiFunction,
4
+ AbiFunctionSignatureNotFoundError,
5
+ type AbiParameter,
6
+ type Address,
7
+ type Chain,
8
+ createPublicClient,
9
+ type DecodeFunctionDataParameters,
10
+ decodeAbiParameters,
11
+ Hex,
12
+ http,
13
+ type PublicClient,
14
+ slice,
15
+ toFunctionSelector,
16
+ } from 'viem'
17
+ import { formatAbiItem } from 'viem/utils'
18
+ import type {
19
+ ArrayArgs,
20
+ AsyncOperations,
21
+ CustomDecodeFunctionDataReturn,
22
+ DecoderResult,
23
+ EnhancedInfo,
24
+ } from './types'
25
+
26
+ /**
27
+ * Custom decoder for function data with additional named args support
28
+ * It's essentially the same code as decodeFunctionData, but also
29
+ * returning a namedArgs where we zip together the args and the inputs.
30
+ */
31
+ export function customDecodeFunctionData<
32
+ const abi extends Abi | readonly unknown[],
33
+ preferError = false,
34
+ >(
35
+ parameters: Partial<
36
+ DecodeFunctionDataParameters<abi> & {
37
+ namedArgs?:
38
+ | Record<number, AbiParameter & { value?: unknown }>
39
+ | Record<string, unknown>
40
+ }
41
+ >,
42
+ preferError?: boolean
43
+ ) {
44
+ try {
45
+ const { abi, data } = parameters as DecodeFunctionDataParameters
46
+ const signature = slice(data, 0, 4)
47
+ const description: AbiFunction | undefined = (abi.find(
48
+ (x) =>
49
+ x.type === (preferError ? 'error' : 'function') &&
50
+ signature === toFunctionSelector(formatAbiItem(x))
51
+ ) || undefined) as AbiFunction | undefined
52
+ if (!description)
53
+ throw new AbiFunctionSignatureNotFoundError(signature, {
54
+ docsPath: '/docs/contract/decodeFunctionData',
55
+ })
56
+ const args = (
57
+ 'inputs' in description &&
58
+ description.inputs &&
59
+ description.inputs.length > 0
60
+ ? decodeAbiParameters(description.inputs, slice(data, 4))
61
+ : undefined
62
+ ) as readonly unknown[] | undefined
63
+ const result: {
64
+ functionName: string
65
+ sig: Hex
66
+ input: Hex
67
+ args?: ArrayArgs
68
+ } = {
69
+ functionName: (description as { name: string }).name,
70
+ sig: signature,
71
+ input: data,
72
+ }
73
+ if (args) {
74
+ const { args: namedArgs } = createNamedArgs(args, description.inputs)
75
+ result.args = namedArgs
76
+ }
77
+ return result as CustomDecodeFunctionDataReturn<abi>
78
+ } catch {}
79
+ }
80
+
81
+ export function createNamedArgs(
82
+ args: unknown[] | readonly unknown[],
83
+ inputs?: AbiParameter[] | readonly AbiParameter[]
84
+ ): { args: ArrayArgs } {
85
+ const array = args.map((value, index) => {
86
+ return {
87
+ name: `args${index + 1}`,
88
+ ...inputs?.[index],
89
+ value,
90
+ } as AbiParameter & { value: unknown }
91
+ })
92
+ return { args: array }
93
+ }
94
+
95
+ /**
96
+ * Get an argument value by its name from the args array.
97
+ * This utility function allows accessing arguments by name without needing namedArgs.
98
+ *
99
+ * @param args - The array of arguments with their metadata
100
+ * @param name - The name of the argument to find
101
+ * @returns The value of the argument if found, undefined otherwise
102
+ */
103
+ export function getArgByName(
104
+ args: ArrayArgs | undefined,
105
+ name: string
106
+ ): unknown {
107
+ if (!args) return undefined
108
+
109
+ const arg = args.find((arg) => arg.name === name)
110
+ return arg?.value
111
+ }
112
+
113
+ export function extractAddress(address?: Address | EnhancedInfo) {
114
+ if (typeof address === 'object') {
115
+ return address.address
116
+ }
117
+ return address
118
+ }
119
+
120
+ const clients: Record<number, PublicClient> = {} as Record<number, PublicClient>
121
+ export function getPublicClient(chain: Chain): PublicClient {
122
+ const { id } = chain
123
+ if (!id) {
124
+ throw new Error('Chain ID is required to create a public client')
125
+ }
126
+ if (!clients[id]) {
127
+ clients[id] = createPublicClient({
128
+ chain,
129
+ transport: http(),
130
+ batch: {
131
+ multicall: {
132
+ batchSize: 100,
133
+ },
134
+ },
135
+ })
136
+ }
137
+ const result = clients[id]
138
+ if (!result) {
139
+ throw new Error(`Public client for chain ID ${id} not found`)
140
+ }
141
+ return result
142
+ }
143
+
144
+ /**
145
+ * Helper to check if a specific async operation is enabled
146
+ */
147
+ export function isAsyncOperationEnabled(
148
+ asyncOption: boolean | AsyncOperations | undefined,
149
+ operation: AsyncOperations
150
+ ): boolean {
151
+ // Handle backward compatibility
152
+ if (typeof asyncOption === 'boolean') {
153
+ return asyncOption
154
+ }
155
+ // If not specified, default to DISABLED
156
+ if (asyncOption === undefined) {
157
+ return false
158
+ }
159
+ // Check bitmap
160
+ return (asyncOption & operation) !== 0
161
+ }
162
+
163
+ /**
164
+ * Check if a single decoded item needs enhancement
165
+ * @param item - A single decoded result (not checking children)
166
+ * @returns true if this specific item needs enhancement
167
+ */
168
+ function needsEnhancementSingle(item: DecoderResult): boolean {
169
+ // If sig is "0x", there's no function signature to decode
170
+ if ('sig' in item && item.sig === '0x') {
171
+ return false
172
+ }
173
+
174
+ // If it has a standard, it's already identified
175
+ if (item.standard) {
176
+ return false
177
+ }
178
+
179
+ // Otherwise it needs enhancement
180
+ return true
181
+ }
182
+
183
+ /**
184
+ * Check if a decoded result needs enhancement
185
+ * Returns true if the result OR any of its children need enhancement
186
+ */
187
+ export function needsEnhancement(result: DecoderResult): boolean {
188
+ // Check if the main result needs enhancement
189
+ if (needsEnhancementSingle(result)) {
190
+ return true
191
+ }
192
+
193
+ // Check if any children need enhancement
194
+ if ('children' in result && Array.isArray(result.children)) {
195
+ return result.children.some((child) => {
196
+ // Children might be ResultType or ResultSetData, which don't have all DecoderResult fields
197
+ // We only check for standard property which is common to all
198
+ if (child.standard) {
199
+ return false
200
+ }
201
+ // If sig is "0x", there's no function signature to decode
202
+ if ('sig' in child && child.sig === '0x') {
203
+ return false
204
+ }
205
+ // Otherwise it needs enhancement
206
+ return true
207
+ })
208
+ }
209
+
210
+ // Nothing needs enhancement
211
+ return false
212
+ }
@@ -0,0 +1,172 @@
1
+ import debug from 'debug'
2
+ import type { Transaction } from 'viem'
3
+ import { lukso } from 'viem/chains'
4
+ import { createDataModel } from '../data'
5
+ import {
6
+ AddressResolver,
7
+ createMemoryAddressCache,
8
+ DecoderIntegration,
9
+ DecoderResult,
10
+ } from '../index'
11
+
12
+ const setupDecoderLog = debug('app:setupDecoder')
13
+
14
+ /**
15
+ * Example of how to connect all the decoder pieces together
16
+ */
17
+ export async function setupDecoder() {
18
+ // 1. Create data model with callbacks
19
+ const dataModel = createDataModel({
20
+ onMissingKeys: (keys) => {
21
+ setupDecoderLog('Missing address data for:', keys)
22
+ // Could trigger address resolution here
23
+ },
24
+ onNewTransaction: (tx) => {
25
+ setupDecoderLog('New transaction added:', tx)
26
+ },
27
+ })
28
+
29
+ // 2. Create address cache (could be IndexedDB, localStorage, etc)
30
+ const addressCache = createMemoryAddressCache()
31
+
32
+ // Alternative: Create IndexedDB cache
33
+ // const addressCache = createIndexedDBCache('decoder-addresses')
34
+
35
+ // 3. Create decoder integration
36
+ const decoder = new DecoderIntegration({
37
+ dataModel,
38
+ decoderOptions: {
39
+ chain: lukso,
40
+ preferError: false,
41
+ },
42
+ addressCache,
43
+ })
44
+
45
+ // 4. Create address resolver for GraphQL
46
+ const addressResolver = new AddressResolver({
47
+ dataModel,
48
+ graphqlEndpoint: 'https://api.universalprofile.cloud/graphql',
49
+ chain: lukso,
50
+ batchSize: 50,
51
+ batchDelay: 100,
52
+ })
53
+
54
+ // 5. Start watching for missing addresses
55
+ addressResolver.startWatching()
56
+
57
+ return {
58
+ dataModel,
59
+ decoder,
60
+ addressResolver,
61
+ addressCache,
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Example of adding and decoding transactions
67
+ */
68
+ export async function handleTransaction(tx: DecoderResult) {
69
+ const { decoder } = await setupDecoder()
70
+
71
+ // Add and decode transaction
72
+ const signal = await decoder.addAndDecodeTransaction(tx)
73
+
74
+ // React to updates
75
+ signal.subscribe((state) => {
76
+ setupDecoderLog('Transaction state updated:', {
77
+ loading: state.loading,
78
+ decodingStatus: state.decodingStatus,
79
+ addresses: state.addresses,
80
+ data: state.data,
81
+ })
82
+ })
83
+
84
+ // Get immediate data
85
+ const currentState = signal.value
86
+ setupDecoderLog('Current transaction data:', currentState.data)
87
+
88
+ return signal
89
+ }
90
+
91
+ /**
92
+ * Example of batch processing
93
+ */
94
+ export async function handleTransactionBatch(transactions: DecoderResult[]) {
95
+ const { decoder, dataModel } = await setupDecoder()
96
+
97
+ // Add and decode all transactions
98
+ const signals = await decoder.addAndDecodeTransactions(transactions)
99
+
100
+ // Monitor overall progress
101
+ let completed = 0
102
+ for (const signal of signals) {
103
+ signal.subscribe((state) => {
104
+ if (
105
+ state.decodingStatus === 'complete' ||
106
+ state.decodingStatus === 'failed'
107
+ ) {
108
+ completed++
109
+ setupDecoderLog(`Progress: ${completed}/${transactions.length}`)
110
+ }
111
+ })
112
+ }
113
+
114
+ // Get all transaction data
115
+ const allTransactions = dataModel.getAllTransactions()
116
+ setupDecoderLog('All transactions:', allTransactions)
117
+
118
+ return signals
119
+ }
120
+
121
+ /**
122
+ * Example of manual address resolution
123
+ */
124
+ export async function resolveAddresses() {
125
+ const { dataModel, decoder } = await setupDecoder()
126
+
127
+ // Get missing addresses
128
+ const missing = decoder.getMissingAddresses()
129
+ setupDecoderLog('Missing addresses:', missing)
130
+
131
+ // Manually fetch and inject address data
132
+ // (normally handled by AddressResolver automatically)
133
+ const addressData = await fetchAddressDataFromAPI(missing)
134
+ await decoder.loadAddressData(addressData)
135
+
136
+ // Check if all resolved
137
+ const stillMissing = decoder.getMissingAddresses()
138
+ setupDecoderLog('Still missing:', stillMissing)
139
+ }
140
+
141
+ // Mock function for example
142
+ async function fetchAddressDataFromAPI(addresses: unknown[]) {
143
+ // This would be your actual API call
144
+ return []
145
+ }
146
+
147
+ /**
148
+ * Example of using with a UI framework (e.g., Vue)
149
+ */
150
+ export function useInVueComponent() {
151
+ // In a Vue component
152
+ /*
153
+ import { computed, onMounted } from 'vue'
154
+ import { getAddress, getTransaction } from '@lukso/decoder'
155
+
156
+ export default {
157
+ props: ['address', 'txHash'],
158
+ setup(props) {
159
+ const addressSignal = getAddress(props.address)
160
+ const txSignal = getTransaction({ hash: props.txHash })
161
+
162
+ const addressName = computed(() => addressSignal.value.data?.name || 'Unknown')
163
+ const txStatus = computed(() => txSignal?.value.decodingStatus || 'loading')
164
+
165
+ return {
166
+ addressName,
167
+ txStatus
168
+ }
169
+ }
170
+ }
171
+ */
172
+ }
package/src/index.ts ADDED
@@ -0,0 +1,174 @@
1
+ /**
2
+ * @lukso/decoder - Consumer API
3
+ *
4
+ * This is the main entry point for consumers of the decoder.
5
+ * Import data provider functions from '@lukso/transaction-decoder/data' instead.
6
+ */
7
+
8
+ import { consumerModel, createGlobalInstance } from './core/instance'
9
+
10
+ // Export all types that consumers need
11
+ export type {
12
+ AddressState,
13
+ DataKey,
14
+ EnhancedInfo,
15
+ IDataModelConsumer,
16
+ TransactionState,
17
+ } from './types'
18
+ // DecoderResult is exported from decoder/types via the decoder imports below
19
+
20
+ // Export all consumer methods directly
21
+ export const getTransaction = consumerModel.getTransaction.bind(consumerModel)
22
+ export const getTransactionByKey =
23
+ consumerModel.getTransactionByKey.bind(consumerModel)
24
+ export const getTransactionsByIndex =
25
+ consumerModel.getTransactionsByIndex.bind(consumerModel)
26
+ export const getTransactionHashByIndex =
27
+ consumerModel.getTransactionHashByIndex.bind(consumerModel)
28
+ export const getTransactionCount =
29
+ consumerModel.getTransactionCount.bind(consumerModel)
30
+ export const getDecodedCount = consumerModel.getDecodedCount.bind(consumerModel)
31
+ export const getDecodedTransactions =
32
+ consumerModel.getDecodedTransactions.bind(consumerModel)
33
+ export const getTransactionsInOrder =
34
+ consumerModel.getTransactionsInOrder.bind(consumerModel)
35
+
36
+ // Address methods
37
+ export const getAddress = consumerModel.getAddress.bind(consumerModel)
38
+ export const getSignal = consumerModel.getSignal.bind(consumerModel)
39
+ export const subscribe = consumerModel.subscribe.bind(consumerModel)
40
+ export const getState = consumerModel.getState.bind(consumerModel)
41
+ export const hasData = consumerModel.hasData.bind(consumerModel)
42
+ export const getData = consumerModel.getData.bind(consumerModel)
43
+ export const isLoading = consumerModel.isLoading.bind(consumerModel)
44
+ export const getError = consumerModel.getError.bind(consumerModel)
45
+
46
+ // Collection methods
47
+ export const getAllKeys = consumerModel.getAllKeys.bind(consumerModel)
48
+ export const getAllData = consumerModel.getAllData.bind(consumerModel)
49
+ export const getAllTransactions =
50
+ consumerModel.getAllTransactions.bind(consumerModel)
51
+
52
+ // Also export the consumer model instance for advanced usage
53
+ export { consumerModel }
54
+
55
+ // Export the function to create global instance (for manual setup)
56
+ export { createGlobalInstance }
57
+
58
+ // Export client utilities
59
+ export {
60
+ createApiAddressResolver,
61
+ type ResolveAddressesOptions,
62
+ type ResolveAddressesResponse,
63
+ resolveAddresses,
64
+ } from './client/resolveAddresses'
65
+ // Export address collection utilities from core
66
+ export { collectDataKeys } from './core/addressCollector'
67
+ export {
68
+ AddressResolver,
69
+ type AddressResolverConfig,
70
+ } from './core/addressResolver'
71
+ // Export integration classes
72
+ export {
73
+ type AddressCache,
74
+ createMemoryAddressCache,
75
+ DecoderIntegration,
76
+ type DecoderIntegrationConfig,
77
+ } from './core/integrateDecoder'
78
+ // Export aggregation utilities
79
+ export {
80
+ type AggregationState,
81
+ PluginAggregationEngine,
82
+ standardAggregation,
83
+ } from './decoder/aggregation'
84
+ export type {
85
+ AddressResolver as TransactionAddressResolver,
86
+ TransactionDecoderResult,
87
+ } from './decoder/decodeTransaction'
88
+ // Export decoder integration utilities
89
+ export {
90
+ decodeTransaction,
91
+ decodeTransactionAsync,
92
+ } from './decoder/decodeTransaction'
93
+ // Export plugin development utilities
94
+ // Export default plugins to ensure they're imported and register themselves
95
+ export {
96
+ createAggregationKey,
97
+ defaultPlugins,
98
+ defaultSchemaPlugins,
99
+ standardPlugin,
100
+ standardSchemaPlugin,
101
+ } from './decoder/plugins'
102
+ export type {
103
+ PluginMetadata,
104
+ SchemaPluginMetadata,
105
+ } from './decoder/registry'
106
+ export {
107
+ createNamedPlugin,
108
+ createNamedSchemaPlugin,
109
+ pluginRegistry,
110
+ registerPlugin,
111
+ registerSchemaPlugin,
112
+ } from './decoder/registry'
113
+ export type {
114
+ Aggregation,
115
+ DecodeEventCallback,
116
+ DecodeEventResult,
117
+ DecoderPlugin,
118
+ DecoderResult,
119
+ EnhancerCallback,
120
+ PluginOptions,
121
+ ResultAggregate,
122
+ ResultCreate,
123
+ ResultError,
124
+ ResultExecute,
125
+ ResultExecuteBatch,
126
+ ResultFollowProfile,
127
+ ResultGrafitti,
128
+ ResultRaw,
129
+ ResultSetData,
130
+ ResultSetDataBatch,
131
+ ResultWrapper,
132
+ SchemaPlugin,
133
+ } from './decoder/types'
134
+ // Export utility functions
135
+ export { getArgByName, needsEnhancement } from './decoder/utils'
136
+ // Export LSP23 deployment resolver utilities
137
+ // Note: Actual Hypersync querying should be done via wallet-app API to protect HYPERSYNC_TOKEN
138
+ export {
139
+ buildLSP23DeploymentQuery,
140
+ DEPLOY_ERC1167_PROXIES_SELECTOR,
141
+ decodeDeploymentCalldata,
142
+ decodeDeploymentOutput,
143
+ extractControllersFromInitCalldata,
144
+ type HypersyncQueryConfig,
145
+ LSP23_FACTORY_ADDRESS,
146
+ type LSP23DeploymentData,
147
+ parseLSP23DeploymentsFromHypersync,
148
+ } from './server/lsp23Resolver'
149
+ // Export shared address resolver utilities
150
+ export {
151
+ type AssetData,
152
+ fetchMultipleAddresses,
153
+ fetchProfilesByControllers,
154
+ getGraphQLEndpoint,
155
+ getImage,
156
+ type ImageData,
157
+ type ImageURL,
158
+ type LinkData,
159
+ type ProfileData,
160
+ type TFetchAddressData,
161
+ type TokenData,
162
+ } from './shared/addressResolver'
163
+ // Export cache utilities
164
+ export {
165
+ type AddressIdentityCache,
166
+ createMemoryAddressIdentityCache,
167
+ dataKeyToString,
168
+ getDataKeyCacheKey,
169
+ parseDataKey,
170
+ } from './shared/cache'
171
+ // Export debug utility for edge/worker environments
172
+ export { createDebug } from './utils/debug'
173
+ // Export JSON BigInt serializer/deserializer
174
+ export { JSONbigString } from './utils/json-bigint'
@@ -0,0 +1,68 @@
1
+ import type { Chain } from 'viem'
2
+ import { fetchMultipleAddresses } from '../shared/addressResolver'
3
+ import type { AddressIdentityCache } from '../shared/cache'
4
+ import type { DataKey, EnhancedInfo } from '../types'
5
+ import type { ServerDecoderCaches } from './caches'
6
+
7
+ /**
8
+ * Server-side address resolver with caching
9
+ */
10
+ export class ServerAddressResolver {
11
+ private cacheAdapter: AddressIdentityCache
12
+
13
+ constructor(
14
+ private graphqlEndpoint: string,
15
+ private chain: Chain,
16
+ private caches: ServerDecoderCaches
17
+ ) {
18
+ // Create adapter to use ServerDecoderCaches as AddressIdentityCache
19
+ this.cacheAdapter = {
20
+ get: (key: DataKey) => this.caches.getAddress(key),
21
+ set: (key: DataKey, value: EnhancedInfo) =>
22
+ this.caches.setAddress(key, value),
23
+ has: (key: DataKey) => this.caches.hasAddress(key),
24
+ getMany: (keys: DataKey[]) => this.caches.getAddresses(keys),
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Resolve addresses, using cache when possible
30
+ */
31
+ async resolveAddresses(
32
+ addresses: readonly DataKey[]
33
+ ): Promise<Map<DataKey, EnhancedInfo>> {
34
+ // Use the shared implementation with cache adapter
35
+ return fetchMultipleAddresses(
36
+ addresses,
37
+ this.graphqlEndpoint,
38
+ this.cacheAdapter
39
+ )
40
+ }
41
+
42
+ /**
43
+ * Resolve addresses with timeout
44
+ */
45
+ async resolveAddressesWithTimeout(
46
+ addresses: DataKey[],
47
+ timeoutMs: number
48
+ ): Promise<Map<DataKey, EnhancedInfo>> {
49
+ return Promise.race([
50
+ this.resolveAddresses(addresses),
51
+ new Promise<Map<DataKey, EnhancedInfo>>((resolve) => {
52
+ setTimeout(() => {
53
+ // On timeout, return whatever we have cached
54
+ const results = this.caches.getAddresses(addresses)
55
+ resolve(results)
56
+ }, timeoutMs)
57
+ }),
58
+ ])
59
+ }
60
+
61
+ /**
62
+ * Warm the cache with specific addresses
63
+ */
64
+ async warmCache(addresses: DataKey[]): Promise<void> {
65
+ // Simply call resolveAddresses which will cache any uncached addresses
66
+ await this.resolveAddresses(addresses)
67
+ }
68
+ }