@opendatalabs/vana-sdk 0.1.0-alpha.a6b60fc → 0.1.0-alpha.a78ce5c

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 (256) hide show
  1. package/dist/client/__tests__/enhancedResponse.test.d.ts +1 -0
  2. package/dist/client/enhancedResponse.cjs +164 -0
  3. package/dist/client/enhancedResponse.cjs.map +1 -0
  4. package/dist/client/enhancedResponse.d.ts +120 -0
  5. package/dist/client/enhancedResponse.js +138 -0
  6. package/dist/client/enhancedResponse.js.map +1 -0
  7. package/dist/controllers/__tests__/data-consistency-integration.test.d.ts +7 -0
  8. package/dist/controllers/__tests__/operations.processQueue.test.d.ts +1 -0
  9. package/dist/controllers/base.cjs +33 -0
  10. package/dist/controllers/base.cjs.map +1 -1
  11. package/dist/controllers/base.d.ts +10 -0
  12. package/dist/controllers/base.js +33 -0
  13. package/dist/controllers/base.js.map +1 -1
  14. package/dist/controllers/data.cjs +278 -159
  15. package/dist/controllers/data.cjs.map +1 -1
  16. package/dist/controllers/data.d.ts +34 -19
  17. package/dist/controllers/data.js +291 -162
  18. package/dist/controllers/data.js.map +1 -1
  19. package/dist/controllers/operations.cjs +430 -0
  20. package/dist/controllers/operations.cjs.map +1 -0
  21. package/dist/controllers/operations.d.ts +229 -0
  22. package/dist/controllers/operations.js +406 -0
  23. package/dist/controllers/operations.js.map +1 -0
  24. package/dist/controllers/permissions.cjs +605 -213
  25. package/dist/controllers/permissions.cjs.map +1 -1
  26. package/dist/controllers/permissions.d.ts +141 -34
  27. package/dist/controllers/permissions.js +605 -213
  28. package/dist/controllers/permissions.js.map +1 -1
  29. package/dist/controllers/schemas.cjs +81 -4
  30. package/dist/controllers/schemas.cjs.map +1 -1
  31. package/dist/controllers/schemas.d.ts +41 -0
  32. package/dist/controllers/schemas.js +81 -4
  33. package/dist/controllers/schemas.js.map +1 -1
  34. package/dist/controllers/server.cjs +251 -42
  35. package/dist/controllers/server.cjs.map +1 -1
  36. package/dist/controllers/server.d.ts +111 -14
  37. package/dist/controllers/server.js +251 -42
  38. package/dist/controllers/server.js.map +1 -1
  39. package/dist/core/__tests__/health.test.d.ts +1 -0
  40. package/dist/core/__tests__/inMemoryNonceManager.test.d.ts +1 -0
  41. package/dist/core/__tests__/nonceManager.test.d.ts +1 -0
  42. package/dist/core/__tests__/pollingManager.test.d.ts +4 -0
  43. package/dist/core/health.cjs +289 -0
  44. package/dist/core/health.cjs.map +1 -0
  45. package/dist/core/health.d.ts +143 -0
  46. package/dist/core/health.js +265 -0
  47. package/dist/core/health.js.map +1 -0
  48. package/dist/core/inMemoryNonceManager.cjs +138 -0
  49. package/dist/core/inMemoryNonceManager.cjs.map +1 -0
  50. package/dist/core/inMemoryNonceManager.d.ts +69 -0
  51. package/dist/core/inMemoryNonceManager.js +114 -0
  52. package/dist/core/inMemoryNonceManager.js.map +1 -0
  53. package/dist/core/nonceManager.cjs +304 -0
  54. package/dist/core/nonceManager.cjs.map +1 -0
  55. package/dist/core/nonceManager.d.ts +116 -0
  56. package/dist/core/nonceManager.js +280 -0
  57. package/dist/core/nonceManager.js.map +1 -0
  58. package/dist/core/pollingManager.cjs +292 -0
  59. package/dist/core/pollingManager.cjs.map +1 -0
  60. package/dist/core/pollingManager.d.ts +120 -0
  61. package/dist/core/pollingManager.js +268 -0
  62. package/dist/core/pollingManager.js.map +1 -0
  63. package/dist/core.cjs +55 -1
  64. package/dist/core.cjs.map +1 -1
  65. package/dist/core.d.ts +54 -3
  66. package/dist/core.js +55 -1
  67. package/dist/core.js.map +1 -1
  68. package/dist/crypto/ecies/base.cjs +16 -3
  69. package/dist/crypto/ecies/base.cjs.map +1 -1
  70. package/dist/crypto/ecies/base.js +16 -3
  71. package/dist/crypto/ecies/base.js.map +1 -1
  72. package/dist/errors.cjs +29 -0
  73. package/dist/errors.cjs.map +1 -1
  74. package/dist/errors.d.ts +64 -0
  75. package/dist/errors.js +28 -0
  76. package/dist/errors.js.map +1 -1
  77. package/dist/generated/abi/ComputeInstructionRegistryImplementation.cjs.map +1 -1
  78. package/dist/generated/abi/ComputeInstructionRegistryImplementation.js.map +1 -1
  79. package/dist/generated/abi/DLPPerformanceImplementation.cjs +42 -0
  80. package/dist/generated/abi/DLPPerformanceImplementation.cjs.map +1 -1
  81. package/dist/generated/abi/DLPPerformanceImplementation.d.ts +32 -0
  82. package/dist/generated/abi/DLPPerformanceImplementation.js +42 -0
  83. package/dist/generated/abi/DLPPerformanceImplementation.js.map +1 -1
  84. package/dist/generated/abi/DLPRegistryImplementation.cjs +5 -5
  85. package/dist/generated/abi/DLPRegistryImplementation.cjs.map +1 -1
  86. package/dist/generated/abi/DLPRegistryImplementation.d.ts +4 -4
  87. package/dist/generated/abi/DLPRegistryImplementation.js +5 -5
  88. package/dist/generated/abi/DLPRegistryImplementation.js.map +1 -1
  89. package/dist/generated/abi/DLPRewardDeployerImplementation.cjs +166 -2
  90. package/dist/generated/abi/DLPRewardDeployerImplementation.cjs.map +1 -1
  91. package/dist/generated/abi/DLPRewardDeployerImplementation.d.ts +129 -2
  92. package/dist/generated/abi/DLPRewardDeployerImplementation.js +166 -2
  93. package/dist/generated/abi/DLPRewardDeployerImplementation.js.map +1 -1
  94. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs +167 -19
  95. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs.map +1 -1
  96. package/dist/generated/abi/DataPortabilityGranteesImplementation.d.ts +127 -14
  97. package/dist/generated/abi/DataPortabilityGranteesImplementation.js +167 -19
  98. package/dist/generated/abi/DataPortabilityGranteesImplementation.js.map +1 -1
  99. package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs +0 -19
  100. package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs.map +1 -1
  101. package/dist/generated/abi/DataPortabilityPermissionsImplementation.d.ts +0 -14
  102. package/dist/generated/abi/DataPortabilityPermissionsImplementation.js +0 -19
  103. package/dist/generated/abi/DataPortabilityPermissionsImplementation.js.map +1 -1
  104. package/dist/generated/abi/DataPortabilityServersImplementation.cjs +0 -19
  105. package/dist/generated/abi/DataPortabilityServersImplementation.cjs.map +1 -1
  106. package/dist/generated/abi/DataPortabilityServersImplementation.d.ts +0 -14
  107. package/dist/generated/abi/DataPortabilityServersImplementation.js +0 -19
  108. package/dist/generated/abi/DataPortabilityServersImplementation.js.map +1 -1
  109. package/dist/generated/abi/DataRegistryImplementation.cjs +0 -13
  110. package/dist/generated/abi/DataRegistryImplementation.cjs.map +1 -1
  111. package/dist/generated/abi/DataRegistryImplementation.d.ts +0 -10
  112. package/dist/generated/abi/DataRegistryImplementation.js +0 -13
  113. package/dist/generated/abi/DataRegistryImplementation.js.map +1 -1
  114. package/dist/generated/abi/SwapHelperImplementation.cjs +0 -43
  115. package/dist/generated/abi/SwapHelperImplementation.cjs.map +1 -1
  116. package/dist/generated/abi/SwapHelperImplementation.d.ts +0 -35
  117. package/dist/generated/abi/SwapHelperImplementation.js +0 -43
  118. package/dist/generated/abi/SwapHelperImplementation.js.map +1 -1
  119. package/dist/generated/abi/VanaEpochImplementation.cjs +195 -0
  120. package/dist/generated/abi/VanaEpochImplementation.cjs.map +1 -1
  121. package/dist/generated/abi/VanaEpochImplementation.d.ts +151 -0
  122. package/dist/generated/abi/VanaEpochImplementation.js +195 -0
  123. package/dist/generated/abi/VanaEpochImplementation.js.map +1 -1
  124. package/dist/generated/abi/VanaPoolEntityImplementation.cjs +22 -65
  125. package/dist/generated/abi/VanaPoolEntityImplementation.cjs.map +1 -1
  126. package/dist/generated/abi/VanaPoolEntityImplementation.d.ts +17 -51
  127. package/dist/generated/abi/VanaPoolEntityImplementation.js +22 -65
  128. package/dist/generated/abi/VanaPoolEntityImplementation.js.map +1 -1
  129. package/dist/generated/abi/VanaPoolStakingImplementation.cjs +113 -1
  130. package/dist/generated/abi/VanaPoolStakingImplementation.cjs.map +1 -1
  131. package/dist/generated/abi/VanaPoolStakingImplementation.d.ts +85 -1
  132. package/dist/generated/abi/VanaPoolStakingImplementation.js +113 -1
  133. package/dist/generated/abi/VanaPoolStakingImplementation.js.map +1 -1
  134. package/dist/generated/abi/index.d.ts +546 -146
  135. package/dist/generated/event-types.cjs.map +1 -1
  136. package/dist/generated/event-types.d.ts +14 -8
  137. package/dist/generated/eventRegistry.cjs +42 -18
  138. package/dist/generated/eventRegistry.cjs.map +1 -1
  139. package/dist/generated/eventRegistry.js +42 -18
  140. package/dist/generated/eventRegistry.js.map +1 -1
  141. package/dist/generated/server/server-exports.cjs +22 -0
  142. package/dist/generated/server/server-exports.cjs.map +1 -1
  143. package/dist/generated/server/server-exports.d.ts +27 -10
  144. package/dist/generated/server/server-exports.js +17 -0
  145. package/dist/generated/server/server-exports.js.map +1 -1
  146. package/dist/generated/server/server.cjs.map +1 -1
  147. package/dist/generated/server/server.d.ts +771 -402
  148. package/dist/generated/subgraph.cjs +797 -32
  149. package/dist/generated/subgraph.cjs.map +1 -1
  150. package/dist/generated/subgraph.d.ts +135 -0
  151. package/dist/generated/subgraph.js +792 -32
  152. package/dist/generated/subgraph.js.map +1 -1
  153. package/dist/index.browser.d.ts +2 -0
  154. package/dist/index.browser.js +10 -0
  155. package/dist/index.browser.js.map +1 -1
  156. package/dist/index.node.cjs +26 -0
  157. package/dist/index.node.cjs.map +1 -1
  158. package/dist/index.node.d.ts +49 -5
  159. package/dist/index.node.js +25 -1
  160. package/dist/index.node.js.map +1 -1
  161. package/dist/lib/__tests__/redisAtomicStore.test.d.ts +1 -0
  162. package/dist/lib/redisAtomicStore.cjs +201 -0
  163. package/dist/lib/redisAtomicStore.cjs.map +1 -0
  164. package/dist/lib/redisAtomicStore.d.ts +120 -0
  165. package/dist/lib/redisAtomicStore.js +177 -0
  166. package/dist/lib/redisAtomicStore.js.map +1 -0
  167. package/dist/server/relayerHandler.cjs +313 -75
  168. package/dist/server/relayerHandler.cjs.map +1 -1
  169. package/dist/server/relayerHandler.d.ts +35 -2
  170. package/dist/server/relayerHandler.js +313 -75
  171. package/dist/server/relayerHandler.js.map +1 -1
  172. package/dist/storage/index.cjs +3 -0
  173. package/dist/storage/index.cjs.map +1 -1
  174. package/dist/storage/index.d.ts +1 -0
  175. package/dist/storage/index.js +2 -0
  176. package/dist/storage/index.js.map +1 -1
  177. package/dist/storage/providers/dropbox.cjs +237 -0
  178. package/dist/storage/providers/dropbox.cjs.map +1 -0
  179. package/dist/storage/providers/dropbox.d.ts +39 -0
  180. package/dist/storage/providers/dropbox.js +215 -0
  181. package/dist/storage/providers/dropbox.js.map +1 -0
  182. package/dist/storage/providers/dropbox.test.d.ts +1 -0
  183. package/dist/tests/data-upload-owner-validation.test.d.ts +1 -0
  184. package/dist/types/atomicStore.cjs +31 -0
  185. package/dist/types/atomicStore.cjs.map +1 -0
  186. package/dist/types/atomicStore.d.ts +236 -0
  187. package/dist/types/atomicStore.js +7 -0
  188. package/dist/types/atomicStore.js.map +1 -0
  189. package/dist/types/config.cjs.map +1 -1
  190. package/dist/types/config.d.ts +32 -0
  191. package/dist/types/config.js.map +1 -1
  192. package/dist/types/controller-context.cjs.map +1 -1
  193. package/dist/types/controller-context.d.ts +4 -1
  194. package/dist/types/data.cjs.map +1 -1
  195. package/dist/types/data.d.ts +7 -4
  196. package/dist/types/generics.cjs.map +1 -1
  197. package/dist/types/generics.d.ts +1 -1
  198. package/dist/types/index.cjs.map +1 -1
  199. package/dist/types/index.d.ts +6 -3
  200. package/dist/types/index.js.map +1 -1
  201. package/dist/types/operationStore.cjs +17 -0
  202. package/dist/types/operationStore.cjs.map +1 -0
  203. package/dist/types/operationStore.d.ts +171 -0
  204. package/dist/types/operationStore.js +1 -0
  205. package/dist/types/operationStore.js.map +1 -0
  206. package/dist/types/operations.cjs +3 -15
  207. package/dist/types/operations.cjs.map +1 -1
  208. package/dist/types/operations.d.ts +17 -42
  209. package/dist/types/operations.js +2 -13
  210. package/dist/types/operations.js.map +1 -1
  211. package/dist/types/options.cjs +17 -0
  212. package/dist/types/options.cjs.map +1 -0
  213. package/dist/types/options.d.ts +308 -0
  214. package/dist/types/options.js +1 -0
  215. package/dist/types/options.js.map +1 -0
  216. package/dist/types/permissions.cjs.map +1 -1
  217. package/dist/types/permissions.d.ts +4 -0
  218. package/dist/types/personal.cjs.map +1 -1
  219. package/dist/types/personal.d.ts +19 -0
  220. package/dist/types/relayer.cjs.map +1 -1
  221. package/dist/types/relayer.d.ts +53 -9
  222. package/dist/types/utils.cjs.map +1 -1
  223. package/dist/types/utils.d.ts +0 -49
  224. package/dist/utils/__tests__/chainQuery.test.d.ts +1 -0
  225. package/dist/utils/__tests__/subgraphConsistency.test.d.ts +4 -0
  226. package/dist/utils/__tests__/subgraphPagination.test.d.ts +4 -0
  227. package/dist/utils/chainQuery.cjs +107 -0
  228. package/dist/utils/chainQuery.cjs.map +1 -0
  229. package/dist/utils/chainQuery.d.ts +31 -0
  230. package/dist/utils/chainQuery.js +82 -0
  231. package/dist/utils/chainQuery.js.map +1 -0
  232. package/dist/utils/grantFiles.cjs +4 -1
  233. package/dist/utils/grantFiles.cjs.map +1 -1
  234. package/dist/utils/grantFiles.js +4 -1
  235. package/dist/utils/grantFiles.js.map +1 -1
  236. package/dist/utils/ipfs.cjs +2 -4
  237. package/dist/utils/ipfs.cjs.map +1 -1
  238. package/dist/utils/ipfs.d.ts +1 -1
  239. package/dist/utils/ipfs.js +2 -4
  240. package/dist/utils/ipfs.js.map +1 -1
  241. package/dist/utils/subgraphConsistency.cjs +184 -0
  242. package/dist/utils/subgraphConsistency.cjs.map +1 -0
  243. package/dist/utils/subgraphConsistency.d.ts +65 -0
  244. package/dist/utils/subgraphConsistency.js +155 -0
  245. package/dist/utils/subgraphConsistency.js.map +1 -0
  246. package/dist/utils/subgraphMetaCache.cjs +101 -0
  247. package/dist/utils/subgraphMetaCache.cjs.map +1 -0
  248. package/dist/utils/subgraphMetaCache.d.ts +56 -0
  249. package/dist/utils/subgraphMetaCache.js +76 -0
  250. package/dist/utils/subgraphMetaCache.js.map +1 -0
  251. package/dist/utils/subgraphPagination.cjs +104 -0
  252. package/dist/utils/subgraphPagination.cjs.map +1 -0
  253. package/dist/utils/subgraphPagination.d.ts +78 -0
  254. package/dist/utils/subgraphPagination.js +78 -0
  255. package/dist/utils/subgraphPagination.js.map +1 -0
  256. package/package.json +3 -1
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Atomic storage primitives for distributed state management.
3
+ *
4
+ * @module
5
+ */
6
+ /**
7
+ * Interface for atomic storage operations required by the SDK's distributed components.
8
+ *
9
+ * @remarks
10
+ * Implementations of this interface MUST guarantee atomicity for all operations.
11
+ * These primitives are used by the SDK's internal components to coordinate
12
+ * distributed state in multi-instance deployments (e.g., serverless functions).
13
+ *
14
+ * The SDK provides a reference Redis implementation, but you can implement
15
+ * this interface using any storage backend that supports atomic operations:
16
+ * - PostgreSQL with advisory locks
17
+ * - DynamoDB with conditional writes
18
+ * - MongoDB with findAndModify
19
+ * - Zookeeper or etcd for coordination
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Using the Redis reference implementation
24
+ * import { RedisAtomicStore } from './lib/redisAtomicStore';
25
+ *
26
+ * const atomicStore = new RedisAtomicStore({
27
+ * redis: process.env.REDIS_URL
28
+ * });
29
+ *
30
+ * const vana = Vana({
31
+ * privateKey: process.env.RELAYER_PRIVATE_KEY,
32
+ * atomicStore
33
+ * });
34
+ * ```
35
+ *
36
+ * @category Storage
37
+ */
38
+ export interface IAtomicStore {
39
+ /**
40
+ * Atomically increments a counter and returns the new value.
41
+ *
42
+ * @remarks
43
+ * This operation MUST be atomic. If the key doesn't exist, it should be
44
+ * initialized to 0 before incrementing. The operation must return the
45
+ * value after incrementing.
46
+ *
47
+ * This is used primarily for nonce assignment where atomicity is critical
48
+ * to prevent conflicts under concurrent load.
49
+ *
50
+ * @param key - The key to increment
51
+ * @returns The new value after incrementing
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // First call returns 1
56
+ * const nonce1 = await store.incr('nonce:0x123:1480');
57
+ * // Second call returns 2
58
+ * const nonce2 = await store.incr('nonce:0x123:1480');
59
+ * ```
60
+ */
61
+ incr(key: string): Promise<number>;
62
+ /**
63
+ * Attempts to acquire a distributed lock with automatic expiration.
64
+ *
65
+ * @remarks
66
+ * This operation MUST be atomic and follow the "SET NX EX" semantics:
67
+ * - Only succeeds if the lock doesn't exist (NX - "Not eXists")
68
+ * - Automatically expires after the specified TTL (EX - "EXpire")
69
+ * - Returns a unique lock ID on success for safe release
70
+ *
71
+ * The lock ID should be a unique value (e.g., UUID or timestamp+random)
72
+ * that prevents accidental release by other processes.
73
+ *
74
+ * @param key - The lock key
75
+ * @param ttlSeconds - Time-to-live in seconds (automatic expiration)
76
+ * @returns A unique lock ID if acquired, null if lock is already held
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const lockId = await store.acquireLock('nonce:lock:0x123', 5);
81
+ * if (lockId) {
82
+ * try {
83
+ * // Critical section - only one process can be here
84
+ * await performCriticalOperation();
85
+ * } finally {
86
+ * await store.releaseLock('nonce:lock:0x123', lockId);
87
+ * }
88
+ * }
89
+ * ```
90
+ */
91
+ acquireLock(key: string, ttlSeconds: number): Promise<string | null>;
92
+ /**
93
+ * Releases a previously acquired lock.
94
+ *
95
+ * @remarks
96
+ * This operation MUST be atomic and safe. It should only succeed if the
97
+ * provided lockId matches the current lock value. This prevents accidental
98
+ * release of locks acquired by other processes.
99
+ *
100
+ * Implementations should use compare-and-delete semantics or a Lua script
101
+ * (in Redis) to ensure atomicity.
102
+ *
103
+ * @param key - The lock key
104
+ * @param lockId - The unique ID returned by acquireLock
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * const lockId = await store.acquireLock('lock:key', 5);
109
+ * if (lockId) {
110
+ * // ... do work ...
111
+ * await store.releaseLock('lock:key', lockId);
112
+ * }
113
+ * ```
114
+ */
115
+ releaseLock(key: string, lockId: string): Promise<void>;
116
+ /**
117
+ * Gets the value associated with a key.
118
+ *
119
+ * @remarks
120
+ * This is a simple read operation. It should return null if the key
121
+ * doesn't exist.
122
+ *
123
+ * @param key - The key to retrieve
124
+ * @returns The stored value, or null if not found
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const lastUsedNonce = await store.get('lastNonce:0x123:1480');
129
+ * ```
130
+ */
131
+ get(key: string): Promise<string | null>;
132
+ /**
133
+ * Sets a key-value pair.
134
+ *
135
+ * @remarks
136
+ * This is a simple write operation. It should overwrite any existing value.
137
+ *
138
+ * @param key - The key to set
139
+ * @param value - The value to store
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * await store.set('lastNonce:0x123:1480', '42');
144
+ * ```
145
+ */
146
+ set(key: string, value: string): Promise<void>;
147
+ /**
148
+ * Sets a key-value pair with expiration.
149
+ *
150
+ * @remarks
151
+ * This operation sets a value with automatic expiration after the specified TTL.
152
+ * Useful for temporary state that should be automatically cleaned up.
153
+ *
154
+ * @param key - The key to set
155
+ * @param value - The value to store
156
+ * @param ttlSeconds - Time-to-live in seconds
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * // Store operation state for 24 hours
161
+ * await store.setWithTTL('operation:123', JSON.stringify(state), 86400);
162
+ * ```
163
+ */
164
+ setWithTTL?(key: string, value: string, ttlSeconds: number): Promise<void>;
165
+ /**
166
+ * Deletes a key.
167
+ *
168
+ * @remarks
169
+ * This operation removes a key from storage. Should be idempotent
170
+ * (no error if key doesn't exist).
171
+ *
172
+ * @param key - The key to delete
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * await store.delete('temp:data:123');
177
+ * ```
178
+ */
179
+ delete?(key: string): Promise<void>;
180
+ /**
181
+ * Executes an atomic script (e.g., Lua in Redis, stored procedure in SQL).
182
+ *
183
+ * @remarks
184
+ * This is an optional method that allows execution of atomic scripts
185
+ * for complex operations that require multiple steps to be atomic.
186
+ * Not all stores support this - simple stores may omit it.
187
+ *
188
+ * For Redis: executes a Lua script
189
+ * For PostgreSQL: executes a stored procedure or CTE
190
+ * For DynamoDB: might use TransactWrite
191
+ *
192
+ * @param script - The script to execute
193
+ * @param keys - Array of keys the script will operate on
194
+ * @param args - Array of arguments to pass to the script
195
+ * @returns The script's return value
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * const result = await store.eval(
200
+ * 'return redis.call("INCR", KEYS[1])',
201
+ * ['counter:users'],
202
+ * []
203
+ * );
204
+ * ```
205
+ */
206
+ eval?(script: string, keys: string[], args: string[]): Promise<any>;
207
+ }
208
+ /**
209
+ * Extended atomic store interface with nonce support.
210
+ *
211
+ * @remarks
212
+ * Some atomic stores (like Redis) provide optimized atomic nonce assignment
213
+ * through native scripting capabilities. This interface extends the base
214
+ * IAtomicStore with this optional optimization.
215
+ *
216
+ * @internal
217
+ */
218
+ export interface IAtomicStoreWithNonceSupport extends IAtomicStore {
219
+ /**
220
+ * Atomically assigns a nonce with gap prevention.
221
+ *
222
+ * @param key - The storage key for the last used nonce
223
+ * @param pendingCount - The current pending transaction count from blockchain
224
+ * @returns The assigned nonce
225
+ */
226
+ atomicAssignNonce(key: string, pendingCount: number): Promise<number>;
227
+ }
228
+ /**
229
+ * Type guard to check if an atomic store supports optimized nonce assignment.
230
+ *
231
+ * @param store - The atomic store to check
232
+ * @returns True if the store supports atomicAssignNonce
233
+ *
234
+ * @internal
235
+ */
236
+ export declare function hasNonceSupport(store: IAtomicStore): store is IAtomicStoreWithNonceSupport;
@@ -0,0 +1,7 @@
1
+ function hasNonceSupport(store) {
2
+ return "atomicAssignNonce" in store && typeof store.atomicAssignNonce === "function";
3
+ }
4
+ export {
5
+ hasNonceSupport
6
+ };
7
+ //# sourceMappingURL=atomicStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/atomicStore.ts"],"sourcesContent":["/**\n * Atomic storage primitives for distributed state management.\n *\n * @module\n */\n\n/**\n * Interface for atomic storage operations required by the SDK's distributed components.\n *\n * @remarks\n * Implementations of this interface MUST guarantee atomicity for all operations.\n * These primitives are used by the SDK's internal components to coordinate\n * distributed state in multi-instance deployments (e.g., serverless functions).\n *\n * The SDK provides a reference Redis implementation, but you can implement\n * this interface using any storage backend that supports atomic operations:\n * - PostgreSQL with advisory locks\n * - DynamoDB with conditional writes\n * - MongoDB with findAndModify\n * - Zookeeper or etcd for coordination\n *\n * @example\n * ```typescript\n * // Using the Redis reference implementation\n * import { RedisAtomicStore } from './lib/redisAtomicStore';\n *\n * const atomicStore = new RedisAtomicStore({\n * redis: process.env.REDIS_URL\n * });\n *\n * const vana = Vana({\n * privateKey: process.env.RELAYER_PRIVATE_KEY,\n * atomicStore\n * });\n * ```\n *\n * @category Storage\n */\nexport interface IAtomicStore {\n /**\n * Atomically increments a counter and returns the new value.\n *\n * @remarks\n * This operation MUST be atomic. If the key doesn't exist, it should be\n * initialized to 0 before incrementing. The operation must return the\n * value after incrementing.\n *\n * This is used primarily for nonce assignment where atomicity is critical\n * to prevent conflicts under concurrent load.\n *\n * @param key - The key to increment\n * @returns The new value after incrementing\n *\n * @example\n * ```typescript\n * // First call returns 1\n * const nonce1 = await store.incr('nonce:0x123:1480');\n * // Second call returns 2\n * const nonce2 = await store.incr('nonce:0x123:1480');\n * ```\n */\n incr(key: string): Promise<number>;\n\n /**\n * Attempts to acquire a distributed lock with automatic expiration.\n *\n * @remarks\n * This operation MUST be atomic and follow the \"SET NX EX\" semantics:\n * - Only succeeds if the lock doesn't exist (NX - \"Not eXists\")\n * - Automatically expires after the specified TTL (EX - \"EXpire\")\n * - Returns a unique lock ID on success for safe release\n *\n * The lock ID should be a unique value (e.g., UUID or timestamp+random)\n * that prevents accidental release by other processes.\n *\n * @param key - The lock key\n * @param ttlSeconds - Time-to-live in seconds (automatic expiration)\n * @returns A unique lock ID if acquired, null if lock is already held\n *\n * @example\n * ```typescript\n * const lockId = await store.acquireLock('nonce:lock:0x123', 5);\n * if (lockId) {\n * try {\n * // Critical section - only one process can be here\n * await performCriticalOperation();\n * } finally {\n * await store.releaseLock('nonce:lock:0x123', lockId);\n * }\n * }\n * ```\n */\n acquireLock(key: string, ttlSeconds: number): Promise<string | null>;\n\n /**\n * Releases a previously acquired lock.\n *\n * @remarks\n * This operation MUST be atomic and safe. It should only succeed if the\n * provided lockId matches the current lock value. This prevents accidental\n * release of locks acquired by other processes.\n *\n * Implementations should use compare-and-delete semantics or a Lua script\n * (in Redis) to ensure atomicity.\n *\n * @param key - The lock key\n * @param lockId - The unique ID returned by acquireLock\n *\n * @example\n * ```typescript\n * const lockId = await store.acquireLock('lock:key', 5);\n * if (lockId) {\n * // ... do work ...\n * await store.releaseLock('lock:key', lockId);\n * }\n * ```\n */\n releaseLock(key: string, lockId: string): Promise<void>;\n\n /**\n * Gets the value associated with a key.\n *\n * @remarks\n * This is a simple read operation. It should return null if the key\n * doesn't exist.\n *\n * @param key - The key to retrieve\n * @returns The stored value, or null if not found\n *\n * @example\n * ```typescript\n * const lastUsedNonce = await store.get('lastNonce:0x123:1480');\n * ```\n */\n get(key: string): Promise<string | null>;\n\n /**\n * Sets a key-value pair.\n *\n * @remarks\n * This is a simple write operation. It should overwrite any existing value.\n *\n * @param key - The key to set\n * @param value - The value to store\n *\n * @example\n * ```typescript\n * await store.set('lastNonce:0x123:1480', '42');\n * ```\n */\n set(key: string, value: string): Promise<void>;\n\n /**\n * Sets a key-value pair with expiration.\n *\n * @remarks\n * This operation sets a value with automatic expiration after the specified TTL.\n * Useful for temporary state that should be automatically cleaned up.\n *\n * @param key - The key to set\n * @param value - The value to store\n * @param ttlSeconds - Time-to-live in seconds\n *\n * @example\n * ```typescript\n * // Store operation state for 24 hours\n * await store.setWithTTL('operation:123', JSON.stringify(state), 86400);\n * ```\n */\n setWithTTL?(key: string, value: string, ttlSeconds: number): Promise<void>;\n\n /**\n * Deletes a key.\n *\n * @remarks\n * This operation removes a key from storage. Should be idempotent\n * (no error if key doesn't exist).\n *\n * @param key - The key to delete\n *\n * @example\n * ```typescript\n * await store.delete('temp:data:123');\n * ```\n */\n delete?(key: string): Promise<void>;\n\n /**\n * Executes an atomic script (e.g., Lua in Redis, stored procedure in SQL).\n *\n * @remarks\n * This is an optional method that allows execution of atomic scripts\n * for complex operations that require multiple steps to be atomic.\n * Not all stores support this - simple stores may omit it.\n *\n * For Redis: executes a Lua script\n * For PostgreSQL: executes a stored procedure or CTE\n * For DynamoDB: might use TransactWrite\n *\n * @param script - The script to execute\n * @param keys - Array of keys the script will operate on\n * @param args - Array of arguments to pass to the script\n * @returns The script's return value\n *\n * @example\n * ```typescript\n * const result = await store.eval(\n * 'return redis.call(\"INCR\", KEYS[1])',\n * ['counter:users'],\n * []\n * );\n * ```\n */\n eval?(script: string, keys: string[], args: string[]): Promise<any>;\n}\n\n/**\n * Extended atomic store interface with nonce support.\n *\n * @remarks\n * Some atomic stores (like Redis) provide optimized atomic nonce assignment\n * through native scripting capabilities. This interface extends the base\n * IAtomicStore with this optional optimization.\n *\n * @internal\n */\nexport interface IAtomicStoreWithNonceSupport extends IAtomicStore {\n /**\n * Atomically assigns a nonce with gap prevention.\n *\n * @param key - The storage key for the last used nonce\n * @param pendingCount - The current pending transaction count from blockchain\n * @returns The assigned nonce\n */\n atomicAssignNonce(key: string, pendingCount: number): Promise<number>;\n}\n\n/**\n * Type guard to check if an atomic store supports optimized nonce assignment.\n *\n * @param store - The atomic store to check\n * @returns True if the store supports atomicAssignNonce\n *\n * @internal\n */\nexport function hasNonceSupport(\n store: IAtomicStore,\n): store is IAtomicStoreWithNonceSupport {\n return (\n \"atomicAssignNonce\" in store &&\n typeof (store as IAtomicStoreWithNonceSupport).atomicAssignNonce ===\n \"function\"\n );\n}\n"],"mappings":"AAqPO,SAAS,gBACd,OACuC;AACvC,SACE,uBAAuB,SACvB,OAAQ,MAAuC,sBAC7C;AAEN;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["import type { WalletClient, PublicClient, Account, Address, Chain } from \"viem\";\nimport type { VanaChainId, VanaChain } from \"./chains\";\nimport type {\n StorageProvider,\n StorageUploadResult,\n StorageListOptions,\n} from \"./storage\";\n\nimport type { RelayerConfig } from \"./relayer\";\n\n/**\n * Marker interface to indicate that a Vana instance has storage configured.\n * Used for compile-time type safety to ensure storage-dependent methods\n * are only called on properly configured instances.\n *\n * @category Configuration\n */\nexport interface StorageRequiredMarker {\n readonly __storageRequired: true;\n}\n\n/**\n * Configures storage providers for SDK file operations.\n *\n * @remarks\n * Supports multiple backends with automatic fallback.\n * IPFS for decentralization, Pinata for reliability,\n * Google Drive for development, custom for flexibility.\n *\n * **Provider Selection:**\n * - IPFS: Decentralized, permanent storage ideal for production\n * - Pinata: Managed IPFS with guaranteed availability\n * - Google Drive: Centralized, suitable for development/testing\n * - Custom providers: Implement StorageProvider interface\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storage: StorageConfig = {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' }),\n * pinata: new PinataStorage({ apiKey: 'key', secretKey: 'secret' })\n * },\n * defaultProvider: 'ipfs'\n * };\n * ```\n */\nexport interface StorageConfig {\n /**\n * Map of provider name to storage provider instance.\n * Common provider names: \"ipfs\", \"pinata\", \"googledrive\", \"s3\".\n * Custom names allowed for custom provider implementations.\n */\n providers: Record<string, StorageProvider>;\n /**\n * Default provider name to use when none specified.\n * Must match a key in the providers map. Falls back to first provider if not specified.\n */\n defaultProvider?: string;\n}\n\n/**\n * Download relayer callbacks for proxying CORS-restricted downloads.\n *\n * Provides a callback to proxy download requests through your application server\n * when direct browser access fails due to CORS restrictions (e.g., Google Drive).\n *\n * IMPORTANT SECURITY REQUIREMENTS for your proxy endpoint:\n * 1. MUST block requests to private/internal IPs (SSRF protection)\n * 2. SHOULD NOT restrict domains (files can be hosted anywhere)\n *\n * @category Configuration\n * @example Client-side implementation:\n * ```typescript\n * const downloadRelayer: DownloadRelayerCallbacks = {\n * async proxyDownload(url) {\n * const response = await fetch('/api/proxy', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ url })\n * });\n * return response.blob();\n * }\n * };\n * ```\n *\n * @example Server-side proxy endpoint (Next.js):\n * ```typescript\n * // /api/proxy/route.ts\n * import { promises as dns } from 'dns';\n * import { isIPv4 } from 'net';\n *\n * async function handleProxy(url: string) {\n * const { hostname } = new URL(url);\n *\n * // Resolve hostname to IP (handle localhost specially)\n * const ip = hostname === 'localhost' ? '127.0.0.1' :\n * isIPv4(hostname) ? hostname :\n * await dns.lookup(hostname).then(r => r.address);\n *\n * // SSRF Protection: Block private/internal IPs\n * if (isIPv4(ip)) {\n * const [a, b] = ip.split('.').map(Number);\n * if (a === 10 || a === 127 || a === 0 ||\n * (a === 172 && b >= 16 && b <= 31) ||\n * (a === 192 && b === 168) ||\n * (a === 169 && b === 254) ||\n * a >= 224) { // Also block multicast/reserved\n * return new Response('Private/internal addresses not allowed', { status: 403 });\n * }\n * }\n *\n * // Proxy the request\n * const response = await fetch(url, { redirect: 'manual' });\n *\n * // Handle redirects (with recursion limit)\n * if (response.status >= 301 && response.status <= 308) {\n * const location = response.headers.get('location');\n * if (location) return handleProxy(new URL(location, url).href);\n * }\n *\n * const data = await response.arrayBuffer();\n * return new Response(data, {\n * headers: {\n * 'Content-Type': response.headers.get('content-type') || 'application/octet-stream',\n * 'Access-Control-Allow-Origin': '*'\n * }\n * });\n * }\n * ```\n */\nexport interface DownloadRelayerCallbacks {\n /**\n * Proxy a download request through your application server\n *\n * @param url - The URL to download from\n * @returns Promise resolving to the downloaded content as a Blob\n */\n proxyDownload: (url: string) => Promise<Blob>;\n}\n\n/**\n * Storage callback functions for flexible storage operations.\n *\n * Instead of hardcoding storage behavior (HTTP endpoints, etc.), users can provide\n * custom callback functions to handle storage operations in any way they choose.\n * This pattern matches the relayer callbacks approach, providing maximum flexibility.\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storageCallbacks: StorageCallbacks = {\n * async upload(blob, filename, metadata) {\n * // Custom implementation - could be HTTP, S3, local filesystem, etc.\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type,\n * metadata: data.metadata\n * };\n * },\n *\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n * ```\n */\nexport interface StorageCallbacks {\n /**\n * Upload a blob to storage\n *\n * @param blob - The data to upload\n * @param filename - Optional filename hint\n * @param metadata - Optional metadata for the upload\n * @returns Upload result with identifier and metadata\n */\n upload: (\n blob: Blob,\n filename?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<StorageUploadResult>;\n\n /**\n * Download data from storage\n *\n * @param identifier - The storage identifier (could be URL, hash, path, or any unique ID)\n * @param options - Optional download options\n * @returns The downloaded data as a Blob\n */\n download: (\n identifier: string,\n options?: StorageDownloadOptions,\n ) => Promise<Blob>;\n\n /**\n * List stored items (optional)\n *\n * @param prefix - Optional prefix to filter results\n * @param options - Optional listing options\n * @returns Array of storage items with metadata\n */\n list?: (\n prefix?: string,\n options?: StorageListOptions,\n ) => Promise<StorageListResult>;\n\n /**\n * Delete a stored item (optional)\n *\n * @param identifier - The storage identifier to delete\n * @returns Promise that resolves to true if deletion succeeded\n */\n delete?: (identifier: string) => Promise<boolean>;\n\n /**\n * Extract identifier from a URL or return as-is (optional)\n * Used for backward compatibility with URL-based systems\n *\n * @param url - The URL to extract from\n * @returns The extracted identifier\n */\n extractIdentifier?: (url: string) => string;\n}\n\n/**\n * Options for storage download operations\n *\n * @category Configuration\n */\nexport interface StorageDownloadOptions {\n /** Optional HTTP headers */\n headers?: Record<string, string>;\n /** Optional abort signal for cancellation */\n signal?: AbortSignal;\n /** Optional byte range for partial downloads */\n range?: { start?: number; end?: number };\n}\n\n/**\n * Result from storage list operations\n *\n * @category Configuration\n */\nexport interface StorageListResult {\n /** Array of storage items */\n items: Array<{\n /** Item identifier */\n identifier: string;\n /** Item size in bytes */\n size?: number;\n /** Last modified timestamp */\n lastModified?: Date;\n /** Item metadata */\n metadata?: Record<string, unknown>;\n }>;\n /** Continuation token for pagination */\n continuationToken?: string;\n /** Whether more results are available */\n hasMore?: boolean;\n}\n\n/**\n * Base configuration interface without storage requirements\n *\n * @category Configuration\n */\nexport interface BaseConfig {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /**\n * Optional storage providers configuration for file upload/download.\n * Required for: upload(), grant() without pre-stored URLs, schema operations.\n * See StorageConfig for provider selection guidance.\n */\n storage?: StorageConfig;\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n * Obtain chain-specific URLs from Vana documentation or deployment info.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n * Order matters: first successful gateway is used.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n}\n\n/**\n * Base configuration interface that requires storage for storage-dependent operations\n *\n * @category Configuration\n */\nexport interface BaseConfigWithStorage {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /** Required storage providers configuration for file upload/download */\n storage: StorageConfig;\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n}\n\n/**\n * Configuration with wallet client\n *\n * @category Configuration\n */\nexport interface WalletConfig extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with wallet client that requires storage\n *\n * @category Configuration\n */\nexport interface WalletConfigWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with chain and account details\n *\n * @category Configuration\n */\nexport interface ChainConfig extends BaseConfig {\n /**\n * The chain ID for Vana network.\n * Supported: 14800 (Vana Mainnet), 14801 (Moksha Testnet), 31337 (Local Development).\n * Use chain constants from '@vana/sdk' for type safety.\n */\n chainId: VanaChainId;\n /**\n * RPC URL for the chain (optional, will use default for the chain if not provided).\n * Default URLs: mainnet (https://rpc.vana.org), testnet (https://rpc.moksha.vana.org).\n * Override for custom nodes or local development.\n */\n rpcUrl?: string;\n /**\n * Optional account for signing transactions.\n * Can be: privateKeyToAccount(), mnemonicToAccount(), or custom Account implementation.\n * Required for write operations; read-only operations work without account.\n */\n account?: Account;\n}\n\n/**\n * Configuration with chain and account details that requires storage\n *\n * @category Configuration\n */\nexport interface ChainConfigWithStorage extends BaseConfigWithStorage {\n /** The chain ID for Vana network */\n chainId: VanaChainId;\n /** RPC URL for the chain (optional, will use default for the chain if not provided) */\n rpcUrl?: string;\n /** Optional account for signing transactions */\n account?: Account;\n}\n\n/**\n * Configuration with wallet client and optional public client\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWallet extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnly extends BaseConfig {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnly extends BaseConfig {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Configuration with wallet client and optional public client that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWalletWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnlyWithStorage extends BaseConfigWithStorage {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnlyWithStorage\n extends BaseConfigWithStorage {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Main configuration interface for initializing the Vana SDK.\n *\n * The SDK supports three initialization modes:\n * 1. Full mode with wallet client for signing transactions\n * 2. Read-only mode with public client and address for read operations\n * 3. Minimal mode with just an address and optional chain\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Mode 1: Full configuration with wallet client\n * const configWithWallet: VanaConfig = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * })\n * };\n *\n * // Mode 2: Read-only with public client and address\n * const configReadOnly: VanaConfig = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...'\n * };\n *\n * // Mode 3: Minimal with just address\n * const configMinimal: VanaConfig = {\n * address: '0x1234...',\n * chain: moksha // optional\n * };\n * ```\n */\nexport type VanaConfig =\n | VanaConfigWithWallet\n | VanaConfigReadOnly\n | VanaConfigAddressOnly\n | WalletConfig\n | ChainConfig;\n\n/**\n * Configuration interface for Vana SDK that requires storage providers.\n *\n * Use this type when you need to ensure storage is configured for operations\n * like file uploads, permission grants without pre-stored URLs, or schema creation.\n * Supports all three initialization modes with required storage.\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Full configuration with wallet client and storage\n * const configWithWallet: VanaConfigWithStorage = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n *\n * // Read-only configuration with storage\n * const configReadOnly: VanaConfigWithStorage = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...',\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n * ```\n */\nexport type VanaConfigWithStorage =\n | VanaConfigWithWalletWithStorage\n | VanaConfigReadOnlyWithStorage\n | VanaConfigAddressOnlyWithStorage\n | WalletConfigWithStorage\n | ChainConfigWithStorage;\n\n/**\n * Runtime configuration information\n *\n * @category Configuration\n */\nexport interface RuntimeConfig {\n /** Current chain ID */\n chainId: VanaChainId;\n /** Current chain name */\n chainName: string;\n /** Available storage providers */\n storageProviders: string[];\n /** Default storage provider */\n defaultStorageProvider?: string;\n /** Current relayer configuration */\n relayerConfig?: RelayerConfig;\n}\n\n/**\n * Validates whether a configuration object has a wallet client (any wallet-based config).\n *\n * @param config - The configuration object to check\n * @returns True if the config contains a walletClient\n * @example\n * ```typescript\n * if (isWalletConfig(config)) {\n * console.log('Using wallet client:', config.walletClient.account?.address);\n * } else {\n * console.log('Read-only or chain config');\n * }\n * ```\n */\nexport function isWalletConfig(\n config: VanaConfig,\n): config is VanaConfigWithWallet | WalletConfig {\n return \"walletClient\" in config;\n}\n\n/**\n * Validates whether a configuration object is a read-only config with public client.\n *\n * @param config - The configuration object to check\n * @returns True if the config has publicClient and address but no walletClient\n * @example\n * ```typescript\n * if (isReadOnlyConfig(config)) {\n * console.log('Read-only mode with address:', config.address);\n * }\n * ```\n */\nexport function isReadOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigReadOnly {\n return (\n \"publicClient\" in config &&\n \"address\" in config &&\n !(\"walletClient\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is an address-only config.\n *\n * @param config - The configuration object to check\n * @returns True if the config has only address (and optionally chain) but no clients\n * @example\n * ```typescript\n * if (isAddressOnlyConfig(config)) {\n * console.log('Address-only mode:', config.address);\n * }\n * ```\n */\nexport function isAddressOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigAddressOnly {\n return (\n \"address\" in config &&\n !(\"publicClient\" in config) &&\n !(\"walletClient\" in config) &&\n !(\"chainId\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is a ChainConfig.\n *\n * @param config - The configuration object to check\n * @returns True if the config is a ChainConfig (contains chainId but not walletClient)\n * @example\n * ```typescript\n * if (isChainConfig(config)) {\n * console.log('Chain ID:', config.chainId);\n * console.log('RPC URL:', config.rpcUrl);\n * } else {\n * console.log('Using pre-configured wallet client');\n * }\n * ```\n */\nexport function isChainConfig(config: VanaConfig): config is ChainConfig {\n return \"chainId\" in config && !(\"walletClient\" in config);\n}\n\n/**\n * Validates whether a configuration has required storage providers.\n *\n * @param config - The configuration object to check\n * @returns True if the config has storage providers configured\n * @example\n * ```typescript\n * if (hasStorageConfig(config)) {\n * // Safe to use storage-dependent operations\n * await vana.data.uploadFile(file);\n * } else {\n * console.log('Storage not configured - some operations may fail');\n * }\n * ```\n */\nexport function hasStorageConfig(\n config: VanaConfig,\n): config is VanaConfigWithStorage {\n return (\n config.storage?.providers !== undefined &&\n Object.keys(config.storage.providers).length > 0\n );\n}\n\n/**\n * Configuration validation options\n *\n * @category Configuration\n */\nexport interface ConfigValidationOptions {\n /** Whether to validate storage providers */\n validateStorage?: boolean;\n /** Whether to validate relayer URL */\n validateRelayer?: boolean;\n /** Whether to validate chain configuration */\n validateChain?: boolean;\n}\n\n/**\n * Configuration validation result\n *\n * @category Configuration\n */\nexport interface ConfigValidationResult {\n /** Whether the configuration is valid */\n valid: boolean;\n /** List of validation errors */\n errors: string[];\n /** List of validation warnings */\n warnings: string[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgpBO,SAAS,eACd,QAC+C;AAC/C,SAAO,kBAAkB;AAC3B;AAcO,SAAS,iBACd,QAC8B;AAC9B,SACE,kBAAkB,UAClB,aAAa,UACb,EAAE,kBAAkB;AAExB;AAcO,SAAS,oBACd,QACiC;AACjC,SACE,aAAa,UACb,EAAE,kBAAkB,WACpB,EAAE,kBAAkB,WACpB,EAAE,aAAa;AAEnB;AAiBO,SAAS,cAAc,QAA2C;AACvE,SAAO,aAAa,UAAU,EAAE,kBAAkB;AACpD;AAiBO,SAAS,iBACd,QACiC;AACjC,SACE,OAAO,SAAS,cAAc,UAC9B,OAAO,KAAK,OAAO,QAAQ,SAAS,EAAE,SAAS;AAEnD;","names":[]}
1
+ {"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["import type { WalletClient, PublicClient, Account, Address, Chain } from \"viem\";\nimport type { VanaChainId, VanaChain } from \"./chains\";\nimport type {\n StorageProvider,\n StorageUploadResult,\n StorageListOptions,\n} from \"./storage\";\n\nimport type { RelayerConfig } from \"./relayer\";\nimport type { IOperationStore, IRelayerStateStore } from \"./operationStore\";\n\n/**\n * Marker interface to indicate that a Vana instance has storage configured.\n * Used for compile-time type safety to ensure storage-dependent methods\n * are only called on properly configured instances.\n *\n * @category Configuration\n */\nexport interface StorageRequiredMarker {\n readonly __storageRequired: true;\n}\n\n/**\n * Configures storage providers for SDK file operations.\n *\n * @remarks\n * Supports multiple backends with automatic fallback.\n * IPFS for decentralization, Pinata for reliability,\n * Google Drive for development, custom for flexibility.\n *\n * **Provider Selection:**\n * - IPFS: Decentralized, permanent storage ideal for production\n * - Pinata: Managed IPFS with guaranteed availability\n * - Google Drive: Centralized, suitable for development/testing\n * - Custom providers: Implement StorageProvider interface\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storage: StorageConfig = {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' }),\n * pinata: new PinataStorage({ apiKey: 'key', secretKey: 'secret' })\n * },\n * defaultProvider: 'ipfs'\n * };\n * ```\n */\nexport interface StorageConfig {\n /**\n * Map of provider name to storage provider instance.\n * Common provider names: \"ipfs\", \"pinata\", \"googledrive\", \"s3\".\n * Custom names allowed for custom provider implementations.\n */\n providers: Record<string, StorageProvider>;\n /**\n * Default provider name to use when none specified.\n * Must match a key in the providers map. Falls back to first provider if not specified.\n */\n defaultProvider?: string;\n}\n\n/**\n * Download relayer callbacks for proxying CORS-restricted downloads.\n *\n * Provides a callback to proxy download requests through your application server\n * when direct browser access fails due to CORS restrictions (e.g., Google Drive).\n *\n * IMPORTANT SECURITY REQUIREMENTS for your proxy endpoint:\n * 1. MUST block requests to private/internal IPs (SSRF protection)\n * 2. SHOULD NOT restrict domains (files can be hosted anywhere)\n *\n * @category Configuration\n * @example Client-side implementation:\n * ```typescript\n * const downloadRelayer: DownloadRelayerCallbacks = {\n * async proxyDownload(url) {\n * const response = await fetch('/api/proxy', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ url })\n * });\n * return response.blob();\n * }\n * };\n * ```\n *\n * @example Server-side proxy endpoint (Next.js):\n * ```typescript\n * // /api/proxy/route.ts\n * import { promises as dns } from 'dns';\n * import { isIPv4 } from 'net';\n *\n * async function handleProxy(url: string) {\n * const { hostname } = new URL(url);\n *\n * // Resolve hostname to IP (handle localhost specially)\n * const ip = hostname === 'localhost' ? '127.0.0.1' :\n * isIPv4(hostname) ? hostname :\n * await dns.lookup(hostname).then(r => r.address);\n *\n * // SSRF Protection: Block private/internal IPs\n * if (isIPv4(ip)) {\n * const [a, b] = ip.split('.').map(Number);\n * if (a === 10 || a === 127 || a === 0 ||\n * (a === 172 && b >= 16 && b <= 31) ||\n * (a === 192 && b === 168) ||\n * (a === 169 && b === 254) ||\n * a >= 224) { // Also block multicast/reserved\n * return new Response('Private/internal addresses not allowed', { status: 403 });\n * }\n * }\n *\n * // Proxy the request\n * const response = await fetch(url, { redirect: 'manual' });\n *\n * // Handle redirects (with recursion limit)\n * if (response.status >= 301 && response.status <= 308) {\n * const location = response.headers.get('location');\n * if (location) return handleProxy(new URL(location, url).href);\n * }\n *\n * const data = await response.arrayBuffer();\n * return new Response(data, {\n * headers: {\n * 'Content-Type': response.headers.get('content-type') || 'application/octet-stream',\n * 'Access-Control-Allow-Origin': '*'\n * }\n * });\n * }\n * ```\n */\nexport interface DownloadRelayerCallbacks {\n /**\n * Proxy a download request through your application server\n *\n * @param url - The URL to download from\n * @returns Promise resolving to the downloaded content as a Blob\n */\n proxyDownload: (url: string) => Promise<Blob>;\n}\n\n/**\n * Storage callback functions for flexible storage operations.\n *\n * Instead of hardcoding storage behavior (HTTP endpoints, etc.), users can provide\n * custom callback functions to handle storage operations in any way they choose.\n * This pattern matches the relayer callbacks approach, providing maximum flexibility.\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storageCallbacks: StorageCallbacks = {\n * async upload(blob, filename, metadata) {\n * // Custom implementation - could be HTTP, S3, local filesystem, etc.\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type,\n * metadata: data.metadata\n * };\n * },\n *\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n * ```\n */\nexport interface StorageCallbacks {\n /**\n * Upload a blob to storage\n *\n * @param blob - The data to upload\n * @param filename - Optional filename hint\n * @param metadata - Optional metadata for the upload\n * @returns Upload result with identifier and metadata\n */\n upload: (\n blob: Blob,\n filename?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<StorageUploadResult>;\n\n /**\n * Download data from storage\n *\n * @param identifier - The storage identifier (could be URL, hash, path, or any unique ID)\n * @param options - Optional download options\n * @returns The downloaded data as a Blob\n */\n download: (\n identifier: string,\n options?: StorageDownloadOptions,\n ) => Promise<Blob>;\n\n /**\n * List stored items (optional)\n *\n * @param prefix - Optional prefix to filter results\n * @param options - Optional listing options\n * @returns Array of storage items with metadata\n */\n list?: (\n prefix?: string,\n options?: StorageListOptions,\n ) => Promise<StorageListResult>;\n\n /**\n * Delete a stored item (optional)\n *\n * @param identifier - The storage identifier to delete\n * @returns Promise that resolves to true if deletion succeeded\n */\n delete?: (identifier: string) => Promise<boolean>;\n\n /**\n * Extract identifier from a URL or return as-is (optional)\n * Used for backward compatibility with URL-based systems\n *\n * @param url - The URL to extract from\n * @returns The extracted identifier\n */\n extractIdentifier?: (url: string) => string;\n}\n\n/**\n * Options for storage download operations\n *\n * @category Configuration\n */\nexport interface StorageDownloadOptions {\n /** Optional HTTP headers */\n headers?: Record<string, string>;\n /** Optional abort signal for cancellation */\n signal?: AbortSignal;\n /** Optional byte range for partial downloads */\n range?: { start?: number; end?: number };\n}\n\n/**\n * Result from storage list operations\n *\n * @category Configuration\n */\nexport interface StorageListResult {\n /** Array of storage items */\n items: Array<{\n /** Item identifier */\n identifier: string;\n /** Item size in bytes */\n size?: number;\n /** Last modified timestamp */\n lastModified?: Date;\n /** Item metadata */\n metadata?: Record<string, unknown>;\n }>;\n /** Continuation token for pagination */\n continuationToken?: string;\n /** Whether more results are available */\n hasMore?: boolean;\n}\n\n/**\n * Base configuration interface without storage requirements\n *\n * @category Configuration\n */\nexport interface BaseConfig {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /**\n * Optional storage providers configuration for file upload/download.\n * Required for: upload(), grant() without pre-stored URLs, schema operations.\n * See StorageConfig for provider selection guidance.\n */\n storage?: StorageConfig;\n\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n * Obtain chain-specific URLs from Vana documentation or deployment info.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n * Order matters: first successful gateway is used.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n\n /**\n * Optional operation store for tracking async relayed transactions.\n * When provided with a relayer, enables resilient transaction management\n * with polling support for pending operations.\n *\n * @example\n * ```typescript\n * const vana = createVana({\n * walletClient,\n * relayer: '/api/relay',\n * operationStore: myOperationStore\n * });\n * ```\n */\n operationStore?: IOperationStore | IRelayerStateStore;\n}\n\n/**\n * Base configuration interface that requires storage for storage-dependent operations\n *\n * @category Configuration\n */\nexport interface BaseConfigWithStorage {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /** Required storage providers configuration for file upload/download */\n storage: StorageConfig;\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n\n /**\n * Optional operation store for tracking async relayed transactions.\n * When provided with a relayer, enables resilient transaction management\n * with polling support for pending operations.\n */\n operationStore?: IOperationStore | IRelayerStateStore;\n}\n\n/**\n * Configuration with wallet client\n *\n * @category Configuration\n */\nexport interface WalletConfig extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with wallet client that requires storage\n *\n * @category Configuration\n */\nexport interface WalletConfigWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with chain and account details\n *\n * @category Configuration\n */\nexport interface ChainConfig extends BaseConfig {\n /**\n * The chain ID for Vana network.\n * Supported: 14800 (Vana Mainnet), 14801 (Moksha Testnet), 31337 (Local Development).\n * Use chain constants from '@vana/sdk' for type safety.\n */\n chainId: VanaChainId;\n /**\n * RPC URL for the chain (optional, will use default for the chain if not provided).\n * Default URLs: mainnet (https://rpc.vana.org), testnet (https://rpc.moksha.vana.org).\n * Override for custom nodes or local development.\n */\n rpcUrl?: string;\n /**\n * Optional account for signing transactions.\n * Can be: privateKeyToAccount(), mnemonicToAccount(), or custom Account implementation.\n * Required for write operations; read-only operations work without account.\n */\n account?: Account;\n}\n\n/**\n * Configuration with chain and account details that requires storage\n *\n * @category Configuration\n */\nexport interface ChainConfigWithStorage extends BaseConfigWithStorage {\n /** The chain ID for Vana network */\n chainId: VanaChainId;\n /** RPC URL for the chain (optional, will use default for the chain if not provided) */\n rpcUrl?: string;\n /** Optional account for signing transactions */\n account?: Account;\n}\n\n/**\n * Configuration with wallet client and optional public client\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWallet extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnly extends BaseConfig {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnly extends BaseConfig {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Configuration with wallet client and optional public client that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWalletWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnlyWithStorage extends BaseConfigWithStorage {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnlyWithStorage\n extends BaseConfigWithStorage {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Main configuration interface for initializing the Vana SDK.\n *\n * The SDK supports three initialization modes:\n * 1. Full mode with wallet client for signing transactions\n * 2. Read-only mode with public client and address for read operations\n * 3. Minimal mode with just an address and optional chain\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Mode 1: Full configuration with wallet client\n * const configWithWallet: VanaConfig = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * })\n * };\n *\n * // Mode 2: Read-only with public client and address\n * const configReadOnly: VanaConfig = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...'\n * };\n *\n * // Mode 3: Minimal with just address\n * const configMinimal: VanaConfig = {\n * address: '0x1234...',\n * chain: moksha // optional\n * };\n * ```\n */\nexport type VanaConfig =\n | VanaConfigWithWallet\n | VanaConfigReadOnly\n | VanaConfigAddressOnly\n | WalletConfig\n | ChainConfig;\n\n/**\n * Configuration interface for Vana SDK that requires storage providers.\n *\n * Use this type when you need to ensure storage is configured for operations\n * like file uploads, permission grants without pre-stored URLs, or schema creation.\n * Supports all three initialization modes with required storage.\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Full configuration with wallet client and storage\n * const configWithWallet: VanaConfigWithStorage = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n *\n * // Read-only configuration with storage\n * const configReadOnly: VanaConfigWithStorage = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...',\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n * ```\n */\nexport type VanaConfigWithStorage =\n | VanaConfigWithWalletWithStorage\n | VanaConfigReadOnlyWithStorage\n | VanaConfigAddressOnlyWithStorage\n | WalletConfigWithStorage\n | ChainConfigWithStorage;\n\n/**\n * Runtime configuration information\n *\n * @category Configuration\n */\nexport interface RuntimeConfig {\n /** Current chain ID */\n chainId: VanaChainId;\n /** Current chain name */\n chainName: string;\n /** Available storage providers */\n storageProviders: string[];\n /** Default storage provider */\n defaultStorageProvider?: string;\n /** Current relayer configuration */\n relayerConfig?: RelayerConfig;\n}\n\n/**\n * Validates whether a configuration object has a wallet client (any wallet-based config).\n *\n * @param config - The configuration object to check\n * @returns True if the config contains a walletClient\n * @example\n * ```typescript\n * if (isWalletConfig(config)) {\n * console.log('Using wallet client:', config.walletClient.account?.address);\n * } else {\n * console.log('Read-only or chain config');\n * }\n * ```\n */\nexport function isWalletConfig(\n config: VanaConfig,\n): config is VanaConfigWithWallet | WalletConfig {\n return \"walletClient\" in config;\n}\n\n/**\n * Validates whether a configuration object is a read-only config with public client.\n *\n * @param config - The configuration object to check\n * @returns True if the config has publicClient and address but no walletClient\n * @example\n * ```typescript\n * if (isReadOnlyConfig(config)) {\n * console.log('Read-only mode with address:', config.address);\n * }\n * ```\n */\nexport function isReadOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigReadOnly {\n return (\n \"publicClient\" in config &&\n \"address\" in config &&\n !(\"walletClient\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is an address-only config.\n *\n * @param config - The configuration object to check\n * @returns True if the config has only address (and optionally chain) but no clients\n * @example\n * ```typescript\n * if (isAddressOnlyConfig(config)) {\n * console.log('Address-only mode:', config.address);\n * }\n * ```\n */\nexport function isAddressOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigAddressOnly {\n return (\n \"address\" in config &&\n !(\"publicClient\" in config) &&\n !(\"walletClient\" in config) &&\n !(\"chainId\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is a ChainConfig.\n *\n * @param config - The configuration object to check\n * @returns True if the config is a ChainConfig (contains chainId but not walletClient)\n * @example\n * ```typescript\n * if (isChainConfig(config)) {\n * console.log('Chain ID:', config.chainId);\n * console.log('RPC URL:', config.rpcUrl);\n * } else {\n * console.log('Using pre-configured wallet client');\n * }\n * ```\n */\nexport function isChainConfig(config: VanaConfig): config is ChainConfig {\n return \"chainId\" in config && !(\"walletClient\" in config);\n}\n\n/**\n * Validates whether a configuration has required storage providers.\n *\n * @param config - The configuration object to check\n * @returns True if the config has storage providers configured\n * @example\n * ```typescript\n * if (hasStorageConfig(config)) {\n * // Safe to use storage-dependent operations\n * await vana.data.uploadFile(file);\n * } else {\n * console.log('Storage not configured - some operations may fail');\n * }\n * ```\n */\nexport function hasStorageConfig(\n config: VanaConfig,\n): config is VanaConfigWithStorage {\n return (\n config.storage?.providers !== undefined &&\n Object.keys(config.storage.providers).length > 0\n );\n}\n\n/**\n * Configuration validation options\n *\n * @category Configuration\n */\nexport interface ConfigValidationOptions {\n /** Whether to validate storage providers */\n validateStorage?: boolean;\n /** Whether to validate relayer URL */\n validateRelayer?: boolean;\n /** Whether to validate chain configuration */\n validateChain?: boolean;\n}\n\n/**\n * Configuration validation result\n *\n * @category Configuration\n */\nexport interface ConfigValidationResult {\n /** Whether the configuration is valid */\n valid: boolean;\n /** List of validation errors */\n errors: string[];\n /** List of validation warnings */\n warnings: string[];\n}\n\n/**\n * Marker interface to enforce the presence of operationStore at compile time.\n * This interface is used to ensure that certain operations requiring a relayer\n * can only be called when the SDK has been properly configured with an operation store.\n *\n * @category Configuration\n */\nexport interface RelayerRequiredMarker {\n readonly __relayerConfigured: true;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyqBO,SAAS,eACd,QAC+C;AAC/C,SAAO,kBAAkB;AAC3B;AAcO,SAAS,iBACd,QAC8B;AAC9B,SACE,kBAAkB,UAClB,aAAa,UACb,EAAE,kBAAkB;AAExB;AAcO,SAAS,oBACd,QACiC;AACjC,SACE,aAAa,UACb,EAAE,kBAAkB,WACpB,EAAE,kBAAkB,WACpB,EAAE,aAAa;AAEnB;AAiBO,SAAS,cAAc,QAA2C;AACvE,SAAO,aAAa,UAAU,EAAE,kBAAkB;AACpD;AAiBO,SAAS,iBACd,QACiC;AACjC,SACE,OAAO,SAAS,cAAc,UAC9B,OAAO,KAAK,OAAO,QAAQ,SAAS,EAAE,SAAS;AAEnD;","names":[]}
@@ -2,6 +2,7 @@ import type { WalletClient, PublicClient, Account, Address, Chain } from "viem";
2
2
  import type { VanaChainId, VanaChain } from "./chains";
3
3
  import type { StorageProvider, StorageUploadResult, StorageListOptions } from "./storage";
4
4
  import type { RelayerConfig } from "./relayer";
5
+ import type { IOperationStore, IRelayerStateStore } from "./operationStore";
5
6
  /**
6
7
  * Marker interface to indicate that a Vana instance has storage configured.
7
8
  * Used for compile-time type safety to ensure storage-dependent methods
@@ -305,6 +306,21 @@ export interface BaseConfig {
305
306
  * @example 'https://my-personal-server.example.com'
306
307
  */
307
308
  defaultPersonalServerUrl?: string;
309
+ /**
310
+ * Optional operation store for tracking async relayed transactions.
311
+ * When provided with a relayer, enables resilient transaction management
312
+ * with polling support for pending operations.
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * const vana = createVana({
317
+ * walletClient,
318
+ * relayer: '/api/relay',
319
+ * operationStore: myOperationStore
320
+ * });
321
+ * ```
322
+ */
323
+ operationStore?: IOperationStore | IRelayerStateStore;
308
324
  }
309
325
  /**
310
326
  * Base configuration interface that requires storage for storage-dependent operations
@@ -360,6 +376,12 @@ export interface BaseConfigWithStorage {
360
376
  * @example 'https://my-personal-server.example.com'
361
377
  */
362
378
  defaultPersonalServerUrl?: string;
379
+ /**
380
+ * Optional operation store for tracking async relayed transactions.
381
+ * When provided with a relayer, enables resilient transaction management
382
+ * with polling support for pending operations.
383
+ */
384
+ operationStore?: IOperationStore | IRelayerStateStore;
363
385
  }
364
386
  /**
365
387
  * Configuration with wallet client
@@ -686,3 +708,13 @@ export interface ConfigValidationResult {
686
708
  /** List of validation warnings */
687
709
  warnings: string[];
688
710
  }
711
+ /**
712
+ * Marker interface to enforce the presence of operationStore at compile time.
713
+ * This interface is used to ensure that certain operations requiring a relayer
714
+ * can only be called when the SDK has been properly configured with an operation store.
715
+ *
716
+ * @category Configuration
717
+ */
718
+ export interface RelayerRequiredMarker {
719
+ readonly __relayerConfigured: true;
720
+ }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["import type { WalletClient, PublicClient, Account, Address, Chain } from \"viem\";\nimport type { VanaChainId, VanaChain } from \"./chains\";\nimport type {\n StorageProvider,\n StorageUploadResult,\n StorageListOptions,\n} from \"./storage\";\n\nimport type { RelayerConfig } from \"./relayer\";\n\n/**\n * Marker interface to indicate that a Vana instance has storage configured.\n * Used for compile-time type safety to ensure storage-dependent methods\n * are only called on properly configured instances.\n *\n * @category Configuration\n */\nexport interface StorageRequiredMarker {\n readonly __storageRequired: true;\n}\n\n/**\n * Configures storage providers for SDK file operations.\n *\n * @remarks\n * Supports multiple backends with automatic fallback.\n * IPFS for decentralization, Pinata for reliability,\n * Google Drive for development, custom for flexibility.\n *\n * **Provider Selection:**\n * - IPFS: Decentralized, permanent storage ideal for production\n * - Pinata: Managed IPFS with guaranteed availability\n * - Google Drive: Centralized, suitable for development/testing\n * - Custom providers: Implement StorageProvider interface\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storage: StorageConfig = {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' }),\n * pinata: new PinataStorage({ apiKey: 'key', secretKey: 'secret' })\n * },\n * defaultProvider: 'ipfs'\n * };\n * ```\n */\nexport interface StorageConfig {\n /**\n * Map of provider name to storage provider instance.\n * Common provider names: \"ipfs\", \"pinata\", \"googledrive\", \"s3\".\n * Custom names allowed for custom provider implementations.\n */\n providers: Record<string, StorageProvider>;\n /**\n * Default provider name to use when none specified.\n * Must match a key in the providers map. Falls back to first provider if not specified.\n */\n defaultProvider?: string;\n}\n\n/**\n * Download relayer callbacks for proxying CORS-restricted downloads.\n *\n * Provides a callback to proxy download requests through your application server\n * when direct browser access fails due to CORS restrictions (e.g., Google Drive).\n *\n * IMPORTANT SECURITY REQUIREMENTS for your proxy endpoint:\n * 1. MUST block requests to private/internal IPs (SSRF protection)\n * 2. SHOULD NOT restrict domains (files can be hosted anywhere)\n *\n * @category Configuration\n * @example Client-side implementation:\n * ```typescript\n * const downloadRelayer: DownloadRelayerCallbacks = {\n * async proxyDownload(url) {\n * const response = await fetch('/api/proxy', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ url })\n * });\n * return response.blob();\n * }\n * };\n * ```\n *\n * @example Server-side proxy endpoint (Next.js):\n * ```typescript\n * // /api/proxy/route.ts\n * import { promises as dns } from 'dns';\n * import { isIPv4 } from 'net';\n *\n * async function handleProxy(url: string) {\n * const { hostname } = new URL(url);\n *\n * // Resolve hostname to IP (handle localhost specially)\n * const ip = hostname === 'localhost' ? '127.0.0.1' :\n * isIPv4(hostname) ? hostname :\n * await dns.lookup(hostname).then(r => r.address);\n *\n * // SSRF Protection: Block private/internal IPs\n * if (isIPv4(ip)) {\n * const [a, b] = ip.split('.').map(Number);\n * if (a === 10 || a === 127 || a === 0 ||\n * (a === 172 && b >= 16 && b <= 31) ||\n * (a === 192 && b === 168) ||\n * (a === 169 && b === 254) ||\n * a >= 224) { // Also block multicast/reserved\n * return new Response('Private/internal addresses not allowed', { status: 403 });\n * }\n * }\n *\n * // Proxy the request\n * const response = await fetch(url, { redirect: 'manual' });\n *\n * // Handle redirects (with recursion limit)\n * if (response.status >= 301 && response.status <= 308) {\n * const location = response.headers.get('location');\n * if (location) return handleProxy(new URL(location, url).href);\n * }\n *\n * const data = await response.arrayBuffer();\n * return new Response(data, {\n * headers: {\n * 'Content-Type': response.headers.get('content-type') || 'application/octet-stream',\n * 'Access-Control-Allow-Origin': '*'\n * }\n * });\n * }\n * ```\n */\nexport interface DownloadRelayerCallbacks {\n /**\n * Proxy a download request through your application server\n *\n * @param url - The URL to download from\n * @returns Promise resolving to the downloaded content as a Blob\n */\n proxyDownload: (url: string) => Promise<Blob>;\n}\n\n/**\n * Storage callback functions for flexible storage operations.\n *\n * Instead of hardcoding storage behavior (HTTP endpoints, etc.), users can provide\n * custom callback functions to handle storage operations in any way they choose.\n * This pattern matches the relayer callbacks approach, providing maximum flexibility.\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storageCallbacks: StorageCallbacks = {\n * async upload(blob, filename, metadata) {\n * // Custom implementation - could be HTTP, S3, local filesystem, etc.\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type,\n * metadata: data.metadata\n * };\n * },\n *\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n * ```\n */\nexport interface StorageCallbacks {\n /**\n * Upload a blob to storage\n *\n * @param blob - The data to upload\n * @param filename - Optional filename hint\n * @param metadata - Optional metadata for the upload\n * @returns Upload result with identifier and metadata\n */\n upload: (\n blob: Blob,\n filename?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<StorageUploadResult>;\n\n /**\n * Download data from storage\n *\n * @param identifier - The storage identifier (could be URL, hash, path, or any unique ID)\n * @param options - Optional download options\n * @returns The downloaded data as a Blob\n */\n download: (\n identifier: string,\n options?: StorageDownloadOptions,\n ) => Promise<Blob>;\n\n /**\n * List stored items (optional)\n *\n * @param prefix - Optional prefix to filter results\n * @param options - Optional listing options\n * @returns Array of storage items with metadata\n */\n list?: (\n prefix?: string,\n options?: StorageListOptions,\n ) => Promise<StorageListResult>;\n\n /**\n * Delete a stored item (optional)\n *\n * @param identifier - The storage identifier to delete\n * @returns Promise that resolves to true if deletion succeeded\n */\n delete?: (identifier: string) => Promise<boolean>;\n\n /**\n * Extract identifier from a URL or return as-is (optional)\n * Used for backward compatibility with URL-based systems\n *\n * @param url - The URL to extract from\n * @returns The extracted identifier\n */\n extractIdentifier?: (url: string) => string;\n}\n\n/**\n * Options for storage download operations\n *\n * @category Configuration\n */\nexport interface StorageDownloadOptions {\n /** Optional HTTP headers */\n headers?: Record<string, string>;\n /** Optional abort signal for cancellation */\n signal?: AbortSignal;\n /** Optional byte range for partial downloads */\n range?: { start?: number; end?: number };\n}\n\n/**\n * Result from storage list operations\n *\n * @category Configuration\n */\nexport interface StorageListResult {\n /** Array of storage items */\n items: Array<{\n /** Item identifier */\n identifier: string;\n /** Item size in bytes */\n size?: number;\n /** Last modified timestamp */\n lastModified?: Date;\n /** Item metadata */\n metadata?: Record<string, unknown>;\n }>;\n /** Continuation token for pagination */\n continuationToken?: string;\n /** Whether more results are available */\n hasMore?: boolean;\n}\n\n/**\n * Base configuration interface without storage requirements\n *\n * @category Configuration\n */\nexport interface BaseConfig {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /**\n * Optional storage providers configuration for file upload/download.\n * Required for: upload(), grant() without pre-stored URLs, schema operations.\n * See StorageConfig for provider selection guidance.\n */\n storage?: StorageConfig;\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n * Obtain chain-specific URLs from Vana documentation or deployment info.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n * Order matters: first successful gateway is used.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n}\n\n/**\n * Base configuration interface that requires storage for storage-dependent operations\n *\n * @category Configuration\n */\nexport interface BaseConfigWithStorage {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /** Required storage providers configuration for file upload/download */\n storage: StorageConfig;\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n}\n\n/**\n * Configuration with wallet client\n *\n * @category Configuration\n */\nexport interface WalletConfig extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with wallet client that requires storage\n *\n * @category Configuration\n */\nexport interface WalletConfigWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with chain and account details\n *\n * @category Configuration\n */\nexport interface ChainConfig extends BaseConfig {\n /**\n * The chain ID for Vana network.\n * Supported: 14800 (Vana Mainnet), 14801 (Moksha Testnet), 31337 (Local Development).\n * Use chain constants from '@vana/sdk' for type safety.\n */\n chainId: VanaChainId;\n /**\n * RPC URL for the chain (optional, will use default for the chain if not provided).\n * Default URLs: mainnet (https://rpc.vana.org), testnet (https://rpc.moksha.vana.org).\n * Override for custom nodes or local development.\n */\n rpcUrl?: string;\n /**\n * Optional account for signing transactions.\n * Can be: privateKeyToAccount(), mnemonicToAccount(), or custom Account implementation.\n * Required for write operations; read-only operations work without account.\n */\n account?: Account;\n}\n\n/**\n * Configuration with chain and account details that requires storage\n *\n * @category Configuration\n */\nexport interface ChainConfigWithStorage extends BaseConfigWithStorage {\n /** The chain ID for Vana network */\n chainId: VanaChainId;\n /** RPC URL for the chain (optional, will use default for the chain if not provided) */\n rpcUrl?: string;\n /** Optional account for signing transactions */\n account?: Account;\n}\n\n/**\n * Configuration with wallet client and optional public client\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWallet extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnly extends BaseConfig {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnly extends BaseConfig {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Configuration with wallet client and optional public client that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWalletWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnlyWithStorage extends BaseConfigWithStorage {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnlyWithStorage\n extends BaseConfigWithStorage {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Main configuration interface for initializing the Vana SDK.\n *\n * The SDK supports three initialization modes:\n * 1. Full mode with wallet client for signing transactions\n * 2. Read-only mode with public client and address for read operations\n * 3. Minimal mode with just an address and optional chain\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Mode 1: Full configuration with wallet client\n * const configWithWallet: VanaConfig = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * })\n * };\n *\n * // Mode 2: Read-only with public client and address\n * const configReadOnly: VanaConfig = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...'\n * };\n *\n * // Mode 3: Minimal with just address\n * const configMinimal: VanaConfig = {\n * address: '0x1234...',\n * chain: moksha // optional\n * };\n * ```\n */\nexport type VanaConfig =\n | VanaConfigWithWallet\n | VanaConfigReadOnly\n | VanaConfigAddressOnly\n | WalletConfig\n | ChainConfig;\n\n/**\n * Configuration interface for Vana SDK that requires storage providers.\n *\n * Use this type when you need to ensure storage is configured for operations\n * like file uploads, permission grants without pre-stored URLs, or schema creation.\n * Supports all three initialization modes with required storage.\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Full configuration with wallet client and storage\n * const configWithWallet: VanaConfigWithStorage = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n *\n * // Read-only configuration with storage\n * const configReadOnly: VanaConfigWithStorage = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...',\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n * ```\n */\nexport type VanaConfigWithStorage =\n | VanaConfigWithWalletWithStorage\n | VanaConfigReadOnlyWithStorage\n | VanaConfigAddressOnlyWithStorage\n | WalletConfigWithStorage\n | ChainConfigWithStorage;\n\n/**\n * Runtime configuration information\n *\n * @category Configuration\n */\nexport interface RuntimeConfig {\n /** Current chain ID */\n chainId: VanaChainId;\n /** Current chain name */\n chainName: string;\n /** Available storage providers */\n storageProviders: string[];\n /** Default storage provider */\n defaultStorageProvider?: string;\n /** Current relayer configuration */\n relayerConfig?: RelayerConfig;\n}\n\n/**\n * Validates whether a configuration object has a wallet client (any wallet-based config).\n *\n * @param config - The configuration object to check\n * @returns True if the config contains a walletClient\n * @example\n * ```typescript\n * if (isWalletConfig(config)) {\n * console.log('Using wallet client:', config.walletClient.account?.address);\n * } else {\n * console.log('Read-only or chain config');\n * }\n * ```\n */\nexport function isWalletConfig(\n config: VanaConfig,\n): config is VanaConfigWithWallet | WalletConfig {\n return \"walletClient\" in config;\n}\n\n/**\n * Validates whether a configuration object is a read-only config with public client.\n *\n * @param config - The configuration object to check\n * @returns True if the config has publicClient and address but no walletClient\n * @example\n * ```typescript\n * if (isReadOnlyConfig(config)) {\n * console.log('Read-only mode with address:', config.address);\n * }\n * ```\n */\nexport function isReadOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigReadOnly {\n return (\n \"publicClient\" in config &&\n \"address\" in config &&\n !(\"walletClient\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is an address-only config.\n *\n * @param config - The configuration object to check\n * @returns True if the config has only address (and optionally chain) but no clients\n * @example\n * ```typescript\n * if (isAddressOnlyConfig(config)) {\n * console.log('Address-only mode:', config.address);\n * }\n * ```\n */\nexport function isAddressOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigAddressOnly {\n return (\n \"address\" in config &&\n !(\"publicClient\" in config) &&\n !(\"walletClient\" in config) &&\n !(\"chainId\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is a ChainConfig.\n *\n * @param config - The configuration object to check\n * @returns True if the config is a ChainConfig (contains chainId but not walletClient)\n * @example\n * ```typescript\n * if (isChainConfig(config)) {\n * console.log('Chain ID:', config.chainId);\n * console.log('RPC URL:', config.rpcUrl);\n * } else {\n * console.log('Using pre-configured wallet client');\n * }\n * ```\n */\nexport function isChainConfig(config: VanaConfig): config is ChainConfig {\n return \"chainId\" in config && !(\"walletClient\" in config);\n}\n\n/**\n * Validates whether a configuration has required storage providers.\n *\n * @param config - The configuration object to check\n * @returns True if the config has storage providers configured\n * @example\n * ```typescript\n * if (hasStorageConfig(config)) {\n * // Safe to use storage-dependent operations\n * await vana.data.uploadFile(file);\n * } else {\n * console.log('Storage not configured - some operations may fail');\n * }\n * ```\n */\nexport function hasStorageConfig(\n config: VanaConfig,\n): config is VanaConfigWithStorage {\n return (\n config.storage?.providers !== undefined &&\n Object.keys(config.storage.providers).length > 0\n );\n}\n\n/**\n * Configuration validation options\n *\n * @category Configuration\n */\nexport interface ConfigValidationOptions {\n /** Whether to validate storage providers */\n validateStorage?: boolean;\n /** Whether to validate relayer URL */\n validateRelayer?: boolean;\n /** Whether to validate chain configuration */\n validateChain?: boolean;\n}\n\n/**\n * Configuration validation result\n *\n * @category Configuration\n */\nexport interface ConfigValidationResult {\n /** Whether the configuration is valid */\n valid: boolean;\n /** List of validation errors */\n errors: string[];\n /** List of validation warnings */\n warnings: string[];\n}\n"],"mappings":"AAgpBO,SAAS,eACd,QAC+C;AAC/C,SAAO,kBAAkB;AAC3B;AAcO,SAAS,iBACd,QAC8B;AAC9B,SACE,kBAAkB,UAClB,aAAa,UACb,EAAE,kBAAkB;AAExB;AAcO,SAAS,oBACd,QACiC;AACjC,SACE,aAAa,UACb,EAAE,kBAAkB,WACpB,EAAE,kBAAkB,WACpB,EAAE,aAAa;AAEnB;AAiBO,SAAS,cAAc,QAA2C;AACvE,SAAO,aAAa,UAAU,EAAE,kBAAkB;AACpD;AAiBO,SAAS,iBACd,QACiC;AACjC,SACE,OAAO,SAAS,cAAc,UAC9B,OAAO,KAAK,OAAO,QAAQ,SAAS,EAAE,SAAS;AAEnD;","names":[]}
1
+ {"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["import type { WalletClient, PublicClient, Account, Address, Chain } from \"viem\";\nimport type { VanaChainId, VanaChain } from \"./chains\";\nimport type {\n StorageProvider,\n StorageUploadResult,\n StorageListOptions,\n} from \"./storage\";\n\nimport type { RelayerConfig } from \"./relayer\";\nimport type { IOperationStore, IRelayerStateStore } from \"./operationStore\";\n\n/**\n * Marker interface to indicate that a Vana instance has storage configured.\n * Used for compile-time type safety to ensure storage-dependent methods\n * are only called on properly configured instances.\n *\n * @category Configuration\n */\nexport interface StorageRequiredMarker {\n readonly __storageRequired: true;\n}\n\n/**\n * Configures storage providers for SDK file operations.\n *\n * @remarks\n * Supports multiple backends with automatic fallback.\n * IPFS for decentralization, Pinata for reliability,\n * Google Drive for development, custom for flexibility.\n *\n * **Provider Selection:**\n * - IPFS: Decentralized, permanent storage ideal for production\n * - Pinata: Managed IPFS with guaranteed availability\n * - Google Drive: Centralized, suitable for development/testing\n * - Custom providers: Implement StorageProvider interface\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storage: StorageConfig = {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' }),\n * pinata: new PinataStorage({ apiKey: 'key', secretKey: 'secret' })\n * },\n * defaultProvider: 'ipfs'\n * };\n * ```\n */\nexport interface StorageConfig {\n /**\n * Map of provider name to storage provider instance.\n * Common provider names: \"ipfs\", \"pinata\", \"googledrive\", \"s3\".\n * Custom names allowed for custom provider implementations.\n */\n providers: Record<string, StorageProvider>;\n /**\n * Default provider name to use when none specified.\n * Must match a key in the providers map. Falls back to first provider if not specified.\n */\n defaultProvider?: string;\n}\n\n/**\n * Download relayer callbacks for proxying CORS-restricted downloads.\n *\n * Provides a callback to proxy download requests through your application server\n * when direct browser access fails due to CORS restrictions (e.g., Google Drive).\n *\n * IMPORTANT SECURITY REQUIREMENTS for your proxy endpoint:\n * 1. MUST block requests to private/internal IPs (SSRF protection)\n * 2. SHOULD NOT restrict domains (files can be hosted anywhere)\n *\n * @category Configuration\n * @example Client-side implementation:\n * ```typescript\n * const downloadRelayer: DownloadRelayerCallbacks = {\n * async proxyDownload(url) {\n * const response = await fetch('/api/proxy', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ url })\n * });\n * return response.blob();\n * }\n * };\n * ```\n *\n * @example Server-side proxy endpoint (Next.js):\n * ```typescript\n * // /api/proxy/route.ts\n * import { promises as dns } from 'dns';\n * import { isIPv4 } from 'net';\n *\n * async function handleProxy(url: string) {\n * const { hostname } = new URL(url);\n *\n * // Resolve hostname to IP (handle localhost specially)\n * const ip = hostname === 'localhost' ? '127.0.0.1' :\n * isIPv4(hostname) ? hostname :\n * await dns.lookup(hostname).then(r => r.address);\n *\n * // SSRF Protection: Block private/internal IPs\n * if (isIPv4(ip)) {\n * const [a, b] = ip.split('.').map(Number);\n * if (a === 10 || a === 127 || a === 0 ||\n * (a === 172 && b >= 16 && b <= 31) ||\n * (a === 192 && b === 168) ||\n * (a === 169 && b === 254) ||\n * a >= 224) { // Also block multicast/reserved\n * return new Response('Private/internal addresses not allowed', { status: 403 });\n * }\n * }\n *\n * // Proxy the request\n * const response = await fetch(url, { redirect: 'manual' });\n *\n * // Handle redirects (with recursion limit)\n * if (response.status >= 301 && response.status <= 308) {\n * const location = response.headers.get('location');\n * if (location) return handleProxy(new URL(location, url).href);\n * }\n *\n * const data = await response.arrayBuffer();\n * return new Response(data, {\n * headers: {\n * 'Content-Type': response.headers.get('content-type') || 'application/octet-stream',\n * 'Access-Control-Allow-Origin': '*'\n * }\n * });\n * }\n * ```\n */\nexport interface DownloadRelayerCallbacks {\n /**\n * Proxy a download request through your application server\n *\n * @param url - The URL to download from\n * @returns Promise resolving to the downloaded content as a Blob\n */\n proxyDownload: (url: string) => Promise<Blob>;\n}\n\n/**\n * Storage callback functions for flexible storage operations.\n *\n * Instead of hardcoding storage behavior (HTTP endpoints, etc.), users can provide\n * custom callback functions to handle storage operations in any way they choose.\n * This pattern matches the relayer callbacks approach, providing maximum flexibility.\n *\n * @category Configuration\n * @example\n * ```typescript\n * const storageCallbacks: StorageCallbacks = {\n * async upload(blob, filename, metadata) {\n * // Custom implementation - could be HTTP, S3, local filesystem, etc.\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type,\n * metadata: data.metadata\n * };\n * },\n *\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n * ```\n */\nexport interface StorageCallbacks {\n /**\n * Upload a blob to storage\n *\n * @param blob - The data to upload\n * @param filename - Optional filename hint\n * @param metadata - Optional metadata for the upload\n * @returns Upload result with identifier and metadata\n */\n upload: (\n blob: Blob,\n filename?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<StorageUploadResult>;\n\n /**\n * Download data from storage\n *\n * @param identifier - The storage identifier (could be URL, hash, path, or any unique ID)\n * @param options - Optional download options\n * @returns The downloaded data as a Blob\n */\n download: (\n identifier: string,\n options?: StorageDownloadOptions,\n ) => Promise<Blob>;\n\n /**\n * List stored items (optional)\n *\n * @param prefix - Optional prefix to filter results\n * @param options - Optional listing options\n * @returns Array of storage items with metadata\n */\n list?: (\n prefix?: string,\n options?: StorageListOptions,\n ) => Promise<StorageListResult>;\n\n /**\n * Delete a stored item (optional)\n *\n * @param identifier - The storage identifier to delete\n * @returns Promise that resolves to true if deletion succeeded\n */\n delete?: (identifier: string) => Promise<boolean>;\n\n /**\n * Extract identifier from a URL or return as-is (optional)\n * Used for backward compatibility with URL-based systems\n *\n * @param url - The URL to extract from\n * @returns The extracted identifier\n */\n extractIdentifier?: (url: string) => string;\n}\n\n/**\n * Options for storage download operations\n *\n * @category Configuration\n */\nexport interface StorageDownloadOptions {\n /** Optional HTTP headers */\n headers?: Record<string, string>;\n /** Optional abort signal for cancellation */\n signal?: AbortSignal;\n /** Optional byte range for partial downloads */\n range?: { start?: number; end?: number };\n}\n\n/**\n * Result from storage list operations\n *\n * @category Configuration\n */\nexport interface StorageListResult {\n /** Array of storage items */\n items: Array<{\n /** Item identifier */\n identifier: string;\n /** Item size in bytes */\n size?: number;\n /** Last modified timestamp */\n lastModified?: Date;\n /** Item metadata */\n metadata?: Record<string, unknown>;\n }>;\n /** Continuation token for pagination */\n continuationToken?: string;\n /** Whether more results are available */\n hasMore?: boolean;\n}\n\n/**\n * Base configuration interface without storage requirements\n *\n * @category Configuration\n */\nexport interface BaseConfig {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /**\n * Optional storage providers configuration for file upload/download.\n * Required for: upload(), grant() without pre-stored URLs, schema operations.\n * See StorageConfig for provider selection guidance.\n */\n storage?: StorageConfig;\n\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n * Obtain chain-specific URLs from Vana documentation or deployment info.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n * Order matters: first successful gateway is used.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n\n /**\n * Optional operation store for tracking async relayed transactions.\n * When provided with a relayer, enables resilient transaction management\n * with polling support for pending operations.\n *\n * @example\n * ```typescript\n * const vana = createVana({\n * walletClient,\n * relayer: '/api/relay',\n * operationStore: myOperationStore\n * });\n * ```\n */\n operationStore?: IOperationStore | IRelayerStateStore;\n}\n\n/**\n * Base configuration interface that requires storage for storage-dependent operations\n *\n * @category Configuration\n */\nexport interface BaseConfigWithStorage {\n /**\n * Optional relayer configuration for handling gasless transactions.\n * Can be a URL string for convenience, or a callback for full control.\n *\n * @example\n * ```typescript\n * // Simple URL (SDK handles transport)\n * relayer: '/api/relay'\n *\n * // Full control with callback\n * relayer: async (request) => {\n * const response = await fetch('/api/relay', {\n * method: 'POST',\n * body: JSON.stringify(request)\n * });\n * return response.json();\n * }\n * ```\n */\n relayer?: RelayerConfig;\n\n /**\n * Optional download relayer for proxying CORS-restricted downloads.\n * Provides a proxy mechanism for files stored on servers with CORS restrictions.\n */\n downloadRelayer?: DownloadRelayerCallbacks;\n\n /** Required storage providers configuration for file upload/download */\n storage: StorageConfig;\n /**\n * Optional subgraph URL for querying user files and permissions.\n * If not provided, defaults to the built-in subgraph URL for the current chain.\n * Can be overridden per method call if needed.\n */\n subgraphUrl?: string;\n /**\n * Optional default IPFS gateways to use for fetching files.\n * These gateways will be used by default in fetchFromIPFS unless overridden per-call.\n * If not provided, the SDK will use public gateways.\n *\n * @example ['https://gateway.pinata.cloud', 'https://ipfs.io']\n */\n ipfsGateways?: string[];\n /**\n * Default personal server base URL for server operations.\n * Required for ServerController methods like getIdentity(), createOperation(), etc.\n *\n * @example 'https://my-personal-server.example.com'\n */\n defaultPersonalServerUrl?: string;\n\n /**\n * Optional operation store for tracking async relayed transactions.\n * When provided with a relayer, enables resilient transaction management\n * with polling support for pending operations.\n */\n operationStore?: IOperationStore | IRelayerStateStore;\n}\n\n/**\n * Configuration with wallet client\n *\n * @category Configuration\n */\nexport interface WalletConfig extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with wallet client that requires storage\n *\n * @category Configuration\n */\nexport interface WalletConfigWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient & {\n chain: VanaChain;\n };\n}\n\n/**\n * Configuration with chain and account details\n *\n * @category Configuration\n */\nexport interface ChainConfig extends BaseConfig {\n /**\n * The chain ID for Vana network.\n * Supported: 14800 (Vana Mainnet), 14801 (Moksha Testnet), 31337 (Local Development).\n * Use chain constants from '@vana/sdk' for type safety.\n */\n chainId: VanaChainId;\n /**\n * RPC URL for the chain (optional, will use default for the chain if not provided).\n * Default URLs: mainnet (https://rpc.vana.org), testnet (https://rpc.moksha.vana.org).\n * Override for custom nodes or local development.\n */\n rpcUrl?: string;\n /**\n * Optional account for signing transactions.\n * Can be: privateKeyToAccount(), mnemonicToAccount(), or custom Account implementation.\n * Required for write operations; read-only operations work without account.\n */\n account?: Account;\n}\n\n/**\n * Configuration with chain and account details that requires storage\n *\n * @category Configuration\n */\nexport interface ChainConfigWithStorage extends BaseConfigWithStorage {\n /** The chain ID for Vana network */\n chainId: VanaChainId;\n /** RPC URL for the chain (optional, will use default for the chain if not provided) */\n rpcUrl?: string;\n /** Optional account for signing transactions */\n account?: Account;\n}\n\n/**\n * Configuration with wallet client and optional public client\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWallet extends BaseConfig {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnly extends BaseConfig {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnly extends BaseConfig {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Configuration with wallet client and optional public client that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigWithWalletWithStorage extends BaseConfigWithStorage {\n /** The viem WalletClient instance used for signing transactions */\n walletClient: WalletClient;\n /** Optional PublicClient for read operations (derived from wallet if not provided) */\n publicClient?: PublicClient;\n}\n\n/**\n * Configuration for read-only operations with public client and address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigReadOnlyWithStorage extends BaseConfigWithStorage {\n /** The viem PublicClient instance for read operations */\n publicClient: PublicClient;\n /** The user's address for read operations */\n address: Address;\n}\n\n/**\n * Configuration for minimal read-only operations with just an address that requires storage\n *\n * @category Configuration\n */\nexport interface VanaConfigAddressOnlyWithStorage\n extends BaseConfigWithStorage {\n /** The user's address for read operations */\n address: Address;\n /** Optional chain configuration (will use default if not provided) */\n chain?: Chain;\n}\n\n/**\n * Main configuration interface for initializing the Vana SDK.\n *\n * The SDK supports three initialization modes:\n * 1. Full mode with wallet client for signing transactions\n * 2. Read-only mode with public client and address for read operations\n * 3. Minimal mode with just an address and optional chain\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Mode 1: Full configuration with wallet client\n * const configWithWallet: VanaConfig = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * })\n * };\n *\n * // Mode 2: Read-only with public client and address\n * const configReadOnly: VanaConfig = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...'\n * };\n *\n * // Mode 3: Minimal with just address\n * const configMinimal: VanaConfig = {\n * address: '0x1234...',\n * chain: moksha // optional\n * };\n * ```\n */\nexport type VanaConfig =\n | VanaConfigWithWallet\n | VanaConfigReadOnly\n | VanaConfigAddressOnly\n | WalletConfig\n | ChainConfig;\n\n/**\n * Configuration interface for Vana SDK that requires storage providers.\n *\n * Use this type when you need to ensure storage is configured for operations\n * like file uploads, permission grants without pre-stored URLs, or schema creation.\n * Supports all three initialization modes with required storage.\n *\n * @category Configuration\n * @example\n * ```typescript\n * // Full configuration with wallet client and storage\n * const configWithWallet: VanaConfigWithStorage = {\n * walletClient: createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: moksha,\n * transport: http()\n * }),\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n *\n * // Read-only configuration with storage\n * const configReadOnly: VanaConfigWithStorage = {\n * publicClient: createPublicClient({\n * chain: moksha,\n * transport: http()\n * }),\n * address: '0x1234...',\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' })\n * },\n * defaultProvider: 'ipfs'\n * }\n * };\n * ```\n */\nexport type VanaConfigWithStorage =\n | VanaConfigWithWalletWithStorage\n | VanaConfigReadOnlyWithStorage\n | VanaConfigAddressOnlyWithStorage\n | WalletConfigWithStorage\n | ChainConfigWithStorage;\n\n/**\n * Runtime configuration information\n *\n * @category Configuration\n */\nexport interface RuntimeConfig {\n /** Current chain ID */\n chainId: VanaChainId;\n /** Current chain name */\n chainName: string;\n /** Available storage providers */\n storageProviders: string[];\n /** Default storage provider */\n defaultStorageProvider?: string;\n /** Current relayer configuration */\n relayerConfig?: RelayerConfig;\n}\n\n/**\n * Validates whether a configuration object has a wallet client (any wallet-based config).\n *\n * @param config - The configuration object to check\n * @returns True if the config contains a walletClient\n * @example\n * ```typescript\n * if (isWalletConfig(config)) {\n * console.log('Using wallet client:', config.walletClient.account?.address);\n * } else {\n * console.log('Read-only or chain config');\n * }\n * ```\n */\nexport function isWalletConfig(\n config: VanaConfig,\n): config is VanaConfigWithWallet | WalletConfig {\n return \"walletClient\" in config;\n}\n\n/**\n * Validates whether a configuration object is a read-only config with public client.\n *\n * @param config - The configuration object to check\n * @returns True if the config has publicClient and address but no walletClient\n * @example\n * ```typescript\n * if (isReadOnlyConfig(config)) {\n * console.log('Read-only mode with address:', config.address);\n * }\n * ```\n */\nexport function isReadOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigReadOnly {\n return (\n \"publicClient\" in config &&\n \"address\" in config &&\n !(\"walletClient\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is an address-only config.\n *\n * @param config - The configuration object to check\n * @returns True if the config has only address (and optionally chain) but no clients\n * @example\n * ```typescript\n * if (isAddressOnlyConfig(config)) {\n * console.log('Address-only mode:', config.address);\n * }\n * ```\n */\nexport function isAddressOnlyConfig(\n config: VanaConfig,\n): config is VanaConfigAddressOnly {\n return (\n \"address\" in config &&\n !(\"publicClient\" in config) &&\n !(\"walletClient\" in config) &&\n !(\"chainId\" in config)\n );\n}\n\n/**\n * Validates whether a configuration object is a ChainConfig.\n *\n * @param config - The configuration object to check\n * @returns True if the config is a ChainConfig (contains chainId but not walletClient)\n * @example\n * ```typescript\n * if (isChainConfig(config)) {\n * console.log('Chain ID:', config.chainId);\n * console.log('RPC URL:', config.rpcUrl);\n * } else {\n * console.log('Using pre-configured wallet client');\n * }\n * ```\n */\nexport function isChainConfig(config: VanaConfig): config is ChainConfig {\n return \"chainId\" in config && !(\"walletClient\" in config);\n}\n\n/**\n * Validates whether a configuration has required storage providers.\n *\n * @param config - The configuration object to check\n * @returns True if the config has storage providers configured\n * @example\n * ```typescript\n * if (hasStorageConfig(config)) {\n * // Safe to use storage-dependent operations\n * await vana.data.uploadFile(file);\n * } else {\n * console.log('Storage not configured - some operations may fail');\n * }\n * ```\n */\nexport function hasStorageConfig(\n config: VanaConfig,\n): config is VanaConfigWithStorage {\n return (\n config.storage?.providers !== undefined &&\n Object.keys(config.storage.providers).length > 0\n );\n}\n\n/**\n * Configuration validation options\n *\n * @category Configuration\n */\nexport interface ConfigValidationOptions {\n /** Whether to validate storage providers */\n validateStorage?: boolean;\n /** Whether to validate relayer URL */\n validateRelayer?: boolean;\n /** Whether to validate chain configuration */\n validateChain?: boolean;\n}\n\n/**\n * Configuration validation result\n *\n * @category Configuration\n */\nexport interface ConfigValidationResult {\n /** Whether the configuration is valid */\n valid: boolean;\n /** List of validation errors */\n errors: string[];\n /** List of validation warnings */\n warnings: string[];\n}\n\n/**\n * Marker interface to enforce the presence of operationStore at compile time.\n * This interface is used to ensure that certain operations requiring a relayer\n * can only be called when the SDK has been properly configured with an operation store.\n *\n * @category Configuration\n */\nexport interface RelayerRequiredMarker {\n readonly __relayerConfigured: true;\n}\n"],"mappings":"AAyqBO,SAAS,eACd,QAC+C;AAC/C,SAAO,kBAAkB;AAC3B;AAcO,SAAS,iBACd,QAC8B;AAC9B,SACE,kBAAkB,UAClB,aAAa,UACb,EAAE,kBAAkB;AAExB;AAcO,SAAS,oBACd,QACiC;AACjC,SACE,aAAa,UACb,EAAE,kBAAkB,WACpB,EAAE,kBAAkB,WACpB,EAAE,aAAa;AAEnB;AAiBO,SAAS,cAAc,QAA2C;AACvE,SAAO,aAAa,UAAU,EAAE,kBAAkB;AACpD;AAiBO,SAAS,iBACd,QACiC;AACjC,SACE,OAAO,SAAS,cAAc,UAC9B,OAAO,KAAK,OAAO,QAAQ,SAAS,EAAE,SAAS;AAEnD;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/controller-context.ts"],"sourcesContent":["/**\n * Shared type definitions for controller contexts.\n *\n * @remarks\n * These types ensure consistency across all controllers and prevent drift.\n * Single source of truth following Rich Hickey's principles.\n */\n\nimport type { WalletClient, PublicClient, Address } from \"viem\";\nimport type { VanaPlatformAdapter } from \"../platform/interface\";\nimport type { StorageManager } from \"../storage\";\nimport type { DownloadRelayerCallbacks } from \"./config\";\nimport type { UnifiedRelayerRequest, UnifiedRelayerResponse } from \"./relayer\";\nimport type {\n TransactionResult,\n TransactionWaitOptions,\n Operation,\n PollingOptions,\n} from \"./operations\";\nimport type {\n Contract,\n Fn,\n TypedTransactionResult,\n} from \"../generated/event-types\";\n\n/**\n * Type definition for waitForTransactionEvents function.\n *\n * @remarks\n * This is THE single definition used everywhere to prevent drift.\n * If you need to change the signature, change it here.\n */\nexport type WaitForTransactionEventsFn = <C extends Contract, F extends Fn<C>>(\n transaction: TransactionResult<C, F>,\n options?: TransactionWaitOptions,\n) => Promise<TypedTransactionResult<C, F>>;\n\n/**\n * Type definition for waitForOperation function.\n */\nexport type WaitForOperationFn = <T = unknown>(\n opOrId: Operation<T> | string,\n options?: PollingOptions,\n) => Promise<Operation<T>>;\n\n/**\n * Shared controller context interface.\n *\n * @remarks\n * This is the contract that all controllers depend on.\n * Changing this interface is a breaking change.\n */\nexport interface ControllerContext {\n /** Signs transactions and messages using the user's private key. Optional to support read-only mode. */\n walletClient?: WalletClient;\n /** Queries blockchain state and smart contracts without signing. */\n publicClient: PublicClient;\n /** Address of the user for operations requiring user identification in read-only mode. */\n userAddress: Address;\n /** Signs application-specific operations when different from primary wallet. */\n applicationClient?: WalletClient;\n /** Handles gasless transaction submission through relayer services. */\n relayer?: (request: UnifiedRelayerRequest) => Promise<UnifiedRelayerResponse>;\n /** Proxies CORS-restricted downloads through application server. */\n downloadRelayer?: DownloadRelayerCallbacks;\n /** Manages file upload and download operations across storage providers. */\n storageManager?: StorageManager;\n /** Provides subgraph endpoint for querying indexed blockchain data. */\n subgraphUrl?: string;\n /** Adapts SDK functionality to the current runtime environment. */\n platform: VanaPlatformAdapter;\n /** Validates that storage is available for storage-dependent operations. */\n validateStorageRequired?: () => void;\n /** Checks whether storage is configured without throwing an error. */\n hasStorage?: () => boolean;\n /** Default IPFS gateways to use for fetching files. */\n ipfsGateways?: string[];\n /** Default personal server base URL for server operations. */\n defaultPersonalServerUrl?: string;\n /** Waits for transaction confirmation and parses typed events. */\n waitForTransactionEvents?: WaitForTransactionEventsFn;\n /** Waits for an operation to complete with polling. */\n waitForOperation?: WaitForOperationFn;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/types/controller-context.ts"],"sourcesContent":["/**\n * Shared type definitions for controller contexts.\n *\n * @remarks\n * These types ensure consistency across all controllers and prevent drift.\n * Single source of truth following Rich Hickey's principles.\n */\n\nimport type { WalletClient, PublicClient, Address } from \"viem\";\nimport type { VanaPlatformAdapter } from \"../platform/interface\";\nimport type { StorageManager } from \"../storage\";\nimport type { DownloadRelayerCallbacks } from \"./config\";\nimport type { UnifiedRelayerRequest, UnifiedRelayerResponse } from \"./relayer\";\nimport type {\n TransactionResult,\n TransactionWaitOptions,\n Operation,\n PollingOptions,\n} from \"./operations\";\nimport type { IOperationStore, IRelayerStateStore } from \"./operationStore\";\nimport type {\n Contract,\n Fn,\n TypedTransactionResult,\n} from \"../generated/event-types\";\n\n/**\n * Type definition for waitForTransactionEvents function.\n *\n * @remarks\n * This is THE single definition used everywhere to prevent drift.\n * If you need to change the signature, change it here.\n */\nexport type WaitForTransactionEventsFn = <C extends Contract, F extends Fn<C>>(\n transaction: TransactionResult<C, F>,\n options?: TransactionWaitOptions,\n) => Promise<TypedTransactionResult<C, F>>;\n\n/**\n * Type definition for waitForOperation function.\n */\nexport type WaitForOperationFn = (\n opOrId: Operation | string,\n options?: PollingOptions,\n) => Promise<Operation>;\n\n/**\n * Shared controller context interface.\n *\n * @remarks\n * This is the contract that all controllers depend on.\n * Changing this interface is a breaking change.\n */\nexport interface ControllerContext {\n /** Signs transactions and messages using the user's private key. Optional to support read-only mode. */\n walletClient?: WalletClient;\n /** Queries blockchain state and smart contracts without signing. */\n publicClient: PublicClient;\n /** Address of the user for operations requiring user identification in read-only mode. */\n userAddress: Address;\n /** Signs application-specific operations when different from primary wallet. */\n applicationClient?: WalletClient;\n /** Handles gasless transaction submission through relayer services. */\n relayer?: (request: UnifiedRelayerRequest) => Promise<UnifiedRelayerResponse>;\n /** Proxies CORS-restricted downloads through application server. */\n downloadRelayer?: DownloadRelayerCallbacks;\n /** Manages file upload and download operations across storage providers. */\n storageManager?: StorageManager;\n /** Provides subgraph endpoint for querying indexed blockchain data. */\n subgraphUrl?: string;\n /** Adapts SDK functionality to the current runtime environment. */\n platform: VanaPlatformAdapter;\n /** Validates that storage is available for storage-dependent operations. */\n validateStorageRequired?: () => void;\n /** Checks whether storage is configured without throwing an error. */\n hasStorage?: () => boolean;\n /** Default IPFS gateways to use for fetching files. */\n ipfsGateways?: string[];\n /** Default personal server base URL for server operations. */\n defaultPersonalServerUrl?: string;\n /** Waits for transaction confirmation and parses typed events. */\n waitForTransactionEvents?: WaitForTransactionEventsFn;\n /** Waits for an operation to complete with polling. */\n waitForOperation?: WaitForOperationFn;\n /** Tracks async relayed transactions for resilient management. */\n operationStore?: IOperationStore | IRelayerStateStore;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -11,6 +11,7 @@ import type { StorageManager } from "../storage";
11
11
  import type { DownloadRelayerCallbacks } from "./config";
12
12
  import type { UnifiedRelayerRequest, UnifiedRelayerResponse } from "./relayer";
13
13
  import type { TransactionResult, TransactionWaitOptions, Operation, PollingOptions } from "./operations";
14
+ import type { IOperationStore, IRelayerStateStore } from "./operationStore";
14
15
  import type { Contract, Fn, TypedTransactionResult } from "../generated/event-types";
15
16
  /**
16
17
  * Type definition for waitForTransactionEvents function.
@@ -23,7 +24,7 @@ export type WaitForTransactionEventsFn = <C extends Contract, F extends Fn<C>>(t
23
24
  /**
24
25
  * Type definition for waitForOperation function.
25
26
  */
26
- export type WaitForOperationFn = <T = unknown>(opOrId: Operation<T> | string, options?: PollingOptions) => Promise<Operation<T>>;
27
+ export type WaitForOperationFn = (opOrId: Operation | string, options?: PollingOptions) => Promise<Operation>;
27
28
  /**
28
29
  * Shared controller context interface.
29
30
  *
@@ -62,4 +63,6 @@ export interface ControllerContext {
62
63
  waitForTransactionEvents?: WaitForTransactionEventsFn;
63
64
  /** Waits for an operation to complete with polling. */
64
65
  waitForOperation?: WaitForOperationFn;
66
+ /** Tracks async relayed transactions for resilient management. */
67
+ operationStore?: IOperationStore | IRelayerStateStore;
65
68
  }