@opendatalabs/vana-sdk 0.1.0-alpha.c17525f → 0.1.0-alpha.cb72de2

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 (43) hide show
  1. package/README.md +207 -436
  2. package/dist/chains.browser.cjs +4 -1
  3. package/dist/chains.browser.cjs.map +1 -1
  4. package/dist/chains.browser.d.cts +2 -1
  5. package/dist/chains.browser.d.ts +2 -1
  6. package/dist/chains.browser.js +3 -1
  7. package/dist/chains.browser.js.map +1 -1
  8. package/dist/chains.cjs +4 -1
  9. package/dist/chains.cjs.map +1 -1
  10. package/dist/chains.d.cts +1 -1
  11. package/dist/chains.d.ts +1 -1
  12. package/dist/chains.js +3 -1
  13. package/dist/chains.js.map +1 -1
  14. package/dist/chains.node.cjs +4 -1
  15. package/dist/chains.node.cjs.map +1 -1
  16. package/dist/chains.node.d.cts +1 -1
  17. package/dist/chains.node.d.ts +1 -1
  18. package/dist/chains.node.js +3 -1
  19. package/dist/chains.node.js.map +1 -1
  20. package/dist/index.browser.d.ts +5835 -3600
  21. package/dist/index.browser.js +2059 -924
  22. package/dist/index.browser.js.map +1 -1
  23. package/dist/index.d.cts +1 -31179
  24. package/dist/index.node.cjs +2145 -981
  25. package/dist/index.node.cjs.map +1 -1
  26. package/dist/index.node.d.cts +5871 -3608
  27. package/dist/index.node.d.ts +5871 -3608
  28. package/dist/index.node.js +2102 -940
  29. package/dist/index.node.js.map +1 -1
  30. package/dist/platform.browser.d.ts +69 -0
  31. package/dist/platform.browser.js +79 -181
  32. package/dist/platform.browser.js.map +1 -1
  33. package/dist/platform.cjs +122 -197
  34. package/dist/platform.cjs.map +1 -1
  35. package/dist/platform.js +122 -197
  36. package/dist/platform.js.map +1 -1
  37. package/dist/platform.node.cjs +122 -197
  38. package/dist/platform.node.cjs.map +1 -1
  39. package/dist/platform.node.d.cts +70 -0
  40. package/dist/platform.node.d.ts +70 -0
  41. package/dist/platform.node.js +122 -197
  42. package/dist/platform.node.js.map +1 -1
  43. package/package.json +24 -18
@@ -29,10 +29,27 @@ function parseEncryptedDataBuffer(encryptedBuffer) {
29
29
  mac: encryptedBuffer.slice(-32)
30
30
  };
31
31
  }
32
- function uint8ArrayToHex(array) {
33
- return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join(
34
- ""
35
- );
32
+ function toBase64(str) {
33
+ if (typeof Buffer !== "undefined") {
34
+ return Buffer.from(str, "utf8").toString("base64");
35
+ } else if (typeof btoa !== "undefined") {
36
+ return btoa(str);
37
+ } else {
38
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
39
+ let result = "";
40
+ let i = 0;
41
+ while (i < str.length) {
42
+ const a = str.charCodeAt(i++);
43
+ const b = i < str.length ? str.charCodeAt(i++) : 0;
44
+ const c = i < str.length ? str.charCodeAt(i++) : 0;
45
+ const bitmap = a << 16 | b << 8 | c;
46
+ result += chars.charAt(bitmap >> 18 & 63);
47
+ result += chars.charAt(bitmap >> 12 & 63);
48
+ result += i - 2 < str.length ? chars.charAt(bitmap >> 6 & 63) : "=";
49
+ result += i - 1 < str.length ? chars.charAt(bitmap & 63) : "=";
50
+ }
51
+ return result;
52
+ }
36
53
  }
37
54
  var init_crypto_utils = __esm({
38
55
  "src/platform/shared/crypto-utils.ts"() {
@@ -84,147 +101,59 @@ var init_error_utils = __esm({
84
101
 
85
102
  // src/platform/browser.ts
86
103
  import * as openpgp from "openpgp";
87
- function hexToUint8Array(hex) {
88
- const result = new Uint8Array(hex.length / 2);
89
- for (let i = 0; i < hex.length; i += 2) {
90
- result[i / 2] = parseInt(hex.substr(i, 2), 16);
91
- }
92
- return result;
93
- }
94
- var BrowserECDH, BrowserCryptoAdapter, BrowserPGPAdapter, BrowserHttpAdapter, BrowserPlatformAdapter, browserPlatformAdapter;
104
+ var BrowserCryptoAdapter, BrowserPGPAdapter, BrowserHttpAdapter, BrowserCacheAdapter, BrowserPlatformAdapter, browserPlatformAdapter;
95
105
  var init_browser = __esm({
96
106
  "src/platform/browser.ts"() {
97
107
  "use strict";
98
108
  init_crypto_utils();
99
109
  init_pgp_utils();
100
110
  init_error_utils();
101
- BrowserECDH = class {
102
- async generateKeyPair() {
103
- const keyPair = await crypto.subtle.generateKey(
104
- {
105
- name: "ECDH",
106
- namedCurve: "P-256"
107
- },
108
- true,
109
- ["deriveKey", "deriveBits"]
110
- );
111
- return keyPair;
112
- }
113
- async encrypt(publicKeyHex, message) {
114
- const ephemeralKeyPair = await this.generateKeyPair();
115
- const publicKeyData = hexToUint8Array(publicKeyHex);
116
- const importedPublicKey = await crypto.subtle.importKey(
117
- "raw",
118
- publicKeyData,
119
- { name: "ECDH", namedCurve: "P-256" },
120
- false,
121
- []
122
- );
123
- const sharedKey = await crypto.subtle.deriveKey(
124
- { name: "ECDH", public: importedPublicKey },
125
- ephemeralKeyPair.privateKey,
126
- { name: "AES-GCM", length: 256 },
127
- false,
128
- ["encrypt"]
129
- );
130
- const iv = crypto.getRandomValues(new Uint8Array(12));
131
- const encoder = new TextEncoder();
132
- const data = encoder.encode(message);
133
- const encrypted = await crypto.subtle.encrypt(
134
- { name: "AES-GCM", iv },
135
- sharedKey,
136
- data
137
- );
138
- const ephemeralPublicKeyData = await crypto.subtle.exportKey(
139
- "raw",
140
- ephemeralKeyPair.publicKey
141
- );
142
- return JSON.stringify({
143
- encrypted: Array.from(new Uint8Array(encrypted)),
144
- iv: Array.from(iv),
145
- ephemeralPublicKey: Array.from(new Uint8Array(ephemeralPublicKeyData)),
146
- publicKey: publicKeyHex
147
- });
148
- }
149
- async decrypt(privateKeyHex, encryptedData) {
150
- try {
151
- const data = JSON.parse(encryptedData);
152
- if (!data.encrypted || !data.iv || !data.ephemeralPublicKey) {
153
- throw new Error("Invalid encrypted data format");
154
- }
155
- const privateKeyData = hexToUint8Array(privateKeyHex);
156
- const importedPrivateKey = await crypto.subtle.importKey(
157
- "pkcs8",
158
- privateKeyData,
159
- { name: "ECDH", namedCurve: "P-256" },
160
- false,
161
- ["deriveKey"]
162
- );
163
- const ephemeralPublicKey = await crypto.subtle.importKey(
164
- "raw",
165
- new Uint8Array(data.ephemeralPublicKey),
166
- { name: "ECDH", namedCurve: "P-256" },
167
- false,
168
- []
169
- );
170
- const sharedKey = await crypto.subtle.deriveKey(
171
- { name: "ECDH", public: ephemeralPublicKey },
172
- importedPrivateKey,
173
- { name: "AES-GCM", length: 256 },
174
- false,
175
- ["decrypt"]
176
- );
177
- const decrypted = await crypto.subtle.decrypt(
178
- { name: "AES-GCM", iv: new Uint8Array(data.iv) },
179
- sharedKey,
180
- new Uint8Array(data.encrypted)
181
- );
182
- return new TextDecoder().decode(decrypted);
183
- } catch (error) {
184
- throw new Error(
185
- `Decryption failed: ${error instanceof Error ? error.message : "Unknown error"}`
186
- );
187
- }
188
- }
189
- };
190
111
  BrowserCryptoAdapter = class {
191
112
  async encryptWithPublicKey(data, publicKeyHex) {
192
113
  try {
193
- const ecdh = new BrowserECDH();
194
- return await ecdh.encrypt(publicKeyHex, data);
114
+ const eccrypto = await import("eccrypto-js");
115
+ const publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
116
+ const encrypted = await eccrypto.encrypt(
117
+ publicKeyBuffer,
118
+ Buffer.from(data, "utf8")
119
+ );
120
+ const result = Buffer.concat([
121
+ encrypted.iv,
122
+ encrypted.ephemPublicKey,
123
+ encrypted.ciphertext,
124
+ encrypted.mac
125
+ ]);
126
+ return result.toString("hex");
195
127
  } catch (error) {
196
128
  throw new Error(`Encryption failed: ${error}`);
197
129
  }
198
130
  }
199
131
  async decryptWithPrivateKey(encryptedData, privateKeyHex) {
200
132
  try {
201
- const ecdh = new BrowserECDH();
202
- return await ecdh.decrypt(privateKeyHex, encryptedData);
133
+ const eccrypto = await import("eccrypto-js");
134
+ const privateKeyBuffer = processWalletPrivateKey(privateKeyHex);
135
+ const encryptedBuffer = Buffer.from(encryptedData, "hex");
136
+ const { iv, ephemPublicKey, ciphertext, mac } = parseEncryptedDataBuffer(encryptedBuffer);
137
+ const encryptedObj = { iv, ephemPublicKey, ciphertext, mac };
138
+ const decryptedBuffer = await eccrypto.decrypt(
139
+ privateKeyBuffer,
140
+ encryptedObj
141
+ );
142
+ return decryptedBuffer.toString("utf8");
203
143
  } catch (error) {
204
144
  throw new Error(`Decryption failed: ${error}`);
205
145
  }
206
146
  }
207
147
  async generateKeyPair() {
208
148
  try {
209
- const keyPair = await crypto.subtle.generateKey(
210
- {
211
- name: "ECDH",
212
- namedCurve: "P-256"
213
- },
214
- true,
215
- ["deriveKey", "deriveBits"]
216
- );
217
- const publicKeyBuffer = await crypto.subtle.exportKey(
218
- "raw",
219
- keyPair.publicKey
220
- );
221
- const privateKeyBuffer = await crypto.subtle.exportKey(
222
- "pkcs8",
223
- keyPair.privateKey
224
- );
149
+ const eccrypto = await import("eccrypto-js");
150
+ const privateKeyBytes = new Uint8Array(32);
151
+ crypto.getRandomValues(privateKeyBytes);
152
+ const privateKey = Buffer.from(privateKeyBytes);
153
+ const publicKey = eccrypto.getPublicCompressed(privateKey);
225
154
  return {
226
- publicKey: uint8ArrayToHex(new Uint8Array(publicKeyBuffer)),
227
- privateKey: uint8ArrayToHex(new Uint8Array(privateKeyBuffer))
155
+ privateKey: privateKey.toString("hex"),
156
+ publicKey: publicKey.toString("hex")
228
157
  };
229
158
  } catch (error) {
230
159
  throw wrapCryptoError("key generation", error);
@@ -234,65 +163,9 @@ var init_browser = __esm({
234
163
  try {
235
164
  const eccrypto = await import("eccrypto-js");
236
165
  const uncompressedKey = processWalletPublicKey(publicKey);
237
- const iv = Buffer.from([
238
- 1,
239
- 2,
240
- 3,
241
- 4,
242
- 5,
243
- 6,
244
- 7,
245
- 8,
246
- 9,
247
- 10,
248
- 11,
249
- 12,
250
- 13,
251
- 14,
252
- 15,
253
- 16
254
- ]);
255
- const ephemeralKey = Buffer.from([
256
- 17,
257
- 34,
258
- 51,
259
- 68,
260
- 85,
261
- 102,
262
- 119,
263
- 136,
264
- 153,
265
- 170,
266
- 187,
267
- 204,
268
- 221,
269
- 238,
270
- 255,
271
- 0,
272
- 16,
273
- 32,
274
- 48,
275
- 64,
276
- 80,
277
- 96,
278
- 112,
279
- 128,
280
- 144,
281
- 160,
282
- 176,
283
- 192,
284
- 208,
285
- 224,
286
- 240,
287
- 0
288
- ]);
289
166
  const encryptedBuffer = await eccrypto.encrypt(
290
167
  uncompressedKey,
291
- Buffer.from(data),
292
- {
293
- iv,
294
- ephemPrivateKey: ephemeralKey
295
- }
168
+ Buffer.from(data)
296
169
  );
297
170
  const result = Buffer.concat([
298
171
  encryptedBuffer.iv,
@@ -407,15 +280,62 @@ var init_browser = __esm({
407
280
  return fetch(url, options);
408
281
  }
409
282
  };
283
+ BrowserCacheAdapter = class {
284
+ constructor() {
285
+ __publicField(this, "prefix", "vana_cache_");
286
+ }
287
+ get(key) {
288
+ try {
289
+ if (typeof sessionStorage === "undefined") {
290
+ return null;
291
+ }
292
+ return sessionStorage.getItem(this.prefix + key);
293
+ } catch {
294
+ return null;
295
+ }
296
+ }
297
+ set(key, value) {
298
+ try {
299
+ if (typeof sessionStorage !== "undefined") {
300
+ sessionStorage.setItem(this.prefix + key, value);
301
+ }
302
+ } catch {
303
+ }
304
+ }
305
+ delete(key) {
306
+ try {
307
+ if (typeof sessionStorage !== "undefined") {
308
+ sessionStorage.removeItem(this.prefix + key);
309
+ }
310
+ } catch {
311
+ }
312
+ }
313
+ clear() {
314
+ try {
315
+ if (typeof sessionStorage === "undefined") {
316
+ return;
317
+ }
318
+ const keys = Object.keys(sessionStorage);
319
+ for (const key of keys) {
320
+ if (key.startsWith(this.prefix)) {
321
+ sessionStorage.removeItem(key);
322
+ }
323
+ }
324
+ } catch {
325
+ }
326
+ }
327
+ };
410
328
  BrowserPlatformAdapter = class {
411
329
  constructor() {
412
330
  __publicField(this, "crypto");
413
331
  __publicField(this, "pgp");
414
332
  __publicField(this, "http");
333
+ __publicField(this, "cache");
415
334
  __publicField(this, "platform", "browser");
416
335
  this.crypto = new BrowserCryptoAdapter();
417
336
  this.pgp = new BrowserPGPAdapter();
418
337
  this.http = new BrowserHttpAdapter();
338
+ this.cache = new BrowserCacheAdapter();
419
339
  }
420
340
  };
421
341
  browserPlatformAdapter = new BrowserPlatformAdapter();
@@ -539,6 +459,9 @@ function isWalletConfig(config) {
539
459
  function isChainConfig(config) {
540
460
  return "chainId" in config && !("walletClient" in config);
541
461
  }
462
+ function hasStorageConfig(config) {
463
+ return config.storage?.providers !== void 0 && Object.keys(config.storage.providers).length > 0;
464
+ }
542
465
 
543
466
  // src/types/chains.ts
544
467
  function isVanaChainId(chainId) {
@@ -562,8 +485,8 @@ var StorageError = class extends Error {
562
485
  import Ajv from "ajv";
563
486
  import addFormats from "ajv-formats";
564
487
 
565
- // src/schemas/dataContract.schema.json
566
- var dataContract_schema_default = {
488
+ // src/schemas/dataSchema.schema.json
489
+ var dataSchema_schema_default = {
567
490
  $id: "https://vana.org/data-schema.json",
568
491
  $schema: "http://json-schema.org/draft-07/schema#",
569
492
  title: "Schema",
@@ -635,7 +558,7 @@ var SchemaValidator = class {
635
558
  strict: false
636
559
  });
637
560
  addFormats(this.ajv);
638
- this.dataSchemaValidator = this.ajv.compile(dataContract_schema_default);
561
+ this.dataSchemaValidator = this.ajv.compile(dataSchema_schema_default);
639
562
  }
640
563
  /**
641
564
  * Validates a data schema against the Vana meta-schema
@@ -834,55 +757,6 @@ function isReplicateAPIResponse(value) {
834
757
  obj.status
835
758
  );
836
759
  }
837
- function isIdentityServerOutput(value) {
838
- console.debug("\u{1F50D} Type Guard: Checking value:", value);
839
- console.debug("\u{1F50D} Type Guard: Value type:", typeof value);
840
- if (typeof value !== "object" || value === null) {
841
- console.debug("\u{1F50D} Type Guard: Failed - not object or null");
842
- return false;
843
- }
844
- const obj = value;
845
- console.debug("\u{1F50D} Type Guard: Object keys:", Object.keys(obj));
846
- console.debug(
847
- "\u{1F50D} Type Guard: user_address:",
848
- obj.user_address,
849
- typeof obj.user_address
850
- );
851
- if (typeof obj.user_address !== "string") {
852
- console.debug("\u{1F50D} Type Guard: Failed - user_address not string");
853
- return false;
854
- }
855
- console.debug(
856
- "\u{1F50D} Type Guard: personal_server:",
857
- obj.personal_server,
858
- typeof obj.personal_server
859
- );
860
- if (typeof obj.personal_server !== "object" || obj.personal_server === null) {
861
- console.debug("\u{1F50D} Type Guard: Failed - personal_server not object or null");
862
- return false;
863
- }
864
- const personalServer = obj.personal_server;
865
- console.debug(
866
- "\u{1F50D} Type Guard: Personal server keys:",
867
- Object.keys(personalServer)
868
- );
869
- console.debug("\u{1F50D} Type Guard: address:", personalServer.address);
870
- console.debug("\u{1F50D} Type Guard: public_key:", personalServer.public_key);
871
- const hasAddress = "address" in personalServer;
872
- const hasPublicKey = "public_key" in personalServer;
873
- console.debug(
874
- "\u{1F50D} Type Guard: Has address:",
875
- hasAddress,
876
- "Has public_key:",
877
- hasPublicKey
878
- );
879
- return hasAddress && hasPublicKey;
880
- }
881
- function isPersonalServerOutput(value) {
882
- if (typeof value !== "object" || value === null) return false;
883
- const obj = value;
884
- return "user_address" in obj && "identity" in obj && typeof obj.user_address === "string" && typeof obj.identity === "object";
885
- }
886
760
  function isAPIResponse(value) {
887
761
  if (typeof value !== "object" || value === null) return false;
888
762
  const obj = value;
@@ -995,276 +869,45 @@ var PermissionError = class extends VanaError {
995
869
  }
996
870
  };
997
871
 
998
- // src/config/addresses.ts
999
- var CONTRACTS = {
1000
- // Core Platform Contracts
1001
- DataPermissions: {
1002
- addresses: {
1003
- 14800: "0x31fb1D48f6B2265A4cAD516BC39E96a18fb7c8de",
1004
- 1480: "0x31fb1D48f6B2265A4cAD516BC39E96a18fb7c8de"
1005
- }
1006
- },
1007
- DataRegistry: {
1008
- addresses: {
1009
- 14800: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C",
1010
- 1480: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C"
1011
- }
1012
- },
1013
- TeePoolPhala: {
1014
- addresses: {
1015
- 14800: "0xE8EC6BD73b23Ad40E6B9a6f4bD343FAc411bD99A",
1016
- 1480: "0xE8EC6BD73b23Ad40E6B9a6f4bD343FAc411bD99A"
1017
- }
1018
- },
1019
- ComputeEngine: {
1020
- addresses: {
1021
- 14800: "0xb2BFe33FA420c45F1Cf1287542ad81ae935447bd",
1022
- 1480: "0xb2BFe33FA420c45F1Cf1287542ad81ae935447bd"
1023
- }
1024
- },
1025
- // Data Access Infrastructure
1026
- DataRefinerRegistry: {
1027
- addresses: {
1028
- 14800: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c",
1029
- 1480: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c"
1030
- }
1031
- },
1032
- QueryEngine: {
1033
- addresses: {
1034
- 14800: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490",
1035
- 1480: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490"
1036
- }
1037
- },
1038
- VanaTreasury: {
1039
- addresses: {
1040
- 14800: "0x94a1E56e555ac48d092f490fB10CDFaB434915eD",
1041
- 1480: "0x94a1E56e555ac48d092f490fB10CDFaB434915eD"
1042
- }
1043
- },
1044
- ComputeInstructionRegistry: {
1045
- addresses: {
1046
- 14800: "0x5786B12b4c6Ba2bFAF0e77Ed30Bf6d32805563A5",
1047
- 1480: "0x5786B12b4c6Ba2bFAF0e77Ed30Bf6d32805563A5"
1048
- }
1049
- },
1050
- // TEE Pool Variants
1051
- TeePoolEphemeralStandard: {
1052
- addresses: {
1053
- 14800: "0xe124bae846D5ec157f75Bd9e68ca87C4d2AB835A",
1054
- 1480: "0xe124bae846D5ec157f75Bd9e68ca87C4d2AB835A"
1055
- }
1056
- },
1057
- TeePoolPersistentStandard: {
1058
- addresses: {
1059
- 14800: "0xe8bB8d0629651Cf33e0845d743976Dc1f0971d76",
1060
- 1480: "0xe8bB8d0629651Cf33e0845d743976Dc1f0971d76"
1061
- }
1062
- },
1063
- TeePoolPersistentGpu: {
1064
- addresses: {
1065
- 14800: "0x1c346Cd74f8551f8fa13f3F4b6b8dAE22338E6a9",
1066
- 1480: "0x1c346Cd74f8551f8fa13f3F4b6b8dAE22338E6a9"
1067
- }
1068
- },
1069
- TeePoolDedicatedStandard: {
1070
- addresses: {
1071
- 14800: "0xf024b7ac5E8417416f53B41ecfa58C8e9396687d",
1072
- 1480: "0xf024b7ac5E8417416f53B41ecfa58C8e9396687d"
1073
- }
1074
- },
1075
- TeePoolDedicatedGpu: {
1076
- addresses: {
1077
- 14800: "0xB1686FA9620bBf851714d1cB47b8a4Bf4664644E",
1078
- 1480: "0xB1686FA9620bBf851714d1cB47b8a4Bf4664644E"
1079
- }
1080
- },
1081
- // DLP Reward System
1082
- VanaEpoch: {
1083
- addresses: {
1084
- 14800: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0",
1085
- 1480: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0"
1086
- }
1087
- },
1088
- DLPRegistry: {
1089
- addresses: {
1090
- 14800: "0x4D59880a924526d1dD33260552Ff4328b1E18a43",
1091
- 1480: "0x4D59880a924526d1dD33260552Ff4328b1E18a43"
1092
- }
1093
- },
1094
- DLPRegistryTreasury: {
1095
- addresses: {
1096
- 14800: "0xb12ce1d27bEeFe39b6F0110b1AB77C21Aa0c9F9a",
1097
- 1480: "0xb12ce1d27bEeFe39b6F0110b1AB77C21Aa0c9F9a"
1098
- }
1099
- },
1100
- DLPPerformance: {
1101
- addresses: {
1102
- 14800: "0x847715C7DB37cF286611182Be0bD333cbfa29cc1",
1103
- 1480: "0x847715C7DB37cF286611182Be0bD333cbfa29cc1"
1104
- }
1105
- },
1106
- DLPRewardDeployer: {
1107
- addresses: {
1108
- 14800: "0xEFD0F9Ba9De70586b7c4189971cF754adC923B04",
1109
- 1480: "0xEFD0F9Ba9De70586b7c4189971cF754adC923B04"
1110
- }
1111
- },
1112
- DLPRewardDeployerTreasury: {
1113
- addresses: {
1114
- 14800: "0xb547ca8Fe4990fe330FeAeb1C2EBb42F925Af5b8",
1115
- 1480: "0xb547ca8Fe4990fe330FeAeb1C2EBb42F925Af5b8"
1116
- }
1117
- },
1118
- DLPRewardSwap: {
1119
- addresses: {
1120
- 14800: "0x7c6862C46830F0fc3bF3FF509EA1bD0EE7267fB0",
1121
- 1480: "0x7c6862C46830F0fc3bF3FF509EA1bD0EE7267fB0"
1122
- }
1123
- },
1124
- SwapHelper: {
1125
- addresses: {
1126
- 14800: "0x55D5e6F73326315bF2E091e97F04f0770e5C54e2",
1127
- 1480: "0x55D5e6F73326315bF2E091e97F04f0770e5C54e2"
1128
- }
1129
- },
1130
- // VanaPool (Staking)
1131
- VanaPoolStaking: {
1132
- addresses: {
1133
- 14800: "0x641C18E2F286c86f96CE95C8ec1EB9fC0415Ca0e",
1134
- 1480: "0x641C18E2F286c86f96CE95C8ec1EB9fC0415Ca0e"
1135
- }
1136
- },
1137
- VanaPoolEntity: {
1138
- addresses: {
1139
- 14800: "0x44f20490A82e1f1F1cC25Dd3BA8647034eDdce30",
1140
- 1480: "0x44f20490A82e1f1F1cC25Dd3BA8647034eDdce30"
1141
- }
1142
- },
1143
- VanaPoolTreasury: {
1144
- addresses: {
1145
- 14800: "0x143BE72CF2541604A7691933CAccd6D9cC17c003",
1146
- 1480: "0x143BE72CF2541604A7691933CAccd6D9cC17c003"
1147
- }
1148
- },
1149
- // DLP Deployment Contracts
1150
- DAT: {
1151
- addresses: {
1152
- 14800: "0xA706b93ccED89f13340673889e29F0a5cd84212d",
1153
- 1480: "0xA706b93ccED89f13340673889e29F0a5cd84212d"
1154
- }
1155
- },
1156
- DATFactory: {
1157
- addresses: {
1158
- 14800: "0x40f8bccF35a75ecef63BC3B1B3E06ffEB9220644",
1159
- 1480: "0x40f8bccF35a75ecef63BC3B1B3E06ffEB9220644"
1160
- }
1161
- },
1162
- DATPausable: {
1163
- addresses: {
1164
- 14800: "0xe69FE86f0B95cC2f8416Fe22815c85DC8887e76e",
1165
- 1480: "0xe69FE86f0B95cC2f8416Fe22815c85DC8887e76e"
1166
- }
1167
- },
1168
- DATVotes: {
1169
- addresses: {
1170
- 14800: "0xaE04c8A77E9B27869eb563720524A9aE0baf1831",
1171
- 1480: "0xaE04c8A77E9B27869eb563720524A9aE0baf1831"
1172
- }
1173
- },
1174
- // Utility Contracts (no ABIs in SDK)
1175
- Multicall3: {
1176
- addresses: {
1177
- 14800: "0xD8d2dFca27E8797fd779F8547166A2d3B29d360E",
1178
- 1480: "0xD8d2dFca27E8797fd779F8547166A2d3B29d360E"
1179
- }
1180
- },
1181
- Multisend: {
1182
- addresses: {
1183
- 14800: "0x8807e8BCDFbaA8c2761760f3FBA37F6f7F2C5b2d",
1184
- 1480: "0x8807e8BCDFbaA8c2761760f3FBA37F6f7F2C5b2d"
1185
- }
1186
- }
1187
- };
1188
- var LEGACY_CONTRACTS = {
1189
- // DEPRECATED: Original Intel SGX TeePool (PRO-347)
1190
- TeePool: {
1191
- addresses: {
1192
- 14800: "0x3c92fD91639b41f13338CE62f19131e7d19eaa0D",
1193
- 1480: "0x3c92fD91639b41f13338CE62f19131e7d19eaa0D"
1194
- }
1195
- },
1196
- // DEPRECATED: DLPRoot system (replaced by VanaPool + DLPRewards)
1197
- DLPRootEpoch: {
1198
- addresses: {
1199
- 14800: "0xc3d176cF6BccFCB9225b53B87a95147218e1537F",
1200
- 1480: "0xc3d176cF6BccFCB9225b53B87a95147218e1537F"
1201
- }
1202
- },
1203
- DLPRootCore: {
1204
- addresses: {
1205
- 14800: "0x0aBa5e28228c323A67712101d61a54d4ff5720FD",
1206
- 1480: "0x0aBa5e28228c323A67712101d61a54d4ff5720FD"
1207
- }
1208
- },
1209
- DLPRoot: {
1210
- addresses: {
1211
- 14800: "0xff14346dF2B8Fd0c95BF34f1c92e49417b508AD5",
1212
- 1480: "0xff14346dF2B8Fd0c95BF34f1c92e49417b508AD5"
1213
- }
1214
- },
1215
- DLPRootMetrics: {
1216
- addresses: {
1217
- 14800: "0xbb532917B6407c060Afd9Cb7d53527eCb91d6662",
1218
- 1480: "0xbb532917B6407c060Afd9Cb7d53527eCb91d6662"
1219
- }
1220
- },
1221
- DLPRootStakesTreasury: {
1222
- addresses: {
1223
- 14800: "0x52c3260ED5C235fcA43524CF508e29c897318775",
1224
- 1480: "0x52c3260ED5C235fcA43524CF508e29c897318775"
1225
- }
1226
- },
1227
- DLPRootRewardsTreasury: {
1228
- addresses: {
1229
- 14800: "0xDBFb6B8b9E2eCAEbdE64d665cD553dB81e524479",
1230
- 1480: "0xDBFb6B8b9E2eCAEbdE64d665cD553dB81e524479"
1231
- }
1232
- }
1233
- };
1234
- var CONTRACT_ADDRESSES = {
1235
- 14800: Object.fromEntries(
1236
- Object.entries(CONTRACTS).map(([name, info]) => [name, info.addresses[14800]]).filter(([, addr]) => addr)
1237
- ),
1238
- 1480: Object.fromEntries(
1239
- Object.entries(CONTRACTS).map(([name, info]) => [name, info.addresses[1480]]).filter(([, addr]) => addr)
1240
- )
1241
- };
1242
- var UTILITY_ADDRESSES = {
1243
- 14800: {
1244
- Multicall3: CONTRACTS.Multicall3.addresses[14800],
1245
- Multisend: CONTRACTS.Multisend.addresses[14800]
1246
- },
1247
- 1480: {
1248
- Multicall3: CONTRACTS.Multicall3.addresses[1480],
1249
- Multisend: CONTRACTS.Multisend.addresses[1480]
1250
- }
1251
- };
1252
- var LEGACY_ADDRESSES = {
1253
- 14800: Object.fromEntries(
1254
- Object.entries(LEGACY_CONTRACTS).map(([name, info]) => [name, info.addresses[14800]]).filter(([, addr]) => addr)
1255
- ),
1256
- 1480: Object.fromEntries(
1257
- Object.entries(LEGACY_CONTRACTS).map(([name, info]) => [name, info.addresses[1480]]).filter(([, addr]) => addr)
1258
- )
1259
- };
1260
- var getContractAddress = (chainId, contract) => {
1261
- const contractAddress = CONTRACT_ADDRESSES[chainId]?.[contract];
1262
- if (!contractAddress) {
1263
- throw new Error(
1264
- `Contract address not found for ${contract} on chain ${chainId}`
1265
- );
872
+ // src/utils/transactionParsing.ts
873
+ import { parseEventLogs } from "viem";
874
+
875
+ // src/config/eventMappings.ts
876
+ var EVENT_MAPPINGS = {
877
+ // Permission operations
878
+ grant: {
879
+ contract: "DataPermissions",
880
+ event: "PermissionAdded"
881
+ },
882
+ revoke: {
883
+ contract: "DataPermissions",
884
+ event: "PermissionRevoked"
885
+ },
886
+ trustServer: {
887
+ contract: "DataPermissions",
888
+ event: "ServerTrusted"
889
+ },
890
+ untrustServer: {
891
+ contract: "DataPermissions",
892
+ event: "ServerUntrusted"
893
+ },
894
+ // Data registry operations
895
+ addFile: {
896
+ contract: "DataRegistry",
897
+ event: "FileAdded"
898
+ },
899
+ addRefinement: {
900
+ contract: "DataRegistry",
901
+ event: "RefinementAdded"
902
+ },
903
+ updateRefinement: {
904
+ contract: "DataRegistry",
905
+ event: "RefinementUpdated"
906
+ },
907
+ addFilePermission: {
908
+ contract: "DataRegistry",
909
+ event: "PermissionGranted"
1266
910
  }
1267
- return contractAddress;
1268
911
  };
1269
912
 
1270
913
  // src/abi/ComputeEngineImplementation.ts
@@ -7913,6 +7556,12 @@ var DataRefinerRegistryABI = [
7913
7556
  name: "schemaId",
7914
7557
  type: "uint256"
7915
7558
  },
7559
+ {
7560
+ indexed: false,
7561
+ internalType: "string",
7562
+ name: "schemaDefinitionUrl",
7563
+ type: "string"
7564
+ },
7916
7565
  {
7917
7566
  indexed: false,
7918
7567
  internalType: "string",
@@ -8016,7 +7665,7 @@ var DataRefinerRegistryABI = [
8016
7665
  {
8017
7666
  indexed: false,
8018
7667
  internalType: "string",
8019
- name: "typ",
7668
+ name: "dialect",
8020
7669
  type: "string"
8021
7670
  },
8022
7671
  {
@@ -8112,6 +7761,40 @@ var DataRefinerRegistryABI = [
8112
7761
  stateMutability: "nonpayable",
8113
7762
  type: "function"
8114
7763
  },
7764
+ {
7765
+ inputs: [
7766
+ {
7767
+ internalType: "uint256",
7768
+ name: "dlpId",
7769
+ type: "uint256"
7770
+ },
7771
+ {
7772
+ internalType: "string",
7773
+ name: "name",
7774
+ type: "string"
7775
+ },
7776
+ {
7777
+ internalType: "string",
7778
+ name: "schemaDefinitionUrl",
7779
+ type: "string"
7780
+ },
7781
+ {
7782
+ internalType: "string",
7783
+ name: "refinementInstructionUrl",
7784
+ type: "string"
7785
+ }
7786
+ ],
7787
+ name: "addRefiner",
7788
+ outputs: [
7789
+ {
7790
+ internalType: "uint256",
7791
+ name: "",
7792
+ type: "uint256"
7793
+ }
7794
+ ],
7795
+ stateMutability: "nonpayable",
7796
+ type: "function"
7797
+ },
8115
7798
  {
8116
7799
  inputs: [
8117
7800
  {
@@ -8135,7 +7818,7 @@ var DataRefinerRegistryABI = [
8135
7818
  type: "string"
8136
7819
  }
8137
7820
  ],
8138
- name: "addRefiner",
7821
+ name: "addRefinerWithSchemaId",
8139
7822
  outputs: [
8140
7823
  {
8141
7824
  internalType: "uint256",
@@ -8155,7 +7838,7 @@ var DataRefinerRegistryABI = [
8155
7838
  },
8156
7839
  {
8157
7840
  internalType: "string",
8158
- name: "typ",
7841
+ name: "dialect",
8159
7842
  type: "string"
8160
7843
  },
8161
7844
  {
@@ -8518,7 +8201,7 @@ var DataRefinerRegistryABI = [
8518
8201
  },
8519
8202
  {
8520
8203
  internalType: "string",
8521
- name: "typ",
8204
+ name: "dialect",
8522
8205
  type: "string"
8523
8206
  },
8524
8207
  {
@@ -33431,11 +33114,337 @@ function getAbi(contract) {
33431
33114
  return abi;
33432
33115
  }
33433
33116
 
33117
+ // src/utils/transactionParsing.ts
33118
+ async function parseTransactionResult(context, hash, operation) {
33119
+ const mapping = EVENT_MAPPINGS[operation];
33120
+ try {
33121
+ console.debug(`\u{1F50D} Parsing ${operation} transaction: ${hash}`);
33122
+ const receipt = await context.publicClient.waitForTransactionReceipt({
33123
+ hash,
33124
+ timeout: 3e4
33125
+ // 30 second timeout
33126
+ });
33127
+ console.debug(`\u2705 Transaction confirmed in block ${receipt.blockNumber}`);
33128
+ const abi = getAbi(mapping.contract);
33129
+ const events = parseEventLogs({
33130
+ logs: receipt.logs,
33131
+ abi,
33132
+ eventName: mapping.event,
33133
+ strict: true
33134
+ // Only return logs that conform to the ABI
33135
+ });
33136
+ if (events.length === 0) {
33137
+ throw new BlockchainError(
33138
+ `No ${mapping.event} event found in transaction ${hash}. Transaction may have failed or reverted.`
33139
+ );
33140
+ }
33141
+ if (events.length > 1) {
33142
+ console.warn(
33143
+ `\u26A0\uFE0F Multiple ${mapping.event} events found in transaction ${hash}. Using the first one.`
33144
+ );
33145
+ }
33146
+ const event = events[0];
33147
+ console.debug(`\u{1F389} Found ${mapping.event} event with args:`, event.args);
33148
+ return {
33149
+ ...event.args,
33150
+ transactionHash: hash,
33151
+ blockNumber: receipt.blockNumber,
33152
+ gasUsed: receipt.gasUsed
33153
+ };
33154
+ } catch (error) {
33155
+ if (error instanceof BlockchainError || error instanceof NetworkError) {
33156
+ throw error;
33157
+ }
33158
+ if (error instanceof Error && error.message.includes("timeout")) {
33159
+ throw new NetworkError(
33160
+ `Transaction ${hash} confirmation timeout after 30 seconds. The transaction may still be pending.`,
33161
+ error
33162
+ );
33163
+ }
33164
+ throw new BlockchainError(
33165
+ `Failed to parse ${operation} transaction ${hash}: ${error instanceof Error ? error.message : "Unknown error"}`,
33166
+ error
33167
+ );
33168
+ }
33169
+ }
33170
+
33171
+ // src/config/addresses.ts
33172
+ var CONTRACTS = {
33173
+ // Core Platform Contracts
33174
+ DataPermissions: {
33175
+ addresses: {
33176
+ 14800: "0x31fb1D48f6B2265A4cAD516BC39E96a18fb7c8de",
33177
+ 1480: "0x31fb1D48f6B2265A4cAD516BC39E96a18fb7c8de"
33178
+ }
33179
+ },
33180
+ DataRegistry: {
33181
+ addresses: {
33182
+ 14800: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C",
33183
+ 1480: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C"
33184
+ }
33185
+ },
33186
+ TeePoolPhala: {
33187
+ addresses: {
33188
+ 14800: "0xE8EC6BD73b23Ad40E6B9a6f4bD343FAc411bD99A",
33189
+ 1480: "0xE8EC6BD73b23Ad40E6B9a6f4bD343FAc411bD99A"
33190
+ }
33191
+ },
33192
+ ComputeEngine: {
33193
+ addresses: {
33194
+ 14800: "0xb2BFe33FA420c45F1Cf1287542ad81ae935447bd",
33195
+ 1480: "0xb2BFe33FA420c45F1Cf1287542ad81ae935447bd"
33196
+ }
33197
+ },
33198
+ // Data Access Infrastructure
33199
+ DataRefinerRegistry: {
33200
+ addresses: {
33201
+ 14800: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c",
33202
+ 1480: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c"
33203
+ }
33204
+ },
33205
+ QueryEngine: {
33206
+ addresses: {
33207
+ 14800: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490",
33208
+ 1480: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490"
33209
+ }
33210
+ },
33211
+ VanaTreasury: {
33212
+ addresses: {
33213
+ 14800: "0x94a1E56e555ac48d092f490fB10CDFaB434915eD",
33214
+ 1480: "0x94a1E56e555ac48d092f490fB10CDFaB434915eD"
33215
+ }
33216
+ },
33217
+ ComputeInstructionRegistry: {
33218
+ addresses: {
33219
+ 14800: "0x5786B12b4c6Ba2bFAF0e77Ed30Bf6d32805563A5",
33220
+ 1480: "0x5786B12b4c6Ba2bFAF0e77Ed30Bf6d32805563A5"
33221
+ }
33222
+ },
33223
+ // TEE Pool Variants
33224
+ TeePoolEphemeralStandard: {
33225
+ addresses: {
33226
+ 14800: "0xe124bae846D5ec157f75Bd9e68ca87C4d2AB835A",
33227
+ 1480: "0xe124bae846D5ec157f75Bd9e68ca87C4d2AB835A"
33228
+ }
33229
+ },
33230
+ TeePoolPersistentStandard: {
33231
+ addresses: {
33232
+ 14800: "0xe8bB8d0629651Cf33e0845d743976Dc1f0971d76",
33233
+ 1480: "0xe8bB8d0629651Cf33e0845d743976Dc1f0971d76"
33234
+ }
33235
+ },
33236
+ TeePoolPersistentGpu: {
33237
+ addresses: {
33238
+ 14800: "0x1c346Cd74f8551f8fa13f3F4b6b8dAE22338E6a9",
33239
+ 1480: "0x1c346Cd74f8551f8fa13f3F4b6b8dAE22338E6a9"
33240
+ }
33241
+ },
33242
+ TeePoolDedicatedStandard: {
33243
+ addresses: {
33244
+ 14800: "0xf024b7ac5E8417416f53B41ecfa58C8e9396687d",
33245
+ 1480: "0xf024b7ac5E8417416f53B41ecfa58C8e9396687d"
33246
+ }
33247
+ },
33248
+ TeePoolDedicatedGpu: {
33249
+ addresses: {
33250
+ 14800: "0xB1686FA9620bBf851714d1cB47b8a4Bf4664644E",
33251
+ 1480: "0xB1686FA9620bBf851714d1cB47b8a4Bf4664644E"
33252
+ }
33253
+ },
33254
+ // DLP Reward System
33255
+ VanaEpoch: {
33256
+ addresses: {
33257
+ 14800: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0",
33258
+ 1480: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0"
33259
+ }
33260
+ },
33261
+ DLPRegistry: {
33262
+ addresses: {
33263
+ 14800: "0x4D59880a924526d1dD33260552Ff4328b1E18a43",
33264
+ 1480: "0x4D59880a924526d1dD33260552Ff4328b1E18a43"
33265
+ }
33266
+ },
33267
+ DLPRegistryTreasury: {
33268
+ addresses: {
33269
+ 14800: "0xb12ce1d27bEeFe39b6F0110b1AB77C21Aa0c9F9a",
33270
+ 1480: "0xb12ce1d27bEeFe39b6F0110b1AB77C21Aa0c9F9a"
33271
+ }
33272
+ },
33273
+ DLPPerformance: {
33274
+ addresses: {
33275
+ 14800: "0x847715C7DB37cF286611182Be0bD333cbfa29cc1",
33276
+ 1480: "0x847715C7DB37cF286611182Be0bD333cbfa29cc1"
33277
+ }
33278
+ },
33279
+ DLPRewardDeployer: {
33280
+ addresses: {
33281
+ 14800: "0xEFD0F9Ba9De70586b7c4189971cF754adC923B04",
33282
+ 1480: "0xEFD0F9Ba9De70586b7c4189971cF754adC923B04"
33283
+ }
33284
+ },
33285
+ DLPRewardDeployerTreasury: {
33286
+ addresses: {
33287
+ 14800: "0xb547ca8Fe4990fe330FeAeb1C2EBb42F925Af5b8",
33288
+ 1480: "0xb547ca8Fe4990fe330FeAeb1C2EBb42F925Af5b8"
33289
+ }
33290
+ },
33291
+ DLPRewardSwap: {
33292
+ addresses: {
33293
+ 14800: "0x7c6862C46830F0fc3bF3FF509EA1bD0EE7267fB0",
33294
+ 1480: "0x7c6862C46830F0fc3bF3FF509EA1bD0EE7267fB0"
33295
+ }
33296
+ },
33297
+ SwapHelper: {
33298
+ addresses: {
33299
+ 14800: "0x55D5e6F73326315bF2E091e97F04f0770e5C54e2",
33300
+ 1480: "0x55D5e6F73326315bF2E091e97F04f0770e5C54e2"
33301
+ }
33302
+ },
33303
+ // VanaPool (Staking)
33304
+ VanaPoolStaking: {
33305
+ addresses: {
33306
+ 14800: "0x641C18E2F286c86f96CE95C8ec1EB9fC0415Ca0e",
33307
+ 1480: "0x641C18E2F286c86f96CE95C8ec1EB9fC0415Ca0e"
33308
+ }
33309
+ },
33310
+ VanaPoolEntity: {
33311
+ addresses: {
33312
+ 14800: "0x44f20490A82e1f1F1cC25Dd3BA8647034eDdce30",
33313
+ 1480: "0x44f20490A82e1f1F1cC25Dd3BA8647034eDdce30"
33314
+ }
33315
+ },
33316
+ VanaPoolTreasury: {
33317
+ addresses: {
33318
+ 14800: "0x143BE72CF2541604A7691933CAccd6D9cC17c003",
33319
+ 1480: "0x143BE72CF2541604A7691933CAccd6D9cC17c003"
33320
+ }
33321
+ },
33322
+ // DLP Deployment Contracts
33323
+ DAT: {
33324
+ addresses: {
33325
+ 14800: "0xA706b93ccED89f13340673889e29F0a5cd84212d",
33326
+ 1480: "0xA706b93ccED89f13340673889e29F0a5cd84212d"
33327
+ }
33328
+ },
33329
+ DATFactory: {
33330
+ addresses: {
33331
+ 14800: "0x40f8bccF35a75ecef63BC3B1B3E06ffEB9220644",
33332
+ 1480: "0x40f8bccF35a75ecef63BC3B1B3E06ffEB9220644"
33333
+ }
33334
+ },
33335
+ DATPausable: {
33336
+ addresses: {
33337
+ 14800: "0xe69FE86f0B95cC2f8416Fe22815c85DC8887e76e",
33338
+ 1480: "0xe69FE86f0B95cC2f8416Fe22815c85DC8887e76e"
33339
+ }
33340
+ },
33341
+ DATVotes: {
33342
+ addresses: {
33343
+ 14800: "0xaE04c8A77E9B27869eb563720524A9aE0baf1831",
33344
+ 1480: "0xaE04c8A77E9B27869eb563720524A9aE0baf1831"
33345
+ }
33346
+ },
33347
+ // Utility Contracts (no ABIs in SDK)
33348
+ Multicall3: {
33349
+ addresses: {
33350
+ 14800: "0xD8d2dFca27E8797fd779F8547166A2d3B29d360E",
33351
+ 1480: "0xD8d2dFca27E8797fd779F8547166A2d3B29d360E"
33352
+ }
33353
+ },
33354
+ Multisend: {
33355
+ addresses: {
33356
+ 14800: "0x8807e8BCDFbaA8c2761760f3FBA37F6f7F2C5b2d",
33357
+ 1480: "0x8807e8BCDFbaA8c2761760f3FBA37F6f7F2C5b2d"
33358
+ }
33359
+ }
33360
+ };
33361
+ var LEGACY_CONTRACTS = {
33362
+ // DEPRECATED: Original Intel SGX TeePool (PRO-347)
33363
+ TeePool: {
33364
+ addresses: {
33365
+ 14800: "0x3c92fD91639b41f13338CE62f19131e7d19eaa0D",
33366
+ 1480: "0x3c92fD91639b41f13338CE62f19131e7d19eaa0D"
33367
+ }
33368
+ },
33369
+ // DEPRECATED: DLPRoot system (replaced by VanaPool + DLPRewards)
33370
+ DLPRootEpoch: {
33371
+ addresses: {
33372
+ 14800: "0xc3d176cF6BccFCB9225b53B87a95147218e1537F",
33373
+ 1480: "0xc3d176cF6BccFCB9225b53B87a95147218e1537F"
33374
+ }
33375
+ },
33376
+ DLPRootCore: {
33377
+ addresses: {
33378
+ 14800: "0x0aBa5e28228c323A67712101d61a54d4ff5720FD",
33379
+ 1480: "0x0aBa5e28228c323A67712101d61a54d4ff5720FD"
33380
+ }
33381
+ },
33382
+ DLPRoot: {
33383
+ addresses: {
33384
+ 14800: "0xff14346dF2B8Fd0c95BF34f1c92e49417b508AD5",
33385
+ 1480: "0xff14346dF2B8Fd0c95BF34f1c92e49417b508AD5"
33386
+ }
33387
+ },
33388
+ DLPRootMetrics: {
33389
+ addresses: {
33390
+ 14800: "0xbb532917B6407c060Afd9Cb7d53527eCb91d6662",
33391
+ 1480: "0xbb532917B6407c060Afd9Cb7d53527eCb91d6662"
33392
+ }
33393
+ },
33394
+ DLPRootStakesTreasury: {
33395
+ addresses: {
33396
+ 14800: "0x52c3260ED5C235fcA43524CF508e29c897318775",
33397
+ 1480: "0x52c3260ED5C235fcA43524CF508e29c897318775"
33398
+ }
33399
+ },
33400
+ DLPRootRewardsTreasury: {
33401
+ addresses: {
33402
+ 14800: "0xDBFb6B8b9E2eCAEbdE64d665cD553dB81e524479",
33403
+ 1480: "0xDBFb6B8b9E2eCAEbdE64d665cD553dB81e524479"
33404
+ }
33405
+ }
33406
+ };
33407
+ var CONTRACT_ADDRESSES = {
33408
+ 14800: Object.fromEntries(
33409
+ Object.entries(CONTRACTS).map(([name, info]) => [name, info.addresses[14800]]).filter(([, addr]) => addr)
33410
+ ),
33411
+ 1480: Object.fromEntries(
33412
+ Object.entries(CONTRACTS).map(([name, info]) => [name, info.addresses[1480]]).filter(([, addr]) => addr)
33413
+ )
33414
+ };
33415
+ var UTILITY_ADDRESSES = {
33416
+ 14800: {
33417
+ Multicall3: CONTRACTS.Multicall3.addresses[14800],
33418
+ Multisend: CONTRACTS.Multisend.addresses[14800]
33419
+ },
33420
+ 1480: {
33421
+ Multicall3: CONTRACTS.Multicall3.addresses[1480],
33422
+ Multisend: CONTRACTS.Multisend.addresses[1480]
33423
+ }
33424
+ };
33425
+ var LEGACY_ADDRESSES = {
33426
+ 14800: Object.fromEntries(
33427
+ Object.entries(LEGACY_CONTRACTS).map(([name, info]) => [name, info.addresses[14800]]).filter(([, addr]) => addr)
33428
+ ),
33429
+ 1480: Object.fromEntries(
33430
+ Object.entries(LEGACY_CONTRACTS).map(([name, info]) => [name, info.addresses[1480]]).filter(([, addr]) => addr)
33431
+ )
33432
+ };
33433
+ var getContractAddress = (chainId, contract) => {
33434
+ const contractAddress = CONTRACT_ADDRESSES[chainId]?.[contract];
33435
+ if (!contractAddress) {
33436
+ throw new Error(
33437
+ `Contract address not found for ${contract} on chain ${chainId}`
33438
+ );
33439
+ }
33440
+ return contractAddress;
33441
+ };
33442
+
33434
33443
  // src/utils/grantFiles.ts
33435
33444
  import { keccak256, toHex } from "viem";
33436
33445
  function createGrantFile(params) {
33437
33446
  const grantFile = {
33438
- grantee: params.to,
33447
+ grantee: params.grantee,
33439
33448
  operation: params.operation,
33440
33449
  parameters: params.parameters
33441
33450
  };
@@ -33832,6 +33841,91 @@ function validateOperationAccess(grantFile, requestedOperation) {
33832
33841
  }
33833
33842
  }
33834
33843
 
33844
+ // src/utils/signatureCache.ts
33845
+ init_crypto_utils();
33846
+ var SignatureCache = class {
33847
+ /**
33848
+ * Get a cached signature if it exists and hasn't expired
33849
+ */
33850
+ static get(cache, walletAddress, messageHash) {
33851
+ const key = this.getCacheKey(walletAddress, messageHash);
33852
+ try {
33853
+ const stored = cache.get(key);
33854
+ if (!stored) return null;
33855
+ const cached = JSON.parse(stored);
33856
+ if (Date.now() > cached.expires) {
33857
+ cache.delete(key);
33858
+ return null;
33859
+ }
33860
+ return cached.signature;
33861
+ } catch {
33862
+ try {
33863
+ cache.delete(key);
33864
+ } catch {
33865
+ }
33866
+ return null;
33867
+ }
33868
+ }
33869
+ /**
33870
+ * Store a signature in the cache
33871
+ */
33872
+ static set(cache, walletAddress, messageHash, signature, ttlHours = this.DEFAULT_TTL_HOURS) {
33873
+ const key = this.getCacheKey(walletAddress, messageHash);
33874
+ const cached = {
33875
+ signature,
33876
+ expires: Date.now() + ttlHours * 36e5
33877
+ // Convert hours to milliseconds
33878
+ };
33879
+ try {
33880
+ cache.set(key, JSON.stringify(cached));
33881
+ } catch {
33882
+ }
33883
+ }
33884
+ /**
33885
+ * Clear all cached signatures (useful for testing or explicit cleanup)
33886
+ */
33887
+ static clear(cache) {
33888
+ try {
33889
+ cache.clear();
33890
+ } catch {
33891
+ }
33892
+ }
33893
+ static getCacheKey(walletAddress, messageHash) {
33894
+ return `${this.PREFIX}${walletAddress.toLowerCase()}:${messageHash}`;
33895
+ }
33896
+ static hashMessage(message) {
33897
+ const jsonString = JSON.stringify(message, this.bigIntReplacer);
33898
+ const base64Hash = toBase64(jsonString);
33899
+ const cleaned = base64Hash.replace(/[^a-zA-Z0-9]/g, "");
33900
+ if (cleaned.length > 32) {
33901
+ return cleaned.substring(0, 16) + cleaned.substring(cleaned.length - 16);
33902
+ }
33903
+ return cleaned.substring(0, 32);
33904
+ }
33905
+ /**
33906
+ * Custom JSON replacer that converts BigInt values to strings for serialization
33907
+ * This ensures deterministic cache key generation for EIP-712 typed data
33908
+ */
33909
+ static bigIntReplacer(key, value) {
33910
+ if (typeof value === "bigint") {
33911
+ return `__BIGINT__${value.toString()}`;
33912
+ }
33913
+ return value;
33914
+ }
33915
+ };
33916
+ __publicField(SignatureCache, "PREFIX", "vana_sig_");
33917
+ __publicField(SignatureCache, "DEFAULT_TTL_HOURS", 2);
33918
+ async function withSignatureCache(cache, walletAddress, typedData, signFn, ttlHours) {
33919
+ const messageHash = SignatureCache.hashMessage(typedData);
33920
+ const cached = SignatureCache.get(cache, walletAddress, messageHash);
33921
+ if (cached) {
33922
+ return cached;
33923
+ }
33924
+ const signature = await signFn();
33925
+ SignatureCache.set(cache, walletAddress, messageHash, signature, ttlHours);
33926
+ return signature;
33927
+ }
33928
+
33835
33929
  // src/controllers/permissions.ts
33836
33930
  var PermissionsController = class {
33837
33931
  constructor(context) {
@@ -33839,23 +33933,23 @@ var PermissionsController = class {
33839
33933
  }
33840
33934
  /**
33841
33935
  * Grants permission for an application to access user data with gasless transactions.
33936
+ *
33937
+ * This method provides a complete end-to-end permission grant flow that returns
33938
+ * the permission ID and other relevant data immediately after successful submission.
33939
+ * For advanced users who need more control over the transaction lifecycle, use
33940
+ * `submitPermissionGrant()` instead.
33842
33941
  *
33843
- * @remarks
33844
- * This method combines signature creation and gasless submission for a complete
33845
- * end-to-end permission grant flow. It creates the grant file, stores it on IPFS,
33846
- * generates an EIP-712 signature, and submits via relayer. The grant file contains
33847
- * detailed parameters while the blockchain stores only a reference to enable
33848
- * efficient permission queries.
33849
33942
  * @param params - The permission grant configuration object
33850
- * @returns A Promise that resolves to the transaction hash when successfully submitted
33943
+ * @returns Promise resolving to permission data from the PermissionAdded event
33851
33944
  * @throws {RelayerError} When gasless transaction submission fails
33852
33945
  * @throws {SignatureError} When user rejects the signature request
33853
33946
  * @throws {SerializationError} When grant data cannot be serialized
33854
- * @throws {BlockchainError} When permission grant preparation fails
33947
+ * @throws {BlockchainError} When permission grant fails or event parsing fails
33948
+ * @throws {NetworkError} When transaction confirmation times out
33855
33949
  * @example
33856
33950
  * ```typescript
33857
- * const txHash = await vana.permissions.grant({
33858
- * to: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
33951
+ * const result = await vana.permissions.grant({
33952
+ * grantee: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
33859
33953
  * operation: "llm_inference",
33860
33954
  * parameters: {
33861
33955
  * model: "gpt-4",
@@ -33864,10 +33958,42 @@ var PermissionsController = class {
33864
33958
  * },
33865
33959
  * });
33866
33960
  *
33867
- * console.log(`Permission granted: ${txHash}`);
33961
+ * console.log(`Permission ${result.permissionId} granted to ${result.user}`);
33962
+ * console.log(`Transaction: ${result.transactionHash}`);
33963
+ *
33964
+ * // Can immediately use the permission ID for other operations
33965
+ * await vana.permissions.revoke({ permissionId: result.permissionId });
33868
33966
  * ```
33869
33967
  */
33870
33968
  async grant(params) {
33969
+ const txHash = await this.submitPermissionGrant(params);
33970
+ return parseTransactionResult(this.context, txHash, "grant");
33971
+ }
33972
+ /**
33973
+ * Submits a permission grant transaction and returns the transaction hash immediately.
33974
+ *
33975
+ * This is the lower-level method that provides maximum control over transaction timing.
33976
+ * Use this when you want to handle transaction confirmation and event parsing separately,
33977
+ * or when submitting multiple transactions in batch.
33978
+ *
33979
+ * @param params - The permission grant configuration object
33980
+ * @returns Promise that resolves to the transaction hash when successfully submitted
33981
+ * @throws {RelayerError} When gasless transaction submission fails
33982
+ * @throws {SignatureError} When user rejects the signature request
33983
+ * @throws {SerializationError} When grant data cannot be serialized
33984
+ * @throws {BlockchainError} When permission grant preparation fails
33985
+ * @example
33986
+ * ```typescript
33987
+ * // Submit transaction and handle confirmation later
33988
+ * const txHash = await vana.permissions.submitPermissionGrant(params);
33989
+ * console.log(`Transaction submitted: ${txHash}`);
33990
+ *
33991
+ * // Later, when you need the permission data:
33992
+ * const result = await parseTransactionResult(context, txHash, 'grant');
33993
+ * console.log(`Permission ID: ${result.permissionId}`);
33994
+ * ```
33995
+ */
33996
+ async submitPermissionGrant(params) {
33871
33997
  const { typedData, signature } = await this.createAndSign(params);
33872
33998
  return await this.submitSignedGrant(typedData, signature);
33873
33999
  }
@@ -33884,7 +34010,7 @@ var PermissionsController = class {
33884
34010
  * @example
33885
34011
  * ```typescript
33886
34012
  * const { preview, confirm } = await vana.permissions.prepareGrant({
33887
- * to: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
34013
+ * grantee: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
33888
34014
  * operation: "llm_inference",
33889
34015
  * files: [1, 2, 3],
33890
34016
  * parameters: { model: "gpt-4", prompt: "Analyze my social media data" }
@@ -33933,9 +34059,13 @@ var PermissionsController = class {
33933
34059
  console.debug("\u{1F50D} Debug - Grant URL from params:", grantUrl);
33934
34060
  if (!grantUrl) {
33935
34061
  if (!this.context.relayerCallbacks?.storeGrantFile && !this.context.storageManager) {
33936
- throw new Error(
33937
- "No storage available. Provide a grantUrl, configure relayerCallbacks.storeGrantFile, or storageManager."
33938
- );
34062
+ if (this.context.validateStorageRequired) {
34063
+ this.context.validateStorageRequired();
34064
+ } else {
34065
+ throw new Error(
34066
+ "No storage available. Provide a grantUrl, configure relayerCallbacks.storeGrantFile, or storageManager."
34067
+ );
34068
+ }
33939
34069
  }
33940
34070
  if (this.context.relayerCallbacks?.storeGrantFile) {
33941
34071
  grantUrl = await this.context.relayerCallbacks.storeGrantFile(grantFile);
@@ -33959,7 +34089,7 @@ var PermissionsController = class {
33959
34089
  grantUrl
33960
34090
  );
33961
34091
  const typedData = await this.composePermissionGrantMessage({
33962
- to: params.to,
34092
+ grantee: params.grantee,
33963
34093
  operation: params.operation,
33964
34094
  // Placeholder - real data is in IPFS
33965
34095
  files: params.files,
@@ -34006,7 +34136,7 @@ var PermissionsController = class {
34006
34136
  * @example
34007
34137
  * ```typescript
34008
34138
  * const { typedData, signature } = await vana.permissions.createAndSign({
34009
- * to: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
34139
+ * grantee: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
34010
34140
  * operation: "data_analysis",
34011
34141
  * parameters: { analysisType: "sentiment" },
34012
34142
  * });
@@ -34022,9 +34152,13 @@ var PermissionsController = class {
34022
34152
  console.debug("\u{1F50D} Debug - Grant URL from params:", grantUrl);
34023
34153
  if (!grantUrl) {
34024
34154
  if (!this.context.relayerCallbacks?.storeGrantFile && !this.context.storageManager) {
34025
- throw new Error(
34026
- "No storage available. Provide a grantUrl, configure relayerCallbacks.storeGrantFile, or storageManager."
34027
- );
34155
+ if (this.context.validateStorageRequired) {
34156
+ this.context.validateStorageRequired();
34157
+ } else {
34158
+ throw new Error(
34159
+ "No storage available. Provide a grantUrl, configure relayerCallbacks.storeGrantFile, or storageManager."
34160
+ );
34161
+ }
34028
34162
  }
34029
34163
  if (this.context.relayerCallbacks?.storeGrantFile) {
34030
34164
  grantUrl = await this.context.relayerCallbacks.storeGrantFile(grantFile);
@@ -34048,7 +34182,7 @@ var PermissionsController = class {
34048
34182
  grantUrl
34049
34183
  );
34050
34184
  const typedData = await this.composePermissionGrantMessage({
34051
- to: params.to,
34185
+ grantee: params.grantee,
34052
34186
  operation: params.operation,
34053
34187
  // Placeholder - real data is in IPFS
34054
34188
  files: params.files,
@@ -34276,23 +34410,52 @@ var PermissionsController = class {
34276
34410
  }
34277
34411
  /**
34278
34412
  * Revokes a previously granted permission.
34413
+ *
34414
+ * This method provides complete revocation with automatic event parsing to confirm
34415
+ * the permission was successfully revoked. For advanced users who need more control,
34416
+ * use `submitPermissionRevoke()` instead.
34279
34417
  *
34280
34418
  * @param params - Parameters for revoking the permission
34281
- * @returns Promise resolving to transaction hash
34419
+ * @param params.permissionId - Permission identifier as bigint for contract compatibility.
34420
+ * Obtain from permission grants via `getUserPermissionGrantsOnChain()`.
34421
+ * @returns Promise resolving to revocation data from PermissionRevoked event
34422
+ * @throws {BlockchainError} When revocation fails or event parsing fails
34423
+ * @throws {UserRejectedRequestError} When user rejects the transaction
34424
+ * @throws {NetworkError} When transaction confirmation times out
34282
34425
  * @example
34283
34426
  * ```typescript
34284
- * // Revoke a permission by its ID
34285
- * const txHash = await vana.permissions.revoke({
34427
+ * // Revoke a permission and get confirmation
34428
+ * const result = await vana.permissions.revoke({
34286
34429
  * permissionId: 123n
34287
34430
  * });
34288
- * console.log('Permission revoked in transaction:', txHash);
34289
- *
34290
- * // Wait for confirmation if needed
34291
- * const receipt = await vana.core.waitForTransaction(txHash);
34292
- * console.log('Revocation confirmed in block:', receipt.blockNumber);
34431
+ * console.log(`Permission ${result.permissionId} revoked in transaction ${result.transactionHash}`);
34432
+ * console.log(`Revoked in block ${result.blockNumber}`);
34293
34433
  * ```
34294
34434
  */
34295
34435
  async revoke(params) {
34436
+ const txHash = await this.submitPermissionRevoke(params);
34437
+ return parseTransactionResult(this.context, txHash, "revoke");
34438
+ }
34439
+ /**
34440
+ * Submits a permission revocation transaction and returns the transaction hash immediately.
34441
+ *
34442
+ * This is the lower-level method that provides maximum control over transaction timing.
34443
+ * Use this when you want to handle transaction confirmation and event parsing separately.
34444
+ *
34445
+ * @param params - Parameters for revoking the permission
34446
+ * @returns Promise resolving to the transaction hash when successfully submitted
34447
+ * @throws {BlockchainError} When revocation transaction fails
34448
+ * @throws {UserRejectedRequestError} When user rejects the transaction
34449
+ * @example
34450
+ * ```typescript
34451
+ * // Submit revocation and handle confirmation later
34452
+ * const txHash = await vana.permissions.submitPermissionRevoke({
34453
+ * permissionId: 123n
34454
+ * });
34455
+ * console.log(`Revocation submitted: ${txHash}`);
34456
+ * ```
34457
+ */
34458
+ async submitPermissionRevoke(params) {
34296
34459
  try {
34297
34460
  if (!this.context.walletClient.chain?.id) {
34298
34461
  throw new BlockchainError("Chain ID not available");
@@ -34399,7 +34562,7 @@ var PermissionsController = class {
34399
34562
  * Composes the EIP-712 typed data for PermissionGrant (new simplified format).
34400
34563
  *
34401
34564
  * @param params - The parameters for composing the permission grant message
34402
- * @param params.to - The recipient address for the permission grant
34565
+ * @param params.grantee - The recipient address for the permission grant
34403
34566
  * @param params.operation - The type of operation being granted permission for
34404
34567
  * @param params.files - Array of file IDs that the permission applies to
34405
34568
  * @param params.grantUrl - URL where the grant details are stored
@@ -34458,17 +34621,24 @@ var PermissionsController = class {
34458
34621
  };
34459
34622
  }
34460
34623
  /**
34461
- * Signs typed data using the wallet client.
34624
+ * Signs typed data using the wallet client with signature caching.
34462
34625
  *
34463
34626
  * @param typedData - The EIP-712 typed data structure to sign
34464
34627
  * @returns Promise resolving to the cryptographic signature
34465
34628
  */
34466
34629
  async signTypedData(typedData) {
34467
34630
  try {
34468
- const signature = await this.context.walletClient.signTypedData(
34469
- typedData
34631
+ const walletAddress = this.context.walletClient.account?.address || await this.getUserAddress();
34632
+ return await withSignatureCache(
34633
+ this.context.platform.cache,
34634
+ walletAddress,
34635
+ typedData,
34636
+ async () => {
34637
+ return await this.context.walletClient.signTypedData(
34638
+ typedData
34639
+ );
34640
+ }
34470
34641
  );
34471
- return signature;
34472
34642
  } catch (error) {
34473
34643
  if (error instanceof Error && error.message.includes("rejected")) {
34474
34644
  throw new UserRejectedRequestError();
@@ -34492,36 +34662,45 @@ var PermissionsController = class {
34492
34662
  return addresses[0];
34493
34663
  }
34494
34664
  /**
34495
- * Retrieves all permissions granted by the current user using subgraph queries.
34665
+ * Gets on-chain permission grant data without expensive off-chain resolution.
34496
34666
  *
34497
34667
  * @remarks
34498
- * This method queries the Vana subgraph to find permissions directly granted by the user
34499
- * using the Permission entity. It efficiently handles millions of permissions by leveraging
34500
- * indexed subgraph data instead of scanning contract logs. The method fetches complete
34501
- * grant files from IPFS to provide detailed permission information including operation
34502
- * parameters and grantee details.
34503
- * @param params - Optional query parameters
34504
- * @param params.limit - Maximum number of permissions to return (default: 50)
34505
- * @param params.subgraphUrl - Optional subgraph URL to override the default endpoint
34506
- * @returns A Promise that resolves to an array of `GrantedPermission` objects
34507
- * @throws {BlockchainError} When subgraph is unavailable or returns invalid data
34668
+ * This method provides a fast, performance-focused way to retrieve permission grants
34669
+ * by querying only the subgraph without making expensive IPFS or individual contract calls.
34670
+ * It eliminates the N+1 query problem of the legacy `getUserPermissions()` method.
34671
+ *
34672
+ * The returned data contains all on-chain information but does NOT include resolved
34673
+ * operation details, parameters, or file IDs. Use `retrieveGrantFile()` separately
34674
+ * for specific grants when detailed data is needed.
34675
+ *
34676
+ * **Performance**: Completes in ~100-500ms regardless of permission count.
34677
+ * **Reliability**: Single point of failure (subgraph) with clear RPC fallback path.
34678
+ *
34679
+ * @param options - Options for retrieving permissions (limit, subgraph URL)
34680
+ * @returns A Promise that resolves to an array of `OnChainPermissionGrant` objects
34681
+ * @throws {BlockchainError} When subgraph query fails
34682
+ * @throws {NetworkError} When network requests fail
34508
34683
  * @example
34509
34684
  * ```typescript
34510
- * // Get all permissions granted by current user
34511
- * const permissions = await vana.permissions.getUserPermissions();
34685
+ * // Fast: Get all on-chain permission data
34686
+ * const grants = await vana.permissions.getUserPermissionGrantsOnChain({ limit: 20 });
34512
34687
  *
34513
- * permissions.forEach(permission => {
34514
- * console.log(`Granted ${permission.operation} to ${permission.grantee}`);
34688
+ * // Display in UI immediately
34689
+ * grants.forEach(grant => {
34690
+ * console.log(`Permission ${grant.id}: ${grant.grantUrl}`);
34515
34691
  * });
34516
34692
  *
34517
- * // Limit results
34518
- * const recent = await vana.permissions.getUserPermissions({ limit: 10 });
34693
+ * // Lazy load detailed data for specific permission when user clicks
34694
+ * const grantFile = await retrieveGrantFile(grants[0].grantUrl);
34695
+ * console.log(`Operation: ${grantFile.operation}`);
34696
+ * console.log(`Parameters:`, grantFile.parameters);
34519
34697
  * ```
34520
34698
  */
34521
- async getUserPermissions(params) {
34699
+ async getUserPermissionGrantsOnChain(options = {}) {
34700
+ const { limit = 50, subgraphUrl } = options;
34522
34701
  try {
34523
34702
  const userAddress = await this.getUserAddress();
34524
- const graphqlEndpoint = params?.subgraphUrl || this.context.subgraphUrl;
34703
+ const graphqlEndpoint = subgraphUrl || this.context.subgraphUrl;
34525
34704
  if (!graphqlEndpoint) {
34526
34705
  throw new BlockchainError(
34527
34706
  "subgraphUrl is required. Please provide a valid subgraph endpoint or configure it in Vana constructor."
@@ -34543,16 +34722,6 @@ var PermissionsController = class {
34543
34722
  }
34544
34723
  }
34545
34724
  `;
34546
- console.info("Query:", query);
34547
- console.info(
34548
- "Body:",
34549
- JSON.stringify({
34550
- query,
34551
- variables: {
34552
- userId: userAddress.toLowerCase()
34553
- }
34554
- })
34555
- );
34556
34725
  const response = await fetch(graphqlEndpoint, {
34557
34726
  method: "POST",
34558
34727
  headers: {
@@ -34571,7 +34740,6 @@ var PermissionsController = class {
34571
34740
  );
34572
34741
  }
34573
34742
  const result = await response.json();
34574
- console.info("Result:", result);
34575
34743
  if (result.errors) {
34576
34744
  throw new BlockchainError(
34577
34745
  `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
@@ -34579,64 +34747,32 @@ var PermissionsController = class {
34579
34747
  }
34580
34748
  const userData = result.data?.user;
34581
34749
  if (!userData || !userData.permissions?.length) {
34582
- console.warn("No permissions found for user:", userAddress);
34583
34750
  return [];
34584
34751
  }
34585
- const userPermissions = [];
34586
- const limit = params?.limit || 50;
34587
- const permissionsToProcess = userData.permissions.slice(0, limit);
34588
- for (const permission of permissionsToProcess) {
34589
- try {
34590
- let operation;
34591
- let files = [];
34592
- let parameters;
34593
- let granteeAddress;
34594
- try {
34595
- const grantFile = await retrieveGrantFile(permission.grant);
34596
- operation = grantFile.operation;
34597
- parameters = grantFile.parameters;
34598
- granteeAddress = grantFile.grantee;
34599
- } catch {
34600
- }
34601
- try {
34602
- const fileIds = await this.getPermissionFileIds(
34603
- BigInt(permission.id)
34604
- );
34605
- files = fileIds.map((id) => Number(id));
34606
- } catch {
34607
- }
34608
- userPermissions.push({
34609
- id: BigInt(permission.id),
34610
- files,
34611
- operation: operation || "",
34612
- parameters: parameters || {},
34613
- grant: permission.grant,
34614
- grantor: userAddress.toLowerCase(),
34615
- // Current user is the grantor
34616
- grantee: granteeAddress || userAddress,
34617
- // Application that received permission
34618
- active: true,
34619
- // Default to active if not specified
34620
- grantedAt: Number(permission.addedAtBlock),
34621
- nonce: Number(permission.nonce)
34622
- });
34623
- } catch (error) {
34624
- console.error(
34625
- "SDK Error: Failed to process permission:",
34626
- permission.id,
34627
- error
34628
- );
34629
- }
34630
- }
34631
- return userPermissions.sort((a, b) => {
34752
+ const onChainGrants = userData.permissions.slice(0, limit).map((permission) => ({
34753
+ id: BigInt(permission.id),
34754
+ grantUrl: permission.grant,
34755
+ grantSignature: permission.grantSignature,
34756
+ grantHash: permission.grantHash,
34757
+ nonce: BigInt(permission.nonce),
34758
+ addedAtBlock: BigInt(permission.addedAtBlock),
34759
+ addedAtTimestamp: BigInt(permission.addedAtTimestamp || "0"),
34760
+ transactionHash: permission.transactionHash || "",
34761
+ grantor: userAddress,
34762
+ active: true
34763
+ // TODO: Add revocation status from subgraph when available
34764
+ }));
34765
+ return onChainGrants.sort((a, b) => {
34632
34766
  if (a.id < b.id) return 1;
34633
34767
  if (a.id > b.id) return -1;
34634
34768
  return 0;
34635
34769
  });
34636
34770
  } catch (error) {
34637
- console.error("Failed to fetch user permissions:", error);
34771
+ if (error instanceof BlockchainError || error instanceof NetworkError) {
34772
+ throw error;
34773
+ }
34638
34774
  throw new BlockchainError(
34639
- `Failed to fetch user permissions: ${error instanceof Error ? error.message : "Unknown error"}`
34775
+ `Failed to fetch user permission grants: ${error instanceof Error ? error.message : "Unknown error"}`
34640
34776
  );
34641
34777
  }
34642
34778
  }
@@ -35336,15 +35472,22 @@ import { getContract, decodeEventLog } from "viem";
35336
35472
 
35337
35473
  // src/utils/encryption.ts
35338
35474
  var DEFAULT_ENCRYPTION_SEED = "Please sign to retrieve your encryption key";
35339
- async function generateEncryptionKey(wallet, seed = DEFAULT_ENCRYPTION_SEED) {
35475
+ async function generateEncryptionKey(wallet, platformAdapter, seed = DEFAULT_ENCRYPTION_SEED) {
35340
35476
  if (!wallet.account) {
35341
35477
  throw new Error("Wallet account is required for encryption key generation");
35342
35478
  }
35343
- const signature = await wallet.signMessage({
35344
- account: wallet.account,
35345
- message: seed
35346
- });
35347
- return signature;
35479
+ const messageData = { message: seed };
35480
+ return await withSignatureCache(
35481
+ platformAdapter.cache,
35482
+ wallet.account.address,
35483
+ messageData,
35484
+ async () => {
35485
+ return await wallet.signMessage({
35486
+ account: wallet.account,
35487
+ message: seed
35488
+ });
35489
+ }
35490
+ );
35348
35491
  }
35349
35492
  async function encryptWithWalletPublicKey(data, publicKey, platformAdapter) {
35350
35493
  try {
@@ -35398,32 +35541,19 @@ async function decryptWithPrivateKey(encryptedData, privateKey, platformAdapter)
35398
35541
  throw new Error(`Failed to decrypt with private key: ${error}`);
35399
35542
  }
35400
35543
  }
35401
- async function encryptUserData(data, walletSignature, platformAdapter) {
35544
+ async function encryptBlobWithSignedKey(data, key, platformAdapter) {
35402
35545
  try {
35403
35546
  const dataBuffer = data instanceof Blob ? await data.arrayBuffer() : new TextEncoder().encode(data);
35404
35547
  const dataArray = new Uint8Array(dataBuffer);
35405
35548
  const encrypted = await platformAdapter.crypto.encryptWithPassword(
35406
35549
  dataArray,
35407
- walletSignature
35550
+ key
35408
35551
  );
35409
35552
  return new Blob([encrypted], {
35410
35553
  type: "application/octet-stream"
35411
35554
  });
35412
35555
  } catch (error) {
35413
- throw new Error(`Failed to encrypt user data: ${error}`);
35414
- }
35415
- }
35416
- async function decryptUserData(encryptedData, walletSignature, platformAdapter) {
35417
- try {
35418
- const encryptedBuffer = encryptedData instanceof Blob ? await encryptedData.arrayBuffer() : new TextEncoder().encode(encryptedData);
35419
- const encryptedArray = new Uint8Array(encryptedBuffer);
35420
- const decrypted = await platformAdapter.crypto.decryptWithPassword(
35421
- encryptedArray,
35422
- walletSignature
35423
- );
35424
- return new Blob([decrypted], { type: "text/plain" });
35425
- } catch (error) {
35426
- throw new Error(`Failed to decrypt user data: ${error}`);
35556
+ throw new Error(`Failed to encrypt data: ${error}`);
35427
35557
  }
35428
35558
  }
35429
35559
  async function generateEncryptionKeyPair(platformAdapter) {
@@ -35440,12 +35570,315 @@ async function generatePGPKeyPair(platformAdapter, options) {
35440
35570
  throw new Error(`Failed to generate PGP key pair: ${error}`);
35441
35571
  }
35442
35572
  }
35573
+ async function decryptBlobWithSignedKey(encryptedData, key, platformAdapter) {
35574
+ try {
35575
+ const encryptedBuffer = encryptedData instanceof Blob ? await encryptedData.arrayBuffer() : new TextEncoder().encode(encryptedData);
35576
+ const encryptedArray = new Uint8Array(encryptedBuffer);
35577
+ const decrypted = await platformAdapter.crypto.decryptWithPassword(
35578
+ encryptedArray,
35579
+ key
35580
+ );
35581
+ return new Blob([decrypted], { type: "text/plain" });
35582
+ } catch (error) {
35583
+ throw new Error(`Failed to decrypt data: ${error}`);
35584
+ }
35585
+ }
35443
35586
 
35444
35587
  // src/controllers/data.ts
35445
35588
  var DataController = class {
35446
35589
  constructor(context) {
35447
35590
  this.context = context;
35448
35591
  }
35592
+ async upload(params) {
35593
+ const {
35594
+ content,
35595
+ filename,
35596
+ schemaId,
35597
+ permissions = [],
35598
+ encrypt: encrypt2 = true,
35599
+ providerName,
35600
+ owner
35601
+ } = params;
35602
+ try {
35603
+ let blob;
35604
+ if (content instanceof Blob) {
35605
+ blob = content;
35606
+ } else if (typeof content === "string") {
35607
+ blob = new Blob([content], { type: "text/plain" });
35608
+ } else if (content instanceof Buffer) {
35609
+ blob = new Blob([content], { type: "application/octet-stream" });
35610
+ } else {
35611
+ blob = new Blob([JSON.stringify(content)], {
35612
+ type: "application/json"
35613
+ });
35614
+ }
35615
+ let isValid = true;
35616
+ let validationErrors = [];
35617
+ if (schemaId !== void 0) {
35618
+ try {
35619
+ const schema = await this.getSchema(schemaId);
35620
+ const response = await fetch(schema.definitionUrl);
35621
+ if (!response.ok) {
35622
+ throw new Error(
35623
+ `Failed to fetch schema definition: ${response.status}`
35624
+ );
35625
+ }
35626
+ const schemaDefinition = await response.json();
35627
+ const dataSchema = {
35628
+ name: schema.name,
35629
+ version: "1.0.0",
35630
+ dialect: "json",
35631
+ schema: schemaDefinition
35632
+ };
35633
+ let parsedContent;
35634
+ if (typeof content === "string") {
35635
+ try {
35636
+ parsedContent = JSON.parse(content);
35637
+ } catch {
35638
+ parsedContent = content;
35639
+ }
35640
+ } else {
35641
+ parsedContent = content;
35642
+ }
35643
+ validateDataAgainstSchema(parsedContent, dataSchema);
35644
+ } catch (error) {
35645
+ isValid = false;
35646
+ validationErrors = [
35647
+ error instanceof Error ? error.message : "Schema validation failed"
35648
+ ];
35649
+ }
35650
+ }
35651
+ let finalBlob = blob;
35652
+ if (encrypt2) {
35653
+ const encryptionKey = await generateEncryptionKey(
35654
+ this.context.walletClient,
35655
+ this.context.platform,
35656
+ DEFAULT_ENCRYPTION_SEED
35657
+ );
35658
+ finalBlob = await encryptBlobWithSignedKey(
35659
+ blob,
35660
+ encryptionKey,
35661
+ this.context.platform
35662
+ );
35663
+ }
35664
+ if (!this.context.storageManager) {
35665
+ if (this.context.validateStorageRequired) {
35666
+ this.context.validateStorageRequired();
35667
+ throw new Error("Storage validation failed");
35668
+ } else {
35669
+ throw new Error(
35670
+ "Storage manager not configured. Please provide storage providers in VanaConfig."
35671
+ );
35672
+ }
35673
+ }
35674
+ const uploadResult = await this.context.storageManager.upload(
35675
+ finalBlob,
35676
+ filename,
35677
+ providerName
35678
+ );
35679
+ const userAddress = owner || await this.getUserAddress();
35680
+ let encryptedPermissions = [];
35681
+ if (permissions.length > 0) {
35682
+ const userEncryptionKey = await generateEncryptionKey(
35683
+ this.context.walletClient,
35684
+ this.context.platform,
35685
+ DEFAULT_ENCRYPTION_SEED
35686
+ );
35687
+ encryptedPermissions = await Promise.all(
35688
+ permissions.map(async (permission) => {
35689
+ const encryptedKey = await encryptWithWalletPublicKey(
35690
+ userEncryptionKey,
35691
+ permission.publicKey,
35692
+ this.context.platform
35693
+ );
35694
+ return {
35695
+ account: permission.account,
35696
+ key: encryptedKey
35697
+ };
35698
+ })
35699
+ );
35700
+ }
35701
+ let result;
35702
+ if (this.context.relayerCallbacks?.submitFileAdditionComplete) {
35703
+ result = await this.context.relayerCallbacks.submitFileAdditionComplete(
35704
+ {
35705
+ url: uploadResult.url,
35706
+ userAddress,
35707
+ permissions: encryptedPermissions,
35708
+ schemaId: schemaId || 0,
35709
+ ownerAddress: owner
35710
+ }
35711
+ );
35712
+ } else if (this.context.relayerCallbacks?.submitFileAddition) {
35713
+ const needsComplexRegistration = schemaId !== void 0 || encryptedPermissions.length > 0;
35714
+ if (needsComplexRegistration) {
35715
+ throw new Error(
35716
+ "The configured relay callback does not support schemas or permissions. Please update your relay server implementation to provide the `submitFileAdditionComplete` callback."
35717
+ );
35718
+ }
35719
+ result = await this.context.relayerCallbacks.submitFileAddition(
35720
+ uploadResult.url,
35721
+ userAddress
35722
+ );
35723
+ } else {
35724
+ result = await this.addFileWithPermissionsAndSchema(
35725
+ uploadResult.url,
35726
+ userAddress,
35727
+ encryptedPermissions,
35728
+ schemaId || 0
35729
+ );
35730
+ }
35731
+ return {
35732
+ fileId: result.fileId,
35733
+ url: uploadResult.url,
35734
+ transactionHash: result.transactionHash,
35735
+ size: uploadResult.size,
35736
+ isValid,
35737
+ validationErrors: validationErrors.length > 0 ? validationErrors : void 0
35738
+ };
35739
+ } catch (error) {
35740
+ throw new Error(
35741
+ `Upload failed: ${error instanceof Error ? error.message : "Unknown error"}`
35742
+ );
35743
+ }
35744
+ }
35745
+ /**
35746
+ * Decrypts a file owned by the user using their wallet signature.
35747
+ *
35748
+ * @remarks
35749
+ * This is the high-level convenience method for decrypting user files, serving as the
35750
+ * symmetrical counterpart to the `upload` method. It handles the complete decryption
35751
+ * workflow including key generation, URL protocol detection, content fetching, and
35752
+ * decryption.
35753
+ *
35754
+ * The method automatically:
35755
+ * - Generates the decryption key from the user's wallet signature
35756
+ * - Determines the appropriate fetch method based on the file URL protocol
35757
+ * - Fetches the encrypted content from IPFS or standard HTTP URLs
35758
+ * - Decrypts the content using the generated key
35759
+ *
35760
+ * For IPFS URLs, the method uses gateway fallback for improved reliability. For
35761
+ * standard HTTP URLs, it uses a simple fetch. If you need custom authentication
35762
+ * headers or specific gateway configurations, use the low-level primitives directly.
35763
+ *
35764
+ * @param file - The user file to decrypt (typically from getUserFiles)
35765
+ * @param encryptionSeed - Optional custom encryption seed (defaults to Vana standard)
35766
+ * @returns Promise resolving to the decrypted file content as a Blob
35767
+ * @throws {Error} When the wallet is not connected
35768
+ * @throws {Error} When fetching the encrypted content fails
35769
+ * @throws {Error} When decryption fails (wrong key or corrupted data)
35770
+ * @example
35771
+ * ```typescript
35772
+ * // Basic file decryption
35773
+ * const files = await vana.data.getUserFiles({ owner: userAddress });
35774
+ * const decryptedBlob = await vana.data.decryptFile(files[0]);
35775
+ *
35776
+ * // Convert to text
35777
+ * const text = await decryptedBlob.text();
35778
+ * console.log('Decrypted content:', text);
35779
+ *
35780
+ * // Convert to JSON
35781
+ * const json = JSON.parse(await decryptedBlob.text());
35782
+ * console.log('Decrypted data:', json);
35783
+ *
35784
+ * // With custom encryption seed
35785
+ * const decryptedBlob = await vana.data.decryptFile(
35786
+ * files[0],
35787
+ * "My custom encryption seed"
35788
+ * );
35789
+ *
35790
+ * // Save to file (in Node.js)
35791
+ * const buffer = await decryptedBlob.arrayBuffer();
35792
+ * fs.writeFileSync('decrypted-file.txt', Buffer.from(buffer));
35793
+ * ```
35794
+ */
35795
+ async decryptFile(file, encryptionSeed) {
35796
+ try {
35797
+ const encryptionKey = await generateEncryptionKey(
35798
+ this.context.walletClient,
35799
+ this.context.platform,
35800
+ encryptionSeed || DEFAULT_ENCRYPTION_SEED
35801
+ );
35802
+ let encryptedBlob;
35803
+ try {
35804
+ if (file.url.startsWith("ipfs://")) {
35805
+ encryptedBlob = await this.fetchFromIPFS(file.url);
35806
+ } else {
35807
+ encryptedBlob = await this.fetch(file.url);
35808
+ }
35809
+ } catch (fetchError) {
35810
+ const errorMessage = fetchError instanceof Error ? fetchError.message : "Unknown error";
35811
+ if (errorMessage.includes("Failed to fetch IPFS content") && errorMessage.includes("from all gateways")) {
35812
+ throw new Error(
35813
+ "Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
35814
+ );
35815
+ } else if (errorMessage.includes("Empty response")) {
35816
+ throw new Error("File is empty or could not be retrieved");
35817
+ } else if (errorMessage.includes("Network error:") || errorMessage.includes("Failed to fetch")) {
35818
+ throw new Error(
35819
+ "Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
35820
+ );
35821
+ } else if (errorMessage.includes("HTTP error!")) {
35822
+ const statusMatch = errorMessage.match(/status: (\d+)/);
35823
+ const status = statusMatch ? statusMatch[1] : "unknown";
35824
+ if (status === "500") {
35825
+ throw new Error(
35826
+ "Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
35827
+ );
35828
+ } else if (status === "403") {
35829
+ throw new Error(
35830
+ "Access denied. You may not have permission to access this file"
35831
+ );
35832
+ } else if (status === "404") {
35833
+ throw new Error(
35834
+ "File not found: The encrypted file is no longer available at the stored URL."
35835
+ );
35836
+ } else {
35837
+ throw new Error(
35838
+ "Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
35839
+ );
35840
+ }
35841
+ }
35842
+ throw fetchError;
35843
+ }
35844
+ if (encryptedBlob.size === 0) {
35845
+ throw new Error("File is empty or could not be retrieved");
35846
+ }
35847
+ let decryptedBlob;
35848
+ try {
35849
+ decryptedBlob = await decryptBlobWithSignedKey(
35850
+ encryptedBlob,
35851
+ encryptionKey,
35852
+ this.context.platform
35853
+ );
35854
+ } catch (decryptError) {
35855
+ const errorMessage = decryptError instanceof Error ? decryptError.message : "Unknown error";
35856
+ if (errorMessage.includes("not a valid OpenPGP message")) {
35857
+ throw new Error(
35858
+ "Invalid file format: This file doesn't appear to be encrypted with the Vana protocol"
35859
+ );
35860
+ } else if (errorMessage.includes("Session key decryption failed")) {
35861
+ throw new Error("Wrong encryption key");
35862
+ } else if (errorMessage.includes("Error decrypting message")) {
35863
+ throw new Error("Wrong encryption key");
35864
+ } else if (errorMessage.includes("File not found")) {
35865
+ throw new Error(
35866
+ "File not found: The encrypted file is no longer available"
35867
+ );
35868
+ } else {
35869
+ throw decryptError;
35870
+ }
35871
+ }
35872
+ return decryptedBlob;
35873
+ } catch (error) {
35874
+ if (error instanceof Error && (error.message.includes("Network error:") || error.message.includes("Invalid file format:") || error.message.includes("Wrong encryption key") || error.message.includes("Access denied") || error.message.includes("File not found:") || error.message.includes("File is empty"))) {
35875
+ throw error;
35876
+ }
35877
+ throw new Error(
35878
+ `Failed to decrypt file: ${error instanceof Error ? error.message : "Unknown error"}`
35879
+ );
35880
+ }
35881
+ }
35449
35882
  /**
35450
35883
  * Retrieves all data files owned by a specific user address.
35451
35884
  *
@@ -36029,6 +36462,7 @@ var DataController = class {
36029
36462
  /**
36030
36463
  * Uploads an encrypted file to storage and registers it on the blockchain.
36031
36464
  *
36465
+ * @deprecated Use vana.data.upload() instead for the high-level API with automatic encryption
36032
36466
  * @param encryptedFile - The encrypted file blob to upload
36033
36467
  * @param filename - Optional filename for the upload
36034
36468
  * @param providerName - Optional storage provider to use
@@ -36116,6 +36550,7 @@ var DataController = class {
36116
36550
  /**
36117
36551
  * Uploads an encrypted file to storage and registers it on the blockchain with a schema.
36118
36552
  *
36553
+ * @deprecated Use vana.data.upload() instead for the high-level API with automatic encryption and schema validation
36119
36554
  * @param encryptedFile - The encrypted file blob to upload
36120
36555
  * @param schemaId - The schema ID to associate with the file
36121
36556
  * @param filename - Optional filename for the upload
@@ -36194,81 +36629,6 @@ var DataController = class {
36194
36629
  );
36195
36630
  }
36196
36631
  }
36197
- /**
36198
- * Decrypts a file that was encrypted using the Vana protocol.
36199
- *
36200
- * @param file - The UserFile object containing the file URL and metadata
36201
- * @param encryptionSeed - Optional custom encryption seed (defaults to Vana standard)
36202
- * @returns Promise resolving to the decrypted file as a Blob
36203
- *
36204
- * This method handles the complete flow of:
36205
- * 1. Generating the encryption key from the user's wallet signature
36206
- * 2. Fetching the encrypted file from the stored URL
36207
- * 3. Decrypting the file using the canonical Vana decryption method
36208
- */
36209
- async decryptFile(file, encryptionSeed = DEFAULT_ENCRYPTION_SEED) {
36210
- try {
36211
- const encryptionKey = await generateEncryptionKey(
36212
- this.context.walletClient,
36213
- encryptionSeed
36214
- );
36215
- const fetchUrl = this.convertToDownloadUrl(file.url);
36216
- console.debug(
36217
- `Fetching encrypted file from URL: ${fetchUrl} (original: ${file.url})`
36218
- );
36219
- const response = await fetch(fetchUrl);
36220
- if (!response.ok) {
36221
- if (response.status === 404) {
36222
- throw new Error(
36223
- "File not found. The encrypted file may have been moved or deleted."
36224
- );
36225
- } else if (response.status === 403) {
36226
- throw new Error(
36227
- "Access denied. You may not have permission to access this file."
36228
- );
36229
- } else {
36230
- throw new Error(
36231
- `Network error: ${response.status} ${response.statusText}`
36232
- );
36233
- }
36234
- }
36235
- const encryptedBlob = await response.blob();
36236
- console.debug(
36237
- `Retrieved blob of size: ${encryptedBlob.size} bytes, type: ${encryptedBlob.type}`
36238
- );
36239
- if (encryptedBlob.size === 0) {
36240
- throw new Error("File is empty or could not be retrieved.");
36241
- }
36242
- const decryptedBlob = await decryptUserData(
36243
- encryptedBlob,
36244
- encryptionKey,
36245
- this.context.platform
36246
- );
36247
- return decryptedBlob;
36248
- } catch (error) {
36249
- console.error("Failed to decrypt file:", error);
36250
- if (error instanceof Error) {
36251
- if (error.message.includes("Session key decryption failed") || error.message.includes("Error decrypting message")) {
36252
- throw new Error(
36253
- "Wrong encryption key. This file may have been encrypted with a different wallet or encryption seed. Try using the same wallet that originally encrypted this file."
36254
- );
36255
- } else if (error.message.includes("Failed to fetch") || error.message.includes("Network error")) {
36256
- throw new Error(
36257
- "Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
36258
- );
36259
- } else if (error.message.includes("File not found")) {
36260
- throw new Error(
36261
- "File not found: The encrypted file is no longer available at the stored URL."
36262
- );
36263
- } else if (error.message.includes("not a valid OpenPGP message") || error.message.includes("does not conform to a valid OpenPGP format")) {
36264
- throw new Error(
36265
- "Invalid file format: This file doesn't appear to be encrypted with the Vana protocol."
36266
- );
36267
- }
36268
- }
36269
- throw error;
36270
- }
36271
- }
36272
36632
  /**
36273
36633
  * Registers a file URL directly on the blockchain with a schema ID.
36274
36634
  *
@@ -36329,26 +36689,6 @@ var DataController = class {
36329
36689
  );
36330
36690
  }
36331
36691
  }
36332
- /**
36333
- * Converts IPFS and Google Drive URLs to direct download URLs for fetching.
36334
- *
36335
- * @param url - The URL to convert to a direct download URL
36336
- * @returns The converted direct download URL or the original URL if not a special URL
36337
- */
36338
- convertToDownloadUrl(url) {
36339
- if (url.startsWith("ipfs://")) {
36340
- const hash = url.replace("ipfs://", "");
36341
- return `https://ipfs.io/ipfs/${hash}`;
36342
- }
36343
- if (url.includes("drive.google.com/file/d/")) {
36344
- const fileIdMatch = url.match(/\/file\/d\/([a-zA-Z0-9-_]+)/);
36345
- if (fileIdMatch) {
36346
- const fileId = fileIdMatch[1];
36347
- return `https://drive.google.com/uc?id=${fileId}&export=download`;
36348
- }
36349
- }
36350
- return url;
36351
- }
36352
36692
  /**
36353
36693
  * Gets the user's address from the wallet client.
36354
36694
  *
@@ -36423,9 +36763,70 @@ var DataController = class {
36423
36763
  );
36424
36764
  }
36425
36765
  }
36766
+ /**
36767
+ * Adds a file to the registry with permissions and schema.
36768
+ * This combines the functionality of addFileWithPermissions and schema validation.
36769
+ *
36770
+ * @param url - The URL of the file to register
36771
+ * @param ownerAddress - The address of the file owner
36772
+ * @param permissions - Array of permissions to grant (account and encrypted key)
36773
+ * @param schemaId - The schema ID to associate with the file (0 for no schema)
36774
+ * @returns Promise resolving to object with fileId and transactionHash
36775
+ */
36776
+ async addFileWithPermissionsAndSchema(url, ownerAddress, permissions = [], schemaId = 0) {
36777
+ try {
36778
+ const chainId = this.context.walletClient.chain?.id;
36779
+ if (!chainId) {
36780
+ throw new Error("Chain ID not available");
36781
+ }
36782
+ const dataRegistryAddress = getContractAddress(chainId, "DataRegistry");
36783
+ const dataRegistryAbi = getAbi("DataRegistry");
36784
+ const txHash = await this.context.walletClient.writeContract({
36785
+ address: dataRegistryAddress,
36786
+ abi: dataRegistryAbi,
36787
+ functionName: "addFileWithPermissionsAndSchema",
36788
+ args: [url, ownerAddress, permissions, BigInt(schemaId)],
36789
+ account: this.context.walletClient.account || ownerAddress,
36790
+ chain: this.context.walletClient.chain || null
36791
+ });
36792
+ const receipt = await this.context.publicClient.waitForTransactionReceipt(
36793
+ {
36794
+ hash: txHash,
36795
+ timeout: 3e4
36796
+ // 30 seconds timeout
36797
+ }
36798
+ );
36799
+ let fileId = 0;
36800
+ for (const log of receipt.logs) {
36801
+ try {
36802
+ const decoded = decodeEventLog({
36803
+ abi: dataRegistryAbi,
36804
+ data: log.data,
36805
+ topics: log.topics
36806
+ });
36807
+ if (decoded.eventName === "FileAdded") {
36808
+ fileId = Number(decoded.args.fileId);
36809
+ break;
36810
+ }
36811
+ } catch {
36812
+ continue;
36813
+ }
36814
+ }
36815
+ return {
36816
+ fileId,
36817
+ transactionHash: txHash
36818
+ };
36819
+ } catch (error) {
36820
+ console.error("Failed to add file with permissions and schema:", error);
36821
+ throw new Error(
36822
+ `Failed to add file with permissions and schema: ${error instanceof Error ? error.message : "Unknown error"}`
36823
+ );
36824
+ }
36825
+ }
36426
36826
  /**
36427
36827
  * Adds a new schema to the DataRefinerRegistry.
36428
36828
  *
36829
+ * @deprecated Use vana.schemas.create() instead for the high-level API with automatic IPFS upload
36429
36830
  * @param params - Schema parameters including name, type, and definition URL
36430
36831
  * @returns Promise resolving to the new schema ID and transaction hash
36431
36832
  */
@@ -36484,6 +36885,7 @@ var DataController = class {
36484
36885
  /**
36485
36886
  * Retrieves a schema by its ID.
36486
36887
  *
36888
+ * @deprecated Use vana.schemas.get() instead
36487
36889
  * @param schemaId - The schema ID to retrieve
36488
36890
  * @returns Promise resolving to the schema information
36489
36891
  */
@@ -36509,11 +36911,15 @@ var DataController = class {
36509
36911
  if (!schemaData) {
36510
36912
  throw new Error("Schema not found");
36511
36913
  }
36914
+ const schemaObj = schemaData;
36915
+ if (!schemaObj.name || !schemaObj.typ || !schemaObj.definitionUrl) {
36916
+ throw new Error("Incomplete schema data");
36917
+ }
36512
36918
  return {
36513
36919
  id: schemaId,
36514
- name: schemaData.name,
36515
- type: schemaData.typ,
36516
- definitionUrl: schemaData.definitionUrl
36920
+ name: schemaObj.name,
36921
+ type: schemaObj.typ,
36922
+ definitionUrl: schemaObj.definitionUrl
36517
36923
  };
36518
36924
  } catch (error) {
36519
36925
  console.error("Failed to get schema:", error);
@@ -36525,6 +36931,7 @@ var DataController = class {
36525
36931
  /**
36526
36932
  * Gets the total number of schemas in the registry.
36527
36933
  *
36934
+ * @deprecated Use vana.schemas.count() instead
36528
36935
  * @returns Promise resolving to the total schema count
36529
36936
  */
36530
36937
  async getSchemasCount() {
@@ -36570,7 +36977,7 @@ var DataController = class {
36570
36977
  const txHash = await this.context.walletClient.writeContract({
36571
36978
  address: dataRefinerRegistryAddress,
36572
36979
  abi: dataRefinerRegistryAbi,
36573
- functionName: "addRefiner",
36980
+ functionName: "addRefinerWithSchemaId",
36574
36981
  args: [
36575
36982
  BigInt(params.dlpId),
36576
36983
  params.name,
@@ -36773,9 +37180,10 @@ var DataController = class {
36773
37180
  try {
36774
37181
  const userEncryptionKey = await generateEncryptionKey(
36775
37182
  this.context.walletClient,
37183
+ this.context.platform,
36776
37184
  DEFAULT_ENCRYPTION_SEED
36777
37185
  );
36778
- const encryptedData = await encryptUserData(
37186
+ const encryptedData = await encryptBlobWithSignedKey(
36779
37187
  data,
36780
37188
  userEncryptionKey,
36781
37189
  this.context.platform
@@ -36838,16 +37246,47 @@ var DataController = class {
36838
37246
  * 1. Gets the user's encryption key
36839
37247
  * 2. Encrypts the user's encryption key with the provided public key
36840
37248
  * 3. Adds the permission to the file
37249
+ * 4. Returns the permission data from the blockchain event
37250
+ *
37251
+ * For advanced users who need more control over transaction timing,
37252
+ * use `submitFilePermission()` instead.
36841
37253
  *
36842
37254
  * @param fileId - The ID of the file to add permissions for
36843
37255
  * @param account - The address of the account to grant permission to
36844
37256
  * @param publicKey - The public key to encrypt the user's encryption key with
36845
- * @returns Promise resolving to the transaction hash
37257
+ * @returns Promise resolving to permission data from PermissionGranted event
37258
+ * @example
37259
+ * ```typescript
37260
+ * const result = await vana.data.addPermissionToFile(fileId, account, publicKey);
37261
+ * console.log(`Permission granted to ${result.account} for file ${result.fileId}`);
37262
+ * console.log(`Transaction: ${result.transactionHash}`);
37263
+ * ```
36846
37264
  */
36847
37265
  async addPermissionToFile(fileId, account, publicKey) {
37266
+ const txHash = await this.submitFilePermission(fileId, account, publicKey);
37267
+ return parseTransactionResult(this.context, txHash, "addFilePermission");
37268
+ }
37269
+ /**
37270
+ * Submits a file permission transaction and returns the transaction hash immediately.
37271
+ *
37272
+ * This is the lower-level method that provides maximum control over transaction timing.
37273
+ * Use this when you want to handle transaction confirmation and event parsing separately.
37274
+ *
37275
+ * @param fileId - The ID of the file to add permissions for
37276
+ * @param account - The address of the account to grant permission to
37277
+ * @param publicKey - The public key to encrypt the user's encryption key with
37278
+ * @returns Promise resolving to the transaction hash
37279
+ * @example
37280
+ * ```typescript
37281
+ * const txHash = await vana.data.submitFilePermission(fileId, account, publicKey);
37282
+ * console.log(`Transaction submitted: ${txHash}`);
37283
+ * ```
37284
+ */
37285
+ async submitFilePermission(fileId, account, publicKey) {
36848
37286
  try {
36849
37287
  const userEncryptionKey = await generateEncryptionKey(
36850
37288
  this.context.walletClient,
37289
+ this.context.platform,
36851
37290
  DEFAULT_ENCRYPTION_SEED
36852
37291
  );
36853
37292
  const encryptedKey = await encryptWithWalletPublicKey(
@@ -36939,12 +37378,13 @@ var DataController = class {
36939
37378
  privateKey,
36940
37379
  this.context.platform
36941
37380
  );
36942
- const response = await fetch(this.convertToDownloadUrl(file.url));
36943
- if (!response.ok) {
36944
- throw new Error(`Failed to download file: ${response.statusText}`);
37381
+ let encryptedData;
37382
+ if (file.url.startsWith("ipfs://")) {
37383
+ encryptedData = await this.fetchFromIPFS(file.url);
37384
+ } else {
37385
+ encryptedData = await this.fetch(file.url);
36945
37386
  }
36946
- const encryptedData = await response.blob();
36947
- const decryptedData = await decryptUserData(
37387
+ const decryptedData = await decryptBlobWithSignedKey(
36948
37388
  encryptedData,
36949
37389
  userEncryptionKey,
36950
37390
  this.context.platform
@@ -36957,6 +37397,162 @@ var DataController = class {
36957
37397
  );
36958
37398
  }
36959
37399
  }
37400
+ /**
37401
+ * Simple network-agnostic fetch utility for retrieving file content.
37402
+ *
37403
+ * @remarks
37404
+ * This is a thin wrapper around the global fetch API that returns the response as a Blob.
37405
+ * It provides a consistent interface for fetching encrypted content before decryption.
37406
+ * For IPFS URLs, consider using fetchFromIPFS for better reliability.
37407
+ *
37408
+ * @param url - The URL to fetch content from
37409
+ * @returns Promise resolving to the fetched content as a Blob
37410
+ * @throws {Error} When the fetch fails or returns a non-ok response
37411
+ *
37412
+ * @example
37413
+ * ```typescript
37414
+ * // Fetch and decrypt a file
37415
+ * const encryptionKey = await generateEncryptionKey(walletClient);
37416
+ * const encryptedBlob = await vana.data.fetch(file.url);
37417
+ * const decryptedBlob = await decryptBlob(encryptedBlob, encryptionKey, platform);
37418
+ *
37419
+ * // With custom headers for authentication
37420
+ * const response = await fetch(file.url, {
37421
+ * headers: { 'Authorization': 'Bearer token' }
37422
+ * });
37423
+ * const encryptedBlob = await response.blob();
37424
+ * ```
37425
+ */
37426
+ async fetch(url) {
37427
+ try {
37428
+ const response = await fetch(url);
37429
+ if (!response.ok) {
37430
+ throw new Error(
37431
+ `HTTP error! status: ${response.status} ${response.statusText}`
37432
+ );
37433
+ }
37434
+ const blob = await response.blob();
37435
+ if (blob.size === 0) {
37436
+ throw new Error("Empty response");
37437
+ }
37438
+ return blob;
37439
+ } catch (error) {
37440
+ if (error instanceof TypeError && error.message.includes("fetch")) {
37441
+ throw new Error(
37442
+ `Network error: Failed to fetch from ${url}. The URL may be invalid or the server may not be accessible.`
37443
+ );
37444
+ }
37445
+ throw error;
37446
+ }
37447
+ }
37448
+ /**
37449
+ * Specialized IPFS fetcher with gateway fallback mechanism.
37450
+ *
37451
+ * @remarks
37452
+ * This method provides robust IPFS content fetching by trying multiple gateways
37453
+ * in sequence until one succeeds. It supports both ipfs:// URLs and raw CIDs.
37454
+ *
37455
+ * The default gateway list includes public gateways, but you should provide
37456
+ * your own gateways for production use to ensure reliability and privacy.
37457
+ *
37458
+ * @param url - The IPFS URL (ipfs://...) or CID to fetch
37459
+ * @param options - Optional configuration
37460
+ * @param options.gateways - Array of IPFS gateway URLs to try (must end with /)
37461
+ * @returns Promise resolving to the fetched content as a Blob
37462
+ * @throws {Error} When all gateways fail to fetch the content
37463
+ *
37464
+ * @example
37465
+ * ```typescript
37466
+ * // Fetch from IPFS with custom gateways
37467
+ * const encryptedBlob = await vana.data.fetchFromIPFS(file.url, {
37468
+ * gateways: [
37469
+ * 'https://my-private-gateway.com/ipfs/',
37470
+ * 'https://dweb.link/ipfs/',
37471
+ * 'https://ipfs.io/ipfs/'
37472
+ * ]
37473
+ * });
37474
+ *
37475
+ * // Decrypt the fetched content
37476
+ * const encryptionKey = await generateEncryptionKey(walletClient);
37477
+ * const decryptedBlob = await decryptBlob(encryptedBlob, encryptionKey, platform);
37478
+ *
37479
+ * // With raw CID
37480
+ * const blob = await vana.data.fetchFromIPFS('QmXxx...', {
37481
+ * gateways: ['https://ipfs.io/ipfs/']
37482
+ * });
37483
+ * ```
37484
+ */
37485
+ async fetchFromIPFS(url, options) {
37486
+ const defaultGateways = [
37487
+ "https://dweb.link/ipfs/",
37488
+ "https://ipfs.io/ipfs/"
37489
+ ];
37490
+ const gateways = options?.gateways || this.context.ipfsGateways || defaultGateways;
37491
+ let cid;
37492
+ if (url.startsWith("ipfs://")) {
37493
+ cid = url.replace("ipfs://", "");
37494
+ } else if (url.startsWith("Qm") || url.startsWith("bafy")) {
37495
+ cid = url;
37496
+ } else {
37497
+ throw new Error(
37498
+ `Invalid IPFS URL format. Expected ipfs://... or a raw CID, got: ${url}`
37499
+ );
37500
+ }
37501
+ const errors = [];
37502
+ for (let i = 0; i < gateways.length; i++) {
37503
+ const gateway = gateways[i];
37504
+ const isLastGateway = i === gateways.length - 1;
37505
+ const gatewayUrl = gateway.endsWith("/") ? `${gateway}${cid}` : `${gateway}/${cid}`;
37506
+ try {
37507
+ console.debug(`Trying IPFS gateway: ${gatewayUrl}`);
37508
+ const response = await fetch(gatewayUrl);
37509
+ if (response.ok) {
37510
+ const blob = await response.blob();
37511
+ if (blob.size > 0) {
37512
+ console.debug(`Successfully fetched from gateway: ${gateway}`);
37513
+ return blob;
37514
+ } else {
37515
+ if (isLastGateway) {
37516
+ throw new Error("Empty response");
37517
+ }
37518
+ errors.push({
37519
+ gateway,
37520
+ error: "Empty response"
37521
+ });
37522
+ }
37523
+ } else {
37524
+ if (isLastGateway) {
37525
+ if (response.status === 403) {
37526
+ throw new Error(`HTTP error! status: 403 ${response.statusText}`);
37527
+ } else if (response.status === 404) {
37528
+ throw new Error(`HTTP error! status: 404 ${response.statusText}`);
37529
+ } else {
37530
+ throw new Error(
37531
+ `HTTP error! status: ${response.status} ${response.statusText}`
37532
+ );
37533
+ }
37534
+ }
37535
+ errors.push({
37536
+ gateway,
37537
+ error: `HTTP ${response.status} ${response.statusText}`
37538
+ });
37539
+ }
37540
+ } catch (error) {
37541
+ if (isLastGateway && error instanceof Error && (error.message.includes("Empty response") || error.message.includes("HTTP error!"))) {
37542
+ throw error;
37543
+ }
37544
+ errors.push({
37545
+ gateway,
37546
+ error: error instanceof Error ? error.message : "Unknown error"
37547
+ });
37548
+ }
37549
+ }
37550
+ const errorDetails = errors.map((e) => `${e.gateway}: ${e.error}`).join("\n ");
37551
+ throw new Error(
37552
+ `Failed to fetch IPFS content ${cid} from all gateways:
37553
+ ${errorDetails}`
37554
+ );
37555
+ }
36960
37556
  /**
36961
37557
  * Validates a data schema against the Vana meta-schema.
36962
37558
  *
@@ -37078,12 +37674,365 @@ var DataController = class {
37078
37674
  }
37079
37675
  };
37080
37676
 
37677
+ // src/controllers/schemas.ts
37678
+ import { getContract as getContract2, decodeEventLog as decodeEventLog2 } from "viem";
37679
+ var SchemaController = class {
37680
+ constructor(context) {
37681
+ this.context = context;
37682
+ }
37683
+ /**
37684
+ * Creates a new schema with automatic validation and IPFS upload.
37685
+ *
37686
+ * @remarks
37687
+ * This is the primary method for creating schemas on the Vana network. It handles
37688
+ * the complete workflow including schema validation, IPFS upload, and blockchain
37689
+ * registration. The schema definition is stored unencrypted on IPFS to enable
37690
+ * public access and reusability.
37691
+ *
37692
+ * The method automatically:
37693
+ * - Validates the schema definition against the Vana metaschema
37694
+ * - Uploads the definition to IPFS to generate a permanent URL
37695
+ * - Registers the schema on the blockchain with the generated URL
37696
+ *
37697
+ * @param params - Schema creation parameters including name, type, and definition
37698
+ * @returns Promise resolving to creation results with schema ID and transaction hash
37699
+ * @throws {SchemaValidationError} When the schema definition is invalid
37700
+ * @throws {Error} When IPFS upload or blockchain registration fails
37701
+ * @example
37702
+ * ```typescript
37703
+ * // Create a JSON schema for user profiles
37704
+ * const result = await vana.schemas.create({
37705
+ * name: "User Profile",
37706
+ * type: "personal",
37707
+ * definition: {
37708
+ * type: "object",
37709
+ * properties: {
37710
+ * name: { type: "string" },
37711
+ * age: { type: "number", minimum: 0 }
37712
+ * },
37713
+ * required: ["name"]
37714
+ * }
37715
+ * });
37716
+ *
37717
+ * console.log(`Schema created with ID: ${result.schemaId}`);
37718
+ * ```
37719
+ */
37720
+ async create(params) {
37721
+ const { name, type, definition } = params;
37722
+ try {
37723
+ let schemaDefinition;
37724
+ if (typeof definition === "string") {
37725
+ try {
37726
+ schemaDefinition = JSON.parse(definition);
37727
+ } catch {
37728
+ throw new SchemaValidationError(
37729
+ "Invalid JSON in schema definition",
37730
+ []
37731
+ );
37732
+ }
37733
+ } else {
37734
+ schemaDefinition = definition;
37735
+ }
37736
+ const dataSchema = {
37737
+ name,
37738
+ version: "1.0.0",
37739
+ dialect: "json",
37740
+ schema: schemaDefinition
37741
+ };
37742
+ validateDataSchema(dataSchema);
37743
+ if (!this.context.storageManager) {
37744
+ if (this.context.validateStorageRequired) {
37745
+ this.context.validateStorageRequired();
37746
+ throw new Error("Storage validation failed");
37747
+ } else {
37748
+ throw new Error(
37749
+ "Storage manager not configured. Please provide storage providers in VanaConfig."
37750
+ );
37751
+ }
37752
+ }
37753
+ const schemaBlob = new Blob([JSON.stringify(schemaDefinition)], {
37754
+ type: "application/json"
37755
+ });
37756
+ const uploadResult = await this.context.storageManager.upload(
37757
+ schemaBlob,
37758
+ `${name.replace(/[^a-zA-Z0-9]/g, "_")}.json`,
37759
+ "ipfs"
37760
+ // Use IPFS for public schema storage
37761
+ );
37762
+ const chainId = this.context.walletClient.chain?.id;
37763
+ if (!chainId) {
37764
+ throw new Error("Chain ID not available");
37765
+ }
37766
+ const dataRefinerRegistryAddress = getContractAddress(
37767
+ chainId,
37768
+ "DataRefinerRegistry"
37769
+ );
37770
+ const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
37771
+ const userAddress = await this.getUserAddress();
37772
+ const txHash = await this.context.walletClient.writeContract({
37773
+ address: dataRefinerRegistryAddress,
37774
+ abi: dataRefinerRegistryAbi,
37775
+ functionName: "addSchema",
37776
+ args: [name, type, uploadResult.url],
37777
+ account: this.context.walletClient.account || userAddress,
37778
+ chain: this.context.walletClient.chain || null
37779
+ });
37780
+ const receipt = await this.context.publicClient.waitForTransactionReceipt(
37781
+ {
37782
+ hash: txHash,
37783
+ timeout: 3e4
37784
+ // 30 seconds timeout
37785
+ }
37786
+ );
37787
+ let schemaId = 0;
37788
+ for (const log of receipt.logs) {
37789
+ try {
37790
+ const decoded = decodeEventLog2({
37791
+ abi: dataRefinerRegistryAbi,
37792
+ data: log.data,
37793
+ topics: log.topics
37794
+ });
37795
+ if (decoded.eventName === "SchemaAdded") {
37796
+ schemaId = Number(decoded.args.schemaId);
37797
+ break;
37798
+ }
37799
+ } catch {
37800
+ }
37801
+ }
37802
+ return {
37803
+ schemaId,
37804
+ definitionUrl: uploadResult.url,
37805
+ transactionHash: txHash
37806
+ };
37807
+ } catch (error) {
37808
+ if (error instanceof SchemaValidationError) {
37809
+ throw error;
37810
+ }
37811
+ throw new Error(
37812
+ `Schema creation failed: ${error instanceof Error ? error.message : "Unknown error"}`
37813
+ );
37814
+ }
37815
+ }
37816
+ /**
37817
+ * Retrieves a schema by its ID.
37818
+ *
37819
+ * @param schemaId - The ID of the schema to retrieve
37820
+ * @returns Promise resolving to the schema object
37821
+ * @throws {Error} When the schema is not found or chain is unavailable
37822
+ * @example
37823
+ * ```typescript
37824
+ * const schema = await vana.schemas.get(1);
37825
+ * console.log(`Schema: ${schema.name} (${schema.type})`);
37826
+ * ```
37827
+ */
37828
+ async get(schemaId) {
37829
+ try {
37830
+ const chainId = this.context.walletClient.chain?.id;
37831
+ if (!chainId) {
37832
+ throw new Error("Chain ID not available");
37833
+ }
37834
+ const dataRefinerRegistryAddress = getContractAddress(
37835
+ chainId,
37836
+ "DataRefinerRegistry"
37837
+ );
37838
+ const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
37839
+ const dataRefinerRegistry = getContract2({
37840
+ address: dataRefinerRegistryAddress,
37841
+ abi: dataRefinerRegistryAbi,
37842
+ client: this.context.publicClient
37843
+ });
37844
+ const schemaData = await dataRefinerRegistry.read.schemas([
37845
+ BigInt(schemaId)
37846
+ ]);
37847
+ if (!schemaData) {
37848
+ throw new Error(`Schema with ID ${schemaId} not found`);
37849
+ }
37850
+ const schemaObj = schemaData;
37851
+ if (!schemaObj.name || !schemaObj.typ || !schemaObj.definitionUrl) {
37852
+ throw new Error("Incomplete schema data");
37853
+ }
37854
+ return {
37855
+ id: schemaId,
37856
+ name: schemaObj.name,
37857
+ type: schemaObj.typ,
37858
+ definitionUrl: schemaObj.definitionUrl
37859
+ };
37860
+ } catch (error) {
37861
+ throw new Error(
37862
+ `Failed to get schema: ${error instanceof Error ? error.message : "Unknown error"}`
37863
+ );
37864
+ }
37865
+ }
37866
+ /**
37867
+ * Gets the total number of schemas registered on the network.
37868
+ *
37869
+ * @returns Promise resolving to the total schema count
37870
+ * @throws {Error} When the count cannot be retrieved
37871
+ * @example
37872
+ * ```typescript
37873
+ * const count = await vana.schemas.count();
37874
+ * console.log(`Total schemas: ${count}`);
37875
+ * ```
37876
+ */
37877
+ async count() {
37878
+ try {
37879
+ const chainId = this.context.walletClient.chain?.id;
37880
+ if (!chainId) {
37881
+ throw new Error("Chain ID not available");
37882
+ }
37883
+ const dataRefinerRegistryAddress = getContractAddress(
37884
+ chainId,
37885
+ "DataRefinerRegistry"
37886
+ );
37887
+ const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
37888
+ const dataRefinerRegistry = getContract2({
37889
+ address: dataRefinerRegistryAddress,
37890
+ abi: dataRefinerRegistryAbi,
37891
+ client: this.context.publicClient
37892
+ });
37893
+ const count = await dataRefinerRegistry.read.schemasCount();
37894
+ return Number(count);
37895
+ } catch (error) {
37896
+ throw new Error(
37897
+ `Failed to get schemas count: ${error instanceof Error ? error.message : "Unknown error"}`
37898
+ );
37899
+ }
37900
+ }
37901
+ /**
37902
+ * Lists all schemas with pagination.
37903
+ *
37904
+ * @param options - Optional parameters for listing schemas
37905
+ * @param options.limit - Maximum number of schemas to return
37906
+ * @param options.offset - Number of schemas to skip
37907
+ * @returns Promise resolving to an array of schemas
37908
+ * @example
37909
+ * ```typescript
37910
+ * // Get all schemas
37911
+ * const schemas = await vana.schemas.list();
37912
+ *
37913
+ * // Get schemas with pagination
37914
+ * const schemas = await vana.schemas.list({ limit: 10, offset: 0 });
37915
+ * ```
37916
+ */
37917
+ async list(options = {}) {
37918
+ const { limit = 100, offset = 0 } = options;
37919
+ try {
37920
+ const totalCount = await this.count();
37921
+ const schemas = [];
37922
+ const start = offset;
37923
+ const end = Math.min(start + limit, totalCount);
37924
+ for (let i = start; i < end; i++) {
37925
+ try {
37926
+ const schema = await this.get(i + 1);
37927
+ schemas.push(schema);
37928
+ } catch (error) {
37929
+ console.warn(`Failed to retrieve schema ${i + 1}:`, error);
37930
+ }
37931
+ }
37932
+ return schemas;
37933
+ } catch (error) {
37934
+ throw new Error(
37935
+ `Failed to list schemas: ${error instanceof Error ? error.message : "Unknown error"}`
37936
+ );
37937
+ }
37938
+ }
37939
+ /**
37940
+ * Adds a schema using the legacy method (low-level API).
37941
+ *
37942
+ * @deprecated Use create() instead for the high-level API with automatic IPFS upload
37943
+ * @param params - Schema parameters including pre-generated definition URL
37944
+ * @returns Promise resolving to the add schema result
37945
+ */
37946
+ async addSchema(params) {
37947
+ try {
37948
+ const chainId = this.context.walletClient.chain?.id;
37949
+ if (!chainId) {
37950
+ throw new Error("Chain ID not available");
37951
+ }
37952
+ const dataRefinerRegistryAddress = getContractAddress(
37953
+ chainId,
37954
+ "DataRefinerRegistry"
37955
+ );
37956
+ const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
37957
+ const userAddress = await this.getUserAddress();
37958
+ const txHash = await this.context.walletClient.writeContract({
37959
+ address: dataRefinerRegistryAddress,
37960
+ abi: dataRefinerRegistryAbi,
37961
+ functionName: "addSchema",
37962
+ args: [params.name, params.type, params.definitionUrl],
37963
+ account: this.context.walletClient.account || userAddress,
37964
+ chain: this.context.walletClient.chain || null
37965
+ });
37966
+ return {
37967
+ schemaId: 0,
37968
+ // TODO: Parse from transaction receipt
37969
+ transactionHash: txHash
37970
+ };
37971
+ } catch (error) {
37972
+ throw new Error(
37973
+ `Failed to add schema: ${error instanceof Error ? error.message : "Unknown error"}`
37974
+ );
37975
+ }
37976
+ }
37977
+ /**
37978
+ * Gets the user's wallet address.
37979
+ *
37980
+ * @private
37981
+ * @returns Promise resolving to the user's address
37982
+ */
37983
+ async getUserAddress() {
37984
+ if (!this.context.walletClient.account) {
37985
+ throw new Error("No wallet account connected");
37986
+ }
37987
+ if (typeof this.context.walletClient.account === "string") {
37988
+ return this.context.walletClient.account;
37989
+ }
37990
+ if (typeof this.context.walletClient.account === "object" && this.context.walletClient.account.address) {
37991
+ return this.context.walletClient.account.address;
37992
+ }
37993
+ throw new Error("Unable to determine wallet address");
37994
+ }
37995
+ };
37996
+
37081
37997
  // src/controllers/server.ts
37082
37998
  var ServerController = class {
37083
37999
  constructor(context) {
37084
38000
  this.context = context;
37085
38001
  __publicField(this, "PERSONAL_SERVER_BASE_URL", process.env.NEXT_PUBLIC_PERSONAL_SERVER_BASE_URL);
37086
38002
  }
38003
+ /**
38004
+ * Retrieves the cryptographic identity of a personal server.
38005
+ *
38006
+ * @remarks
38007
+ * This method fetches the public key and metadata for a personal server,
38008
+ * which is required for encrypting data before sharing with the server.
38009
+ * The identity includes the server's public key, address, and operational
38010
+ * details needed for secure communication. This information is cached
38011
+ * by identity servers to enable offline key retrieval.
38012
+ *
38013
+ * @param request - Parameters containing the user address
38014
+ * @param request.userAddress - The wallet address associated with the personal server
38015
+ * @returns Promise resolving to the server's identity information
38016
+ * @throws {NetworkError} When the identity service is unavailable or returns invalid data
38017
+ * @throws {PersonalServerError} When server identity cannot be retrieved
38018
+ * @example
38019
+ * ```typescript
38020
+ * // Get server identity for data encryption
38021
+ * const identity = await vana.server.getIdentity({
38022
+ * userAddress: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36"
38023
+ * });
38024
+ *
38025
+ * console.log(`Server: ${identity.name}`);
38026
+ * console.log(`Address: ${identity.address}`);
38027
+ * console.log(`Public Key: ${identity.public_key}`);
38028
+ *
38029
+ * // Use the public key for encrypting data to share with this server
38030
+ * const encryptedData = await encryptWithWalletPublicKey(
38031
+ * userData,
38032
+ * identity.public_key
38033
+ * );
38034
+ * ```
38035
+ */
37087
38036
  async getIdentity(request) {
37088
38037
  try {
37089
38038
  const response = await fetch(
@@ -37104,6 +38053,7 @@ var ServerController = class {
37104
38053
  }
37105
38054
  const serverResponse = await response.json();
37106
38055
  return {
38056
+ kind: serverResponse.personal_server.kind,
37107
38057
  address: serverResponse.personal_server.address,
37108
38058
  public_key: serverResponse.personal_server.public_key,
37109
38059
  base_url: this.PERSONAL_SERVER_BASE_URL || "",
@@ -37125,10 +38075,13 @@ var ServerController = class {
37125
38075
  * This method submits a computation request to the personal server API.
37126
38076
  * The response includes the operation ID.
37127
38077
  * @param params - The request parameters object
37128
- * @param params.permissionId - The permission ID authorizing this operation
38078
+ * @param params.permissionId - The permission ID authorizing this operation.
38079
+ * Obtain from granted permissions via `vana.permissions.getUserPermissionGrantsOnChain()`.
37129
38080
  * @returns A Promise that resolves to an operation response with status and control URLs
37130
- * @throws {PersonalServerError} When server request fails or parameters are invalid
37131
- * @throws {NetworkError} When personal server API communication fails
38081
+ * @throws {PersonalServerError} When server request fails or parameters are invalid.
38082
+ * Verify permissionId exists and is active for the target server.
38083
+ * @throws {NetworkError} When personal server API communication fails.
38084
+ * Check server URL configuration and network connectivity.
37132
38085
  * @example
37133
38086
  * ```typescript
37134
38087
  * const response = await vana.server.createOperation({
@@ -37230,6 +38183,50 @@ var ServerController = class {
37230
38183
  );
37231
38184
  }
37232
38185
  }
38186
+ /**
38187
+ * Cancels a running operation on the personal server.
38188
+ *
38189
+ * @remarks
38190
+ * This method attempts to cancel an operation that is currently processing
38191
+ * on the personal server. The operation must be in a cancellable state
38192
+ * (typically `starting` or `processing`). Not all operations support
38193
+ * cancellation, and cancellation may not be immediate. The server will
38194
+ * attempt to stop the operation and update its status to `canceled`.
38195
+ *
38196
+ * **Cancellation Behavior:**
38197
+ * - Operations in `succeeded` or `failed` states cannot be canceled
38198
+ * - Some long-running operations may take time to respond to cancellation
38199
+ * - Always verify cancellation by polling the operation status afterward
38200
+ *
38201
+ * @param operationId - The unique identifier of the operation to cancel,
38202
+ * obtained from `createOperation()` response
38203
+ * @returns Promise that resolves when the cancellation request is accepted
38204
+ * @throws {PersonalServerError} When the operation cannot be canceled or doesn't exist.
38205
+ * Check operation status - it may already be completed or failed.
38206
+ * @throws {NetworkError} When unable to reach the personal server API.
38207
+ * Verify server URL and network connectivity.
38208
+ * @example
38209
+ * ```typescript
38210
+ * // Start a long-running operation
38211
+ * const operation = await vana.server.createOperation({
38212
+ * permissionId: 123
38213
+ * });
38214
+ *
38215
+ * // Cancel if needed
38216
+ * try {
38217
+ * await vana.server.cancelOperation(operation.id);
38218
+ * console.log("Cancellation requested");
38219
+ *
38220
+ * // Verify cancellation
38221
+ * const status = await vana.server.getOperation(operation.id);
38222
+ * if (status.status === "canceled") {
38223
+ * console.log("Operation successfully canceled");
38224
+ * }
38225
+ * } catch (error) {
38226
+ * console.error("Failed to cancel:", error);
38227
+ * }
38228
+ * ```
38229
+ */
37233
38230
  async cancelOperation(operationId) {
37234
38231
  try {
37235
38232
  const response = await fetch(
@@ -37256,7 +38253,7 @@ var ServerController = class {
37256
38253
  /**
37257
38254
  * Makes the request to the personal server API.
37258
38255
  *
37259
- * @param params - The post request parameters to serialize
38256
+ * @param requestBody - The post request parameters to serialize
37260
38257
  * @returns JSON string representation of the request data
37261
38258
  */
37262
38259
  async makeRequest(requestBody) {
@@ -37339,7 +38336,7 @@ var ServerController = class {
37339
38336
 
37340
38337
  // src/contracts/contractController.ts
37341
38338
  import {
37342
- getContract as getContract2
38339
+ getContract as getContract3
37343
38340
  } from "viem";
37344
38341
 
37345
38342
  // src/core/client.ts
@@ -37440,7 +38437,7 @@ function getContractController(contract, client = createClient()) {
37440
38437
  const cacheKey = createCacheKey(contract, chainId);
37441
38438
  let controller = contractCache.get(cacheKey);
37442
38439
  if (!controller) {
37443
- controller = getContract2({
38440
+ controller = getContract3({
37444
38441
  address: getContractAddress(chainId, contract),
37445
38442
  abi: getAbi(contract),
37446
38443
  client
@@ -37533,7 +38530,8 @@ var ProtocolController = class {
37533
38530
  * are actually deployed on the current network.
37534
38531
  * @param contractName - The name of the Vana contract to retrieve (use const assertion for full typing)
37535
38532
  * @returns An object containing the contract's address and fully typed ABI
37536
- * @throws {ContractNotFoundError} When the contract is not deployed on the current chain
38533
+ * @throws {ContractNotFoundError} When the contract is not deployed on the current chain.
38534
+ * Verify contract name spelling and check current network with `getChainId()`.
37537
38535
  * @example
37538
38536
  * ```typescript
37539
38537
  * // Get contract info with full type inference
@@ -38154,6 +39152,7 @@ var GoogleDriveStorage = class {
38154
39152
  };
38155
39153
 
38156
39154
  // src/storage/providers/ipfs.ts
39155
+ init_crypto_utils();
38157
39156
  var IpfsStorage = class _IpfsStorage {
38158
39157
  constructor(config) {
38159
39158
  this.config = config;
@@ -38193,7 +39192,7 @@ var IpfsStorage = class _IpfsStorage {
38193
39192
  * ```
38194
39193
  */
38195
39194
  static forInfura(credentials) {
38196
- const auth = btoa(`${credentials.projectId}:${credentials.projectSecret}`);
39195
+ const auth = toBase64(`${credentials.projectId}:${credentials.projectSecret}`);
38197
39196
  return new _IpfsStorage({
38198
39197
  apiEndpoint: "https://ipfs.infura.io:5001/api/v0/add",
38199
39198
  gatewayUrl: "https://ipfs.infura.io/ipfs",
@@ -38717,175 +39716,151 @@ var PinataStorage = class {
38717
39716
  }
38718
39717
  };
38719
39718
 
38720
- // src/storage/providers/server-proxy.ts
38721
- var ServerProxyStorage = class {
38722
- constructor(config) {
38723
- this.config = config;
38724
- if (!config.uploadUrl) {
38725
- throw new StorageError(
38726
- "Upload URL is required",
38727
- "MISSING_UPLOAD_URL",
38728
- "server-proxy"
38729
- );
38730
- }
38731
- if (!config.downloadUrl) {
38732
- throw new StorageError(
38733
- "Download URL is required",
38734
- "MISSING_DOWNLOAD_URL",
38735
- "server-proxy"
39719
+ // src/storage/providers/callback-storage.ts
39720
+ var CallbackStorage = class {
39721
+ constructor(callbacks) {
39722
+ this.callbacks = callbacks;
39723
+ if (!callbacks.upload || !callbacks.download) {
39724
+ throw new Error(
39725
+ "CallbackStorage requires both upload and download callbacks"
38736
39726
  );
38737
39727
  }
38738
39728
  }
38739
39729
  /**
38740
- * Uploads a file through your server endpoint
39730
+ * Upload a file using the provided callback
38741
39731
  *
38742
- * @remarks
38743
- * This method sends the file to your configured upload endpoint via FormData.
38744
- * Your server is responsible for handling the actual storage implementation
38745
- * and must return a JSON response with `success: true` and an `identifier` field.
38746
- *
38747
- * @param file - The file to upload
38748
- * @param filename - Optional custom filename
38749
- * @returns Promise that resolves to the server-provided identifier
38750
- * @throws {StorageError} When the upload fails or server returns an error
38751
- *
38752
- * @example
38753
- * ```typescript
38754
- * const identifier = await serverStorage.upload(fileBlob, { name: "report.pdf" });
38755
- * console.log("File uploaded with identifier:", identifier);
38756
- * ```
39732
+ * @param file - The blob to upload
39733
+ * @param filename - Optional filename for the upload
39734
+ * @returns The upload result with URL and metadata
38757
39735
  */
38758
39736
  async upload(file, filename) {
38759
39737
  try {
38760
- const formData = new FormData();
38761
- formData.append("file", file);
38762
- if (filename) {
38763
- formData.append("name", filename);
38764
- }
38765
- const response = await fetch(this.config.uploadUrl, {
38766
- method: "POST",
38767
- body: formData
38768
- });
38769
- if (!response.ok) {
38770
- const _errorText = await response.text();
38771
- throw new StorageError(
38772
- `Server upload failed: ${response.status} ${response.statusText}`,
38773
- "UPLOAD_FAILED",
38774
- "server-proxy"
38775
- );
38776
- }
38777
- const result = await response.json();
38778
- if (!result.success) {
39738
+ const result = await this.callbacks.upload(file, filename);
39739
+ if (!result.url || result.url.trim() === "") {
38779
39740
  throw new StorageError(
38780
- `Upload failed: ${result.error || "Unknown server error"}`,
38781
- "UPLOAD_FAILED",
38782
- "server-proxy"
39741
+ "Upload callback returned invalid result: missing or empty url",
39742
+ "INVALID_UPLOAD_RESULT",
39743
+ "callback-storage"
38783
39744
  );
38784
39745
  }
38785
- if (!result.identifier) {
38786
- throw new StorageError(
38787
- "Server upload succeeded but no identifier returned",
38788
- "NO_IDENTIFIER_RETURNED",
38789
- "server-proxy"
38790
- );
38791
- }
38792
- return {
38793
- url: result.url || result.identifier,
38794
- size: file.size,
38795
- contentType: file.type || "application/octet-stream"
38796
- };
39746
+ return result;
38797
39747
  } catch (error) {
38798
39748
  if (error instanceof StorageError) {
38799
39749
  throw error;
38800
39750
  }
38801
39751
  throw new StorageError(
38802
- `Server proxy upload error: ${error instanceof Error ? error.message : "Unknown error"}`,
39752
+ `Upload failed: ${error instanceof Error ? error.message : String(error)}`,
38803
39753
  "UPLOAD_ERROR",
38804
- "server-proxy"
39754
+ "callback-storage",
39755
+ { cause: error instanceof Error ? error : void 0 }
38805
39756
  );
38806
39757
  }
38807
39758
  }
38808
39759
  /**
38809
- * Downloads a file through your server endpoint
38810
- *
38811
- * @remarks
38812
- * This method sends the identifier to your configured download endpoint via POST request.
38813
- * Your server is responsible for retrieving the file from your storage backend
38814
- * and returning the file content as a blob response.
38815
- *
38816
- * @param url - The server-provided URL or identifier from upload
38817
- * @returns Promise that resolves to the downloaded file content
38818
- * @throws {StorageError} When the download fails or file is not found
39760
+ * Download a file using the provided callback
38819
39761
  *
38820
- * @example
38821
- * ```typescript
38822
- * const fileBlob = await serverStorage.download("file-123");
38823
- * const url = URL.createObjectURL(fileBlob);
38824
- * ```
39762
+ * @param url - The URL or identifier to download
39763
+ * @returns The downloaded blob
38825
39764
  */
38826
39765
  async download(url) {
38827
39766
  try {
38828
- const identifier = this.extractIdentifierFromUrl(url);
38829
- const response = await fetch(this.config.downloadUrl, {
38830
- method: "POST",
38831
- headers: {
38832
- "Content-Type": "application/json"
38833
- },
38834
- body: JSON.stringify({ identifier })
38835
- });
38836
- if (!response.ok) {
38837
- const _errorText = await response.text();
39767
+ const identifier = this.callbacks.extractIdentifier ? this.callbacks.extractIdentifier(url) : url;
39768
+ const blob = await this.callbacks.download(identifier);
39769
+ if (!(blob instanceof Blob)) {
38838
39770
  throw new StorageError(
38839
- `Server download failed: ${response.status} ${response.statusText}`,
38840
- "DOWNLOAD_FAILED",
38841
- "server-proxy"
39771
+ "Download callback returned invalid result: expected Blob",
39772
+ "INVALID_DOWNLOAD_RESULT",
39773
+ "callback-storage"
38842
39774
  );
38843
39775
  }
38844
- return await response.blob();
39776
+ return blob;
38845
39777
  } catch (error) {
38846
39778
  if (error instanceof StorageError) {
38847
39779
  throw error;
38848
39780
  }
38849
39781
  throw new StorageError(
38850
- `Server proxy download error: ${error instanceof Error ? error.message : "Unknown error"}`,
39782
+ `Download failed: ${error instanceof Error ? error.message : String(error)}`,
38851
39783
  "DOWNLOAD_ERROR",
38852
- "server-proxy"
39784
+ "callback-storage",
39785
+ { cause: error instanceof Error ? error : void 0 }
38853
39786
  );
38854
39787
  }
38855
39788
  }
38856
- async list(_options) {
38857
- throw new StorageError(
38858
- "List operation is not supported by server proxy storage",
38859
- "LIST_NOT_SUPPORTED",
38860
- "server-proxy"
38861
- );
38862
- }
38863
- async delete(_url) {
38864
- throw new StorageError(
38865
- "Delete operation is not supported by server proxy storage",
38866
- "DELETE_NOT_SUPPORTED",
38867
- "server-proxy"
38868
- );
39789
+ /**
39790
+ * List files using the provided callback (if available)
39791
+ *
39792
+ * @param options - Optional list options including filters and pagination
39793
+ * @returns Array of storage files
39794
+ */
39795
+ async list(options) {
39796
+ if (!this.callbacks.list) {
39797
+ throw new StorageError(
39798
+ "List operation not supported - no list callback provided",
39799
+ "NOT_SUPPORTED",
39800
+ "callback-storage"
39801
+ );
39802
+ }
39803
+ try {
39804
+ const result = await this.callbacks.list(options?.namePattern, options);
39805
+ return result.items.map((item, index) => ({
39806
+ id: item.identifier,
39807
+ name: item.identifier.split("/").pop() || `file-${index}`,
39808
+ url: item.identifier,
39809
+ size: item.size || 0,
39810
+ contentType: "application/octet-stream",
39811
+ createdAt: item.lastModified || /* @__PURE__ */ new Date(),
39812
+ metadata: item.metadata
39813
+ }));
39814
+ } catch (error) {
39815
+ throw new StorageError(
39816
+ `List failed: ${error instanceof Error ? error.message : String(error)}`,
39817
+ "LIST_ERROR",
39818
+ "callback-storage",
39819
+ { cause: error instanceof Error ? error : void 0 }
39820
+ );
39821
+ }
38869
39822
  }
38870
39823
  /**
38871
- * Extract identifier from URL or return as-is
39824
+ * Delete a file using the provided callback (if available)
38872
39825
  *
38873
- * @param url - URL or identifier string
38874
- * @returns identifier string
39826
+ * @param url - The URL or identifier to delete
39827
+ * @returns True if deletion succeeded
38875
39828
  */
38876
- extractIdentifierFromUrl(url) {
38877
- return url;
39829
+ async delete(url) {
39830
+ if (!this.callbacks.delete) {
39831
+ throw new StorageError(
39832
+ "Delete operation not supported - no delete callback provided",
39833
+ "NOT_SUPPORTED",
39834
+ "callback-storage"
39835
+ );
39836
+ }
39837
+ try {
39838
+ const identifier = this.callbacks.extractIdentifier ? this.callbacks.extractIdentifier(url) : url;
39839
+ return await this.callbacks.delete(identifier);
39840
+ } catch (error) {
39841
+ throw new StorageError(
39842
+ `Delete failed: ${error instanceof Error ? error.message : String(error)}`,
39843
+ "DELETE_ERROR",
39844
+ "callback-storage",
39845
+ { cause: error instanceof Error ? error : void 0 }
39846
+ );
39847
+ }
38878
39848
  }
39849
+ /**
39850
+ * Get provider configuration
39851
+ *
39852
+ * @returns Provider configuration metadata
39853
+ */
38879
39854
  getConfig() {
38880
39855
  return {
38881
- name: "Server Proxy",
38882
- type: "server-proxy",
39856
+ name: "callback-storage",
39857
+ type: "callback",
38883
39858
  requiresAuth: false,
38884
39859
  features: {
38885
39860
  upload: true,
38886
39861
  download: true,
38887
- list: false,
38888
- delete: false
39862
+ list: !!this.callbacks.list,
39863
+ delete: !!this.callbacks.delete
38889
39864
  }
38890
39865
  };
38891
39866
  }
@@ -39099,7 +40074,7 @@ var moksha = {
39099
40074
  url: "https://moksha.vanascan.io"
39100
40075
  }
39101
40076
  },
39102
- subgraphUrl: "https://api.goldsky.com/api/public/project_cm168cz887zva010j39il7a6p/subgraphs/moksha/7.0.4/gn"
40077
+ subgraphUrl: "https://api.goldsky.com/api/public/project_cm168cz887zva010j39il7a6p/subgraphs/moksha/7.0.3/gn"
39103
40078
  };
39104
40079
  function getChainConfig(chainId) {
39105
40080
  switch (chainId) {
@@ -39111,11 +40086,53 @@ function getChainConfig(chainId) {
39111
40086
  return void 0;
39112
40087
  }
39113
40088
  }
40089
+ var mokshaTestnet2 = moksha;
39114
40090
  function getAllChains() {
39115
40091
  return [vanaMainnet2, moksha];
39116
40092
  }
39117
40093
 
39118
40094
  // src/core.ts
40095
+ var VanaCoreFactory = class {
40096
+ /**
40097
+ * Creates a VanaCore instance that enforces storage requirements at compile time.
40098
+ * Use this factory when you know you'll need storage-dependent operations.
40099
+ *
40100
+ * @param platform - The platform adapter for environment-specific operations
40101
+ * @param config - Configuration that includes required storage providers
40102
+ * @returns VanaCore instance with storage validation
40103
+ * @example
40104
+ * ```typescript
40105
+ * const vanaCore = VanaCoreFactory.createWithStorage(platformAdapter, {
40106
+ * walletClient: myWalletClient,
40107
+ * storage: {
40108
+ * providers: { ipfs: new IPFSStorage() },
40109
+ * defaultProvider: 'ipfs'
40110
+ * }
40111
+ * });
40112
+ * ```
40113
+ */
40114
+ static createWithStorage(platform, config) {
40115
+ const core = new VanaCore(platform, config);
40116
+ return core;
40117
+ }
40118
+ /**
40119
+ * Creates a VanaCore instance without storage requirements.
40120
+ * Storage-dependent operations will fail at runtime if not configured.
40121
+ *
40122
+ * @param platform - The platform adapter for environment-specific operations
40123
+ * @param config - Basic configuration without required storage
40124
+ * @returns VanaCore instance
40125
+ * @example
40126
+ * ```typescript
40127
+ * const vanaCore = VanaCoreFactory.create(platformAdapter, {
40128
+ * walletClient: myWalletClient
40129
+ * });
40130
+ * ```
40131
+ */
40132
+ static create(platform, config) {
40133
+ return new VanaCore(platform, config);
40134
+ }
40135
+ };
39119
40136
  var VanaCore = class {
39120
40137
  /**
39121
40138
  * Initializes a new VanaCore client instance with the provided configuration.
@@ -39123,6 +40140,10 @@ var VanaCore = class {
39123
40140
  * @remarks
39124
40141
  * The constructor validates the configuration, initializes storage providers if configured,
39125
40142
  * creates wallet and public clients, and sets up all SDK controllers with shared context.
40143
+ *
40144
+ * IMPORTANT: This constructor will validate storage requirements at runtime to fail fast.
40145
+ * Methods that require storage will throw runtime errors if storage is not configured.
40146
+ *
39126
40147
  * @param platform - The platform adapter for environment-specific operations
39127
40148
  * @param config - The configuration object specifying wallet or chain settings
39128
40149
  * @throws {InvalidConfigurationError} When the configuration is invalid or incomplete
@@ -39137,8 +40158,10 @@ var VanaCore = class {
39137
40158
  constructor(platform, config) {
39138
40159
  /** Manages gasless data access permissions and trusted server registry. */
39139
40160
  __publicField(this, "permissions");
39140
- /** Handles user data file operations and schema management. */
40161
+ /** Handles user data file operations. */
39141
40162
  __publicField(this, "data");
40163
+ /** Manages data schemas and refiners. */
40164
+ __publicField(this, "schemas");
39142
40165
  /** Provides personal server setup and trusted server interactions. */
39143
40166
  __publicField(this, "server");
39144
40167
  /** Offers low-level access to Vana protocol smart contracts. */
@@ -39147,9 +40170,13 @@ var VanaCore = class {
39147
40170
  __publicField(this, "platform");
39148
40171
  __publicField(this, "relayerCallbacks");
39149
40172
  __publicField(this, "storageManager");
40173
+ __publicField(this, "hasRequiredStorage");
40174
+ __publicField(this, "ipfsGateways");
39150
40175
  this.platform = platform;
39151
40176
  this.validateConfig(config);
39152
40177
  this.relayerCallbacks = config.relayerCallbacks;
40178
+ this.ipfsGateways = config.ipfsGateways;
40179
+ this.hasRequiredStorage = hasStorageConfig(config);
39153
40180
  if (config.storage?.providers) {
39154
40181
  this.storageManager = new StorageManager();
39155
40182
  for (const [name, provider] of Object.entries(config.storage.providers)) {
@@ -39204,14 +40231,70 @@ var VanaCore = class {
39204
40231
  relayerCallbacks: this.relayerCallbacks,
39205
40232
  storageManager: this.storageManager,
39206
40233
  subgraphUrl,
39207
- platform: this.platform
40234
+ platform: this.platform,
39208
40235
  // Pass the platform adapter to controllers
40236
+ validateStorageRequired: this.validateStorageRequired.bind(this),
40237
+ hasStorage: this.hasStorage.bind(this),
40238
+ ipfsGateways: this.ipfsGateways
39209
40239
  };
39210
40240
  this.permissions = new PermissionsController(sharedContext);
39211
40241
  this.data = new DataController(sharedContext);
40242
+ this.schemas = new SchemaController(sharedContext);
39212
40243
  this.server = new ServerController(sharedContext);
39213
40244
  this.protocol = new ProtocolController(sharedContext);
39214
40245
  }
40246
+ /**
40247
+ * Validates that storage is available for storage-dependent operations.
40248
+ * This method enforces the fail-fast principle by checking storage availability
40249
+ * at method call time rather than during expensive operations.
40250
+ *
40251
+ * @throws {InvalidConfigurationError} When storage is required but not configured
40252
+ * @example
40253
+ * ```typescript
40254
+ * // This will throw if storage is not configured
40255
+ * vana.validateStorageRequired();
40256
+ * await vana.data.uploadFile(file); // Safe to proceed
40257
+ * ```
40258
+ */
40259
+ validateStorageRequired() {
40260
+ if (!this.hasRequiredStorage) {
40261
+ throw new InvalidConfigurationError(
40262
+ "Storage configuration is required for this operation. Please configure storage providers in VanaConfig.storage, provide a relayerCallbacks.storeGrantFile implementation, or pass pre-stored URLs to avoid this dependency. \n\nFor better type safety, consider using VanaCoreFactory.createWithStorage() with VanaConfigWithStorage to catch this error at compile time."
40263
+ );
40264
+ }
40265
+ }
40266
+ /**
40267
+ * Checks whether storage is configured without throwing an error.
40268
+ *
40269
+ * @returns True if storage is properly configured
40270
+ * @example
40271
+ * ```typescript
40272
+ * if (vana.hasStorage()) {
40273
+ * await vana.data.uploadFile(file);
40274
+ * } else {
40275
+ * console.warn('Storage not configured - using pre-stored URLs only');
40276
+ * }
40277
+ * ```
40278
+ */
40279
+ hasStorage() {
40280
+ return this.hasRequiredStorage;
40281
+ }
40282
+ /**
40283
+ * Type guard to check if this instance has storage enabled at compile time.
40284
+ * Use this when you need TypeScript to understand that storage is available.
40285
+ *
40286
+ * @returns True if storage is configured, with type narrowing
40287
+ * @example
40288
+ * ```typescript
40289
+ * if (vana.isStorageEnabled()) {
40290
+ * // TypeScript knows storage is available here
40291
+ * await vana.data.uploadFile(file);
40292
+ * }
40293
+ * ```
40294
+ */
40295
+ isStorageEnabled() {
40296
+ return this.hasRequiredStorage;
40297
+ }
39215
40298
  /**
39216
40299
  * Validates the provided configuration object against all requirements.
39217
40300
  *
@@ -39400,37 +40483,97 @@ var VanaCore = class {
39400
40483
  return this.platform;
39401
40484
  }
39402
40485
  /**
39403
- * Encrypts user data using the Vana protocol standard encryption.
39404
- * This method automatically uses the correct platform adapter for the current environment.
40486
+ * Encrypts data using the Vana protocol standard encryption.
40487
+ *
40488
+ * @remarks
40489
+ * This method implements the Vana network's standard encryption protocol using
40490
+ * platform-appropriate cryptographic libraries. It automatically handles different
40491
+ * input types (string or Blob) and produces encrypted output suitable for secure
40492
+ * storage or transmission. The encryption is compatible with the network's
40493
+ * decryption protocols and can be decrypted by authorized parties.
39405
40494
  *
39406
- * @param data The data to encrypt (string or Blob)
39407
- * @param walletSignature The wallet signature to use as encryption key
39408
- * @returns The encrypted data as Blob
40495
+ * @param data - The data to encrypt (string or Blob)
40496
+ * @param key - The encryption key (typically generated via `generateEncryptionKey`)
40497
+ * @returns The encrypted data as a Blob
40498
+ * @throws {Error} When encryption fails due to invalid key or data format
39409
40499
  * @example
39410
40500
  * ```typescript
39411
- * const encryptionKey = await generateEncryptionKey(walletClient);
39412
- * const encrypted = await vana.encryptUserData("sensitive data", encryptionKey);
40501
+ * import { generateEncryptionKey } from '@opendatalabs/vana-sdk/node';
40502
+ *
40503
+ * // Generate encryption key from wallet signature
40504
+ * const encryptionKey = await generateEncryptionKey(vana.walletClient);
40505
+ *
40506
+ * // Encrypt string data
40507
+ * const sensitiveData = "User's private information";
40508
+ * const encrypted = await vana.encryptBlob(sensitiveData, encryptionKey);
40509
+ *
40510
+ * // Encrypt file data
40511
+ * const fileBlob = new Blob([fileContent], { type: 'application/json' });
40512
+ * const encryptedFile = await vana.encryptBlob(fileBlob, encryptionKey);
40513
+ *
40514
+ * // Store encrypted data safely
40515
+ * await storageProvider.upload(encrypted, 'encrypted-data.bin');
39413
40516
  * ```
39414
40517
  */
39415
- async encryptUserData(data, walletSignature) {
39416
- return encryptUserData(data, walletSignature, this.platform);
40518
+ async encryptBlob(data, key) {
40519
+ return encryptBlobWithSignedKey(data, key, this.platform);
39417
40520
  }
39418
40521
  /**
39419
- * Decrypts user data using the Vana protocol standard decryption.
39420
- * This method automatically uses the correct platform adapter for the current environment.
40522
+ * Decrypts data that was encrypted using the Vana protocol.
40523
+ *
40524
+ * @remarks
40525
+ * This method decrypts data that was previously encrypted using the Vana network's
40526
+ * standard encryption protocol. It requires the same wallet signature that was used
40527
+ * for encryption and automatically uses the appropriate platform adapter for
40528
+ * cryptographic operations. The decrypted output maintains the original data format.
39421
40529
  *
39422
- * @param encryptedData The encrypted data (string or Blob)
39423
- * @param walletSignature The wallet signature to use as decryption key
39424
- * @returns The decrypted data as Blob
40530
+ * @param encryptedData - The encrypted data (string or Blob)
40531
+ * @param walletSignature - The wallet signature used as decryption key
40532
+ * @returns The decrypted data as a Blob
40533
+ * @throws {Error} When decryption fails due to invalid signature or corrupted data
39425
40534
  * @example
39426
40535
  * ```typescript
39427
- * const encryptionKey = await generateEncryptionKey(walletClient);
39428
- * const decrypted = await vana.decryptUserData(encryptedData, encryptionKey);
39429
- * const text = await decrypted.text();
40536
+ * import { generateEncryptionKey } from '@opendatalabs/vana-sdk/node';
40537
+ *
40538
+ * // Retrieve encrypted data from storage
40539
+ * const encryptedBlob = await storageProvider.download('encrypted-data.bin');
40540
+ *
40541
+ * // Generate the same key used for encryption
40542
+ * const decryptionKey = await generateEncryptionKey(vana.walletClient);
40543
+ *
40544
+ * // Decrypt the data
40545
+ * const decrypted = await vana.decryptBlob(encryptedBlob, decryptionKey);
40546
+ *
40547
+ * // Convert back to original format
40548
+ * const originalText = await decrypted.text();
40549
+ * const originalJson = JSON.parse(originalText);
40550
+ *
40551
+ * console.log('Decrypted data:', originalJson);
40552
+ * ```
40553
+ *
40554
+ * @example
40555
+ * ```typescript
40556
+ * // Decrypt file downloaded from Vana network
40557
+ * const userFiles = await vana.data.getUserFiles();
40558
+ * const file = userFiles[0];
40559
+ *
40560
+ * // Download encrypted content
40561
+ * const encrypted = await fetch(file.url).then(r => r.blob());
40562
+ *
40563
+ * // Decrypt with user's key
40564
+ * const decryptionKey = await generateEncryptionKey(vana.walletClient);
40565
+ * const decrypted = await vana.decryptBlob(encrypted, decryptionKey);
40566
+ *
40567
+ * // Process original data
40568
+ * const fileContent = await decrypted.arrayBuffer();
39430
40569
  * ```
39431
40570
  */
39432
- async decryptUserData(encryptedData, walletSignature) {
39433
- return decryptUserData(encryptedData, walletSignature, this.platform);
40571
+ async decryptBlob(encryptedData, walletSignature) {
40572
+ return decryptBlobWithSignedKey(
40573
+ encryptedData,
40574
+ walletSignature,
40575
+ this.platform
40576
+ );
39434
40577
  }
39435
40578
  };
39436
40579
 
@@ -39461,7 +40604,7 @@ function createValidatedGrant(params) {
39461
40604
  try {
39462
40605
  validateGrant(grantFile, {
39463
40606
  schema: true,
39464
- grantee: params.to,
40607
+ grantee: params.grantee,
39465
40608
  operation: params.operation
39466
40609
  });
39467
40610
  } catch (error) {
@@ -40218,31 +41361,22 @@ var ApiClient = class {
40218
41361
  };
40219
41362
 
40220
41363
  // src/index.browser.ts
40221
- var VanaBrowser = class extends VanaCore {
40222
- /**
40223
- * Creates a Vana SDK instance configured for browser environments.
40224
- *
40225
- * @param config - SDK configuration object (wallet client or chain config)
40226
- * @example
40227
- * ```typescript
40228
- * // With wallet client
40229
- * const vana = new Vana({ walletClient });
40230
- *
40231
- * // With chain configuration
40232
- * const vana = new Vana({ chainId: 14800, account });
40233
- * ```
40234
- */
41364
+ var VanaBrowserImpl = class extends VanaCore {
40235
41365
  constructor(config) {
40236
41366
  super(new BrowserPlatformAdapter(), config);
40237
41367
  }
40238
41368
  };
40239
- var index_browser_default = VanaBrowser;
41369
+ function Vana(config) {
41370
+ return new VanaBrowserImpl(config);
41371
+ }
41372
+ var index_browser_default = Vana;
40240
41373
  export {
40241
41374
  ApiClient,
40242
41375
  AsyncQueue,
40243
41376
  BaseController,
40244
41377
  BlockchainError,
40245
41378
  BrowserPlatformAdapter,
41379
+ CallbackStorage,
40246
41380
  CircuitBreaker,
40247
41381
  ContractFactory,
40248
41382
  ContractNotFoundError,
@@ -40275,14 +41409,16 @@ export {
40275
41409
  SchemaValidator,
40276
41410
  SerializationError,
40277
41411
  ServerController,
40278
- ServerProxyStorage,
40279
41412
  ServerUrlMismatchError,
41413
+ SignatureCache,
40280
41414
  SignatureError,
40281
41415
  StorageError,
40282
41416
  StorageManager,
40283
41417
  UserRejectedRequestError,
40284
- VanaBrowser as Vana,
40285
- VanaBrowser,
41418
+ Vana,
41419
+ VanaBrowserImpl,
41420
+ VanaCore,
41421
+ VanaCoreFactory,
40286
41422
  VanaError,
40287
41423
  __contractCache,
40288
41424
  chains,
@@ -40295,13 +41431,13 @@ export {
40295
41431
  createGrantFile,
40296
41432
  createPlatformAdapterSafe,
40297
41433
  createValidatedGrant,
40298
- decryptUserData,
41434
+ decryptBlobWithSignedKey,
40299
41435
  decryptWithPrivateKey,
40300
41436
  decryptWithWalletPrivateKey,
40301
41437
  index_browser_default as default,
40302
41438
  detectPlatform,
41439
+ encryptBlobWithSignedKey,
40303
41440
  encryptFileKey,
40304
- encryptUserData,
40305
41441
  encryptWithWalletPublicKey,
40306
41442
  extractIpfsHash,
40307
41443
  fetchAndValidateSchema,
@@ -40325,13 +41461,11 @@ export {
40325
41461
  getPlatformCapabilities,
40326
41462
  isAPIResponse,
40327
41463
  isGrantExpired,
40328
- isIdentityServerOutput,
40329
41464
  isIpfsUrl,
40330
- isPersonalServerOutput,
40331
41465
  isPlatformSupported,
40332
41466
  isReplicateAPIResponse,
40333
41467
  moksha,
40334
- mokshaTestnet,
41468
+ mokshaTestnet2 as mokshaTestnet,
40335
41469
  parseReplicateOutput,
40336
41470
  retrieveAndValidateGrant,
40337
41471
  retrieveGrantFile,
@@ -40347,6 +41481,7 @@ export {
40347
41481
  validateGrantFile,
40348
41482
  validateGranteeAccess,
40349
41483
  validateOperationAccess,
40350
- vanaMainnet
41484
+ vanaMainnet2 as vanaMainnet,
41485
+ withSignatureCache
40351
41486
  };
40352
41487
  //# sourceMappingURL=index.browser.js.map