@opendatalabs/vana-sdk 0.1.0-alpha.e64ec83 → 0.1.0-alpha.f05a34e
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.
- package/README.md +189 -425
- package/dist/chains.browser.cjs +4 -1
- package/dist/chains.browser.cjs.map +1 -1
- package/dist/chains.browser.d.cts +2 -1
- package/dist/chains.browser.d.ts +2 -1
- package/dist/chains.browser.js +3 -1
- package/dist/chains.browser.js.map +1 -1
- package/dist/chains.cjs +4 -1
- package/dist/chains.cjs.map +1 -1
- package/dist/chains.d.cts +1 -1
- package/dist/chains.d.ts +1 -1
- package/dist/chains.js +3 -1
- package/dist/chains.js.map +1 -1
- package/dist/chains.node.cjs +4 -1
- package/dist/chains.node.cjs.map +1 -1
- package/dist/chains.node.d.cts +1 -1
- package/dist/chains.node.d.ts +1 -1
- package/dist/chains.node.js +3 -1
- package/dist/chains.node.js.map +1 -1
- package/dist/index.browser.d.ts +3883 -2669
- package/dist/index.browser.js +1412 -1094
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.cts +1 -31277
- package/dist/index.node.cjs +1448 -1131
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.d.cts +3885 -2671
- package/dist/index.node.d.ts +3885 -2671
- package/dist/index.node.js +1427 -1110
- package/dist/index.node.js.map +1 -1
- package/dist/platform.browser.js +32 -181
- package/dist/platform.browser.js.map +1 -1
- package/dist/platform.cjs +47 -197
- package/dist/platform.cjs.map +1 -1
- package/dist/platform.js +47 -197
- package/dist/platform.js.map +1 -1
- package/dist/platform.node.cjs +47 -197
- package/dist/platform.node.cjs.map +1 -1
- package/dist/platform.node.js +47 -197
- package/dist/platform.node.js.map +1 -1
- package/package.json +24 -18
package/dist/index.node.cjs
CHANGED
|
@@ -49,11 +49,6 @@ function parseEncryptedDataBuffer(encryptedBuffer) {
|
|
|
49
49
|
mac: encryptedBuffer.slice(-32)
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
function uint8ArrayToHex(array) {
|
|
53
|
-
return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
54
|
-
""
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
52
|
var init_crypto_utils = __esm({
|
|
58
53
|
"src/platform/shared/crypto-utils.ts"() {
|
|
59
54
|
"use strict";
|
|
@@ -215,14 +210,7 @@ __export(browser_exports, {
|
|
|
215
210
|
BrowserPlatformAdapter: () => BrowserPlatformAdapter,
|
|
216
211
|
browserPlatformAdapter: () => browserPlatformAdapter
|
|
217
212
|
});
|
|
218
|
-
|
|
219
|
-
const result = new Uint8Array(hex.length / 2);
|
|
220
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
221
|
-
result[i / 2] = parseInt(hex.substr(i, 2), 16);
|
|
222
|
-
}
|
|
223
|
-
return result;
|
|
224
|
-
}
|
|
225
|
-
var openpgp2, BrowserECDH, BrowserCryptoAdapter, BrowserPGPAdapter, BrowserHttpAdapter, BrowserPlatformAdapter, browserPlatformAdapter;
|
|
213
|
+
var openpgp2, BrowserCryptoAdapter, BrowserPGPAdapter, BrowserHttpAdapter, BrowserPlatformAdapter, browserPlatformAdapter;
|
|
226
214
|
var init_browser = __esm({
|
|
227
215
|
"src/platform/browser.ts"() {
|
|
228
216
|
"use strict";
|
|
@@ -230,133 +218,52 @@ var init_browser = __esm({
|
|
|
230
218
|
init_crypto_utils();
|
|
231
219
|
init_pgp_utils();
|
|
232
220
|
init_error_utils();
|
|
233
|
-
BrowserECDH = class {
|
|
234
|
-
async generateKeyPair() {
|
|
235
|
-
const keyPair = await crypto.subtle.generateKey(
|
|
236
|
-
{
|
|
237
|
-
name: "ECDH",
|
|
238
|
-
namedCurve: "P-256"
|
|
239
|
-
},
|
|
240
|
-
true,
|
|
241
|
-
["deriveKey", "deriveBits"]
|
|
242
|
-
);
|
|
243
|
-
return keyPair;
|
|
244
|
-
}
|
|
245
|
-
async encrypt(publicKeyHex, message) {
|
|
246
|
-
const ephemeralKeyPair = await this.generateKeyPair();
|
|
247
|
-
const publicKeyData = hexToUint8Array(publicKeyHex);
|
|
248
|
-
const importedPublicKey = await crypto.subtle.importKey(
|
|
249
|
-
"raw",
|
|
250
|
-
publicKeyData,
|
|
251
|
-
{ name: "ECDH", namedCurve: "P-256" },
|
|
252
|
-
false,
|
|
253
|
-
[]
|
|
254
|
-
);
|
|
255
|
-
const sharedKey = await crypto.subtle.deriveKey(
|
|
256
|
-
{ name: "ECDH", public: importedPublicKey },
|
|
257
|
-
ephemeralKeyPair.privateKey,
|
|
258
|
-
{ name: "AES-GCM", length: 256 },
|
|
259
|
-
false,
|
|
260
|
-
["encrypt"]
|
|
261
|
-
);
|
|
262
|
-
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
263
|
-
const encoder = new TextEncoder();
|
|
264
|
-
const data = encoder.encode(message);
|
|
265
|
-
const encrypted = await crypto.subtle.encrypt(
|
|
266
|
-
{ name: "AES-GCM", iv },
|
|
267
|
-
sharedKey,
|
|
268
|
-
data
|
|
269
|
-
);
|
|
270
|
-
const ephemeralPublicKeyData = await crypto.subtle.exportKey(
|
|
271
|
-
"raw",
|
|
272
|
-
ephemeralKeyPair.publicKey
|
|
273
|
-
);
|
|
274
|
-
return JSON.stringify({
|
|
275
|
-
encrypted: Array.from(new Uint8Array(encrypted)),
|
|
276
|
-
iv: Array.from(iv),
|
|
277
|
-
ephemeralPublicKey: Array.from(new Uint8Array(ephemeralPublicKeyData)),
|
|
278
|
-
publicKey: publicKeyHex
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
async decrypt(privateKeyHex, encryptedData) {
|
|
282
|
-
try {
|
|
283
|
-
const data = JSON.parse(encryptedData);
|
|
284
|
-
if (!data.encrypted || !data.iv || !data.ephemeralPublicKey) {
|
|
285
|
-
throw new Error("Invalid encrypted data format");
|
|
286
|
-
}
|
|
287
|
-
const privateKeyData = hexToUint8Array(privateKeyHex);
|
|
288
|
-
const importedPrivateKey = await crypto.subtle.importKey(
|
|
289
|
-
"pkcs8",
|
|
290
|
-
privateKeyData,
|
|
291
|
-
{ name: "ECDH", namedCurve: "P-256" },
|
|
292
|
-
false,
|
|
293
|
-
["deriveKey"]
|
|
294
|
-
);
|
|
295
|
-
const ephemeralPublicKey = await crypto.subtle.importKey(
|
|
296
|
-
"raw",
|
|
297
|
-
new Uint8Array(data.ephemeralPublicKey),
|
|
298
|
-
{ name: "ECDH", namedCurve: "P-256" },
|
|
299
|
-
false,
|
|
300
|
-
[]
|
|
301
|
-
);
|
|
302
|
-
const sharedKey = await crypto.subtle.deriveKey(
|
|
303
|
-
{ name: "ECDH", public: ephemeralPublicKey },
|
|
304
|
-
importedPrivateKey,
|
|
305
|
-
{ name: "AES-GCM", length: 256 },
|
|
306
|
-
false,
|
|
307
|
-
["decrypt"]
|
|
308
|
-
);
|
|
309
|
-
const decrypted = await crypto.subtle.decrypt(
|
|
310
|
-
{ name: "AES-GCM", iv: new Uint8Array(data.iv) },
|
|
311
|
-
sharedKey,
|
|
312
|
-
new Uint8Array(data.encrypted)
|
|
313
|
-
);
|
|
314
|
-
return new TextDecoder().decode(decrypted);
|
|
315
|
-
} catch (error) {
|
|
316
|
-
throw new Error(
|
|
317
|
-
`Decryption failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
221
|
BrowserCryptoAdapter = class {
|
|
323
222
|
async encryptWithPublicKey(data, publicKeyHex) {
|
|
324
223
|
try {
|
|
325
|
-
const
|
|
326
|
-
|
|
224
|
+
const eccrypto2 = await import("eccrypto-js");
|
|
225
|
+
const publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
|
|
226
|
+
const encrypted = await eccrypto2.encrypt(
|
|
227
|
+
publicKeyBuffer,
|
|
228
|
+
Buffer.from(data, "utf8")
|
|
229
|
+
);
|
|
230
|
+
const result = Buffer.concat([
|
|
231
|
+
encrypted.iv,
|
|
232
|
+
encrypted.ephemPublicKey,
|
|
233
|
+
encrypted.ciphertext,
|
|
234
|
+
encrypted.mac
|
|
235
|
+
]);
|
|
236
|
+
return result.toString("hex");
|
|
327
237
|
} catch (error) {
|
|
328
238
|
throw new Error(`Encryption failed: ${error}`);
|
|
329
239
|
}
|
|
330
240
|
}
|
|
331
241
|
async decryptWithPrivateKey(encryptedData, privateKeyHex) {
|
|
332
242
|
try {
|
|
333
|
-
const
|
|
334
|
-
|
|
243
|
+
const eccrypto2 = await import("eccrypto-js");
|
|
244
|
+
const privateKeyBuffer = processWalletPrivateKey(privateKeyHex);
|
|
245
|
+
const encryptedBuffer = Buffer.from(encryptedData, "hex");
|
|
246
|
+
const { iv, ephemPublicKey, ciphertext, mac } = parseEncryptedDataBuffer(encryptedBuffer);
|
|
247
|
+
const encryptedObj = { iv, ephemPublicKey, ciphertext, mac };
|
|
248
|
+
const decryptedBuffer = await eccrypto2.decrypt(
|
|
249
|
+
privateKeyBuffer,
|
|
250
|
+
encryptedObj
|
|
251
|
+
);
|
|
252
|
+
return decryptedBuffer.toString("utf8");
|
|
335
253
|
} catch (error) {
|
|
336
254
|
throw new Error(`Decryption failed: ${error}`);
|
|
337
255
|
}
|
|
338
256
|
}
|
|
339
257
|
async generateKeyPair() {
|
|
340
258
|
try {
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
true,
|
|
347
|
-
["deriveKey", "deriveBits"]
|
|
348
|
-
);
|
|
349
|
-
const publicKeyBuffer = await crypto.subtle.exportKey(
|
|
350
|
-
"raw",
|
|
351
|
-
keyPair.publicKey
|
|
352
|
-
);
|
|
353
|
-
const privateKeyBuffer = await crypto.subtle.exportKey(
|
|
354
|
-
"pkcs8",
|
|
355
|
-
keyPair.privateKey
|
|
356
|
-
);
|
|
259
|
+
const eccrypto2 = await import("eccrypto-js");
|
|
260
|
+
const privateKeyBytes = new Uint8Array(32);
|
|
261
|
+
crypto.getRandomValues(privateKeyBytes);
|
|
262
|
+
const privateKey = Buffer.from(privateKeyBytes);
|
|
263
|
+
const publicKey = eccrypto2.getPublicCompressed(privateKey);
|
|
357
264
|
return {
|
|
358
|
-
|
|
359
|
-
|
|
265
|
+
privateKey: privateKey.toString("hex"),
|
|
266
|
+
publicKey: publicKey.toString("hex")
|
|
360
267
|
};
|
|
361
268
|
} catch (error) {
|
|
362
269
|
throw wrapCryptoError("key generation", error);
|
|
@@ -366,65 +273,9 @@ var init_browser = __esm({
|
|
|
366
273
|
try {
|
|
367
274
|
const eccrypto2 = await import("eccrypto-js");
|
|
368
275
|
const uncompressedKey = processWalletPublicKey(publicKey);
|
|
369
|
-
const iv = Buffer.from([
|
|
370
|
-
1,
|
|
371
|
-
2,
|
|
372
|
-
3,
|
|
373
|
-
4,
|
|
374
|
-
5,
|
|
375
|
-
6,
|
|
376
|
-
7,
|
|
377
|
-
8,
|
|
378
|
-
9,
|
|
379
|
-
10,
|
|
380
|
-
11,
|
|
381
|
-
12,
|
|
382
|
-
13,
|
|
383
|
-
14,
|
|
384
|
-
15,
|
|
385
|
-
16
|
|
386
|
-
]);
|
|
387
|
-
const ephemeralKey = Buffer.from([
|
|
388
|
-
17,
|
|
389
|
-
34,
|
|
390
|
-
51,
|
|
391
|
-
68,
|
|
392
|
-
85,
|
|
393
|
-
102,
|
|
394
|
-
119,
|
|
395
|
-
136,
|
|
396
|
-
153,
|
|
397
|
-
170,
|
|
398
|
-
187,
|
|
399
|
-
204,
|
|
400
|
-
221,
|
|
401
|
-
238,
|
|
402
|
-
255,
|
|
403
|
-
0,
|
|
404
|
-
16,
|
|
405
|
-
32,
|
|
406
|
-
48,
|
|
407
|
-
64,
|
|
408
|
-
80,
|
|
409
|
-
96,
|
|
410
|
-
112,
|
|
411
|
-
128,
|
|
412
|
-
144,
|
|
413
|
-
160,
|
|
414
|
-
176,
|
|
415
|
-
192,
|
|
416
|
-
208,
|
|
417
|
-
224,
|
|
418
|
-
240,
|
|
419
|
-
0
|
|
420
|
-
]);
|
|
421
276
|
const encryptedBuffer = await eccrypto2.encrypt(
|
|
422
277
|
uncompressedKey,
|
|
423
|
-
Buffer.from(data)
|
|
424
|
-
{
|
|
425
|
-
iv,
|
|
426
|
-
ephemPrivateKey: ephemeralKey
|
|
427
|
-
}
|
|
278
|
+
Buffer.from(data)
|
|
428
279
|
);
|
|
429
280
|
const result = Buffer.concat([
|
|
430
281
|
encryptedBuffer.iv,
|
|
@@ -591,6 +442,7 @@ __export(index_node_exports, {
|
|
|
591
442
|
RateLimiter: () => RateLimiter,
|
|
592
443
|
RelayerError: () => RelayerError,
|
|
593
444
|
RetryUtility: () => RetryUtility,
|
|
445
|
+
SchemaController: () => SchemaController,
|
|
594
446
|
SchemaValidationError: () => SchemaValidationError,
|
|
595
447
|
SchemaValidator: () => SchemaValidator,
|
|
596
448
|
SerializationError: () => SerializationError,
|
|
@@ -601,10 +453,11 @@ __export(index_node_exports, {
|
|
|
601
453
|
StorageError: () => StorageError,
|
|
602
454
|
StorageManager: () => StorageManager,
|
|
603
455
|
UserRejectedRequestError: () => UserRejectedRequestError,
|
|
604
|
-
Vana: () =>
|
|
456
|
+
Vana: () => Vana,
|
|
605
457
|
VanaCore: () => VanaCore,
|
|
458
|
+
VanaCoreFactory: () => VanaCoreFactory,
|
|
606
459
|
VanaError: () => VanaError,
|
|
607
|
-
|
|
460
|
+
VanaNodeImpl: () => VanaNodeImpl,
|
|
608
461
|
__contractCache: () => __contractCache,
|
|
609
462
|
chains: () => chains,
|
|
610
463
|
checkGrantAccess: () => checkGrantAccess,
|
|
@@ -619,13 +472,13 @@ __export(index_node_exports, {
|
|
|
619
472
|
createPlatformAdapterFor: () => createPlatformAdapterFor,
|
|
620
473
|
createPlatformAdapterSafe: () => createPlatformAdapterSafe,
|
|
621
474
|
createValidatedGrant: () => createValidatedGrant,
|
|
622
|
-
|
|
475
|
+
decryptBlobWithSignedKey: () => decryptBlobWithSignedKey,
|
|
623
476
|
decryptWithPrivateKey: () => decryptWithPrivateKey,
|
|
624
477
|
decryptWithWalletPrivateKey: () => decryptWithWalletPrivateKey,
|
|
625
478
|
default: () => index_node_default,
|
|
626
479
|
detectPlatform: () => detectPlatform,
|
|
480
|
+
encryptBlobWithSignedKey: () => encryptBlobWithSignedKey,
|
|
627
481
|
encryptFileKey: () => encryptFileKey,
|
|
628
|
-
encryptUserData: () => encryptUserData,
|
|
629
482
|
encryptWithWalletPublicKey: () => encryptWithWalletPublicKey,
|
|
630
483
|
extractIpfsHash: () => extractIpfsHash,
|
|
631
484
|
fetchAndValidateSchema: () => fetchAndValidateSchema,
|
|
@@ -650,13 +503,11 @@ __export(index_node_exports, {
|
|
|
650
503
|
handleRelayerRequest: () => handleRelayerRequest,
|
|
651
504
|
isAPIResponse: () => isAPIResponse,
|
|
652
505
|
isGrantExpired: () => isGrantExpired,
|
|
653
|
-
isIdentityServerOutput: () => isIdentityServerOutput,
|
|
654
506
|
isIpfsUrl: () => isIpfsUrl,
|
|
655
|
-
isPersonalServerOutput: () => isPersonalServerOutput,
|
|
656
507
|
isPlatformSupported: () => isPlatformSupported,
|
|
657
508
|
isReplicateAPIResponse: () => isReplicateAPIResponse,
|
|
658
509
|
moksha: () => moksha,
|
|
659
|
-
mokshaTestnet: () =>
|
|
510
|
+
mokshaTestnet: () => mokshaTestnet2,
|
|
660
511
|
parseReplicateOutput: () => parseReplicateOutput,
|
|
661
512
|
retrieveAndValidateGrant: () => retrieveAndValidateGrant,
|
|
662
513
|
retrieveGrantFile: () => retrieveGrantFile,
|
|
@@ -672,7 +523,7 @@ __export(index_node_exports, {
|
|
|
672
523
|
validateGrantFile: () => validateGrantFile,
|
|
673
524
|
validateGranteeAccess: () => validateGranteeAccess,
|
|
674
525
|
validateOperationAccess: () => validateOperationAccess,
|
|
675
|
-
vanaMainnet: () =>
|
|
526
|
+
vanaMainnet: () => vanaMainnet2
|
|
676
527
|
});
|
|
677
528
|
module.exports = __toCommonJS(index_node_exports);
|
|
678
529
|
|
|
@@ -730,13 +581,13 @@ var NodeCryptoAdapter = class {
|
|
|
730
581
|
const publicKey = Buffer.from(publicKeyHex, "hex");
|
|
731
582
|
const message = Buffer.from(data, "utf8");
|
|
732
583
|
const encrypted = await eccryptoLib.encrypt(publicKey, message);
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
return
|
|
584
|
+
const result = Buffer.concat([
|
|
585
|
+
encrypted.iv,
|
|
586
|
+
encrypted.ephemPublicKey,
|
|
587
|
+
encrypted.ciphertext,
|
|
588
|
+
encrypted.mac
|
|
589
|
+
]);
|
|
590
|
+
return result.toString("hex");
|
|
740
591
|
} catch (error) {
|
|
741
592
|
throw new Error(`Encryption failed: ${error}`);
|
|
742
593
|
}
|
|
@@ -744,15 +595,14 @@ var NodeCryptoAdapter = class {
|
|
|
744
595
|
async decryptWithPrivateKey(encryptedData, privateKeyHex) {
|
|
745
596
|
try {
|
|
746
597
|
const eccryptoLib = await getEccrypto();
|
|
747
|
-
const
|
|
748
|
-
const
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
const decrypted = await eccryptoLib.decrypt(privateKey, encrypted);
|
|
598
|
+
const privateKeyBuffer = processWalletPrivateKey(privateKeyHex);
|
|
599
|
+
const encryptedBuffer = Buffer.from(encryptedData, "hex");
|
|
600
|
+
const { iv, ephemPublicKey, ciphertext, mac } = parseEncryptedDataBuffer(encryptedBuffer);
|
|
601
|
+
const encryptedObj = { iv, ephemPublicKey, ciphertext, mac };
|
|
602
|
+
const decrypted = await eccryptoLib.decrypt(
|
|
603
|
+
privateKeyBuffer,
|
|
604
|
+
encryptedObj
|
|
605
|
+
);
|
|
756
606
|
return decrypted.toString("utf8");
|
|
757
607
|
} catch (error) {
|
|
758
608
|
throw new Error(`Decryption failed: ${error}`);
|
|
@@ -916,6 +766,9 @@ function isWalletConfig(config) {
|
|
|
916
766
|
function isChainConfig(config) {
|
|
917
767
|
return "chainId" in config && !("walletClient" in config);
|
|
918
768
|
}
|
|
769
|
+
function hasStorageConfig(config) {
|
|
770
|
+
return config.storage?.providers !== void 0 && Object.keys(config.storage.providers).length > 0;
|
|
771
|
+
}
|
|
919
772
|
|
|
920
773
|
// src/types/chains.ts
|
|
921
774
|
function isVanaChainId(chainId) {
|
|
@@ -939,8 +792,8 @@ var StorageError = class extends Error {
|
|
|
939
792
|
var import_ajv = __toESM(require("ajv"), 1);
|
|
940
793
|
var import_ajv_formats = __toESM(require("ajv-formats"), 1);
|
|
941
794
|
|
|
942
|
-
// src/schemas/
|
|
943
|
-
var
|
|
795
|
+
// src/schemas/dataSchema.schema.json
|
|
796
|
+
var dataSchema_schema_default = {
|
|
944
797
|
$id: "https://vana.org/data-schema.json",
|
|
945
798
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
946
799
|
title: "Schema",
|
|
@@ -1012,7 +865,7 @@ var SchemaValidator = class {
|
|
|
1012
865
|
strict: false
|
|
1013
866
|
});
|
|
1014
867
|
(0, import_ajv_formats.default)(this.ajv);
|
|
1015
|
-
this.dataSchemaValidator = this.ajv.compile(
|
|
868
|
+
this.dataSchemaValidator = this.ajv.compile(dataSchema_schema_default);
|
|
1016
869
|
}
|
|
1017
870
|
/**
|
|
1018
871
|
* Validates a data schema against the Vana meta-schema
|
|
@@ -1211,55 +1064,6 @@ function isReplicateAPIResponse(value) {
|
|
|
1211
1064
|
obj.status
|
|
1212
1065
|
);
|
|
1213
1066
|
}
|
|
1214
|
-
function isIdentityServerOutput(value) {
|
|
1215
|
-
console.debug("\u{1F50D} Type Guard: Checking value:", value);
|
|
1216
|
-
console.debug("\u{1F50D} Type Guard: Value type:", typeof value);
|
|
1217
|
-
if (typeof value !== "object" || value === null) {
|
|
1218
|
-
console.debug("\u{1F50D} Type Guard: Failed - not object or null");
|
|
1219
|
-
return false;
|
|
1220
|
-
}
|
|
1221
|
-
const obj = value;
|
|
1222
|
-
console.debug("\u{1F50D} Type Guard: Object keys:", Object.keys(obj));
|
|
1223
|
-
console.debug(
|
|
1224
|
-
"\u{1F50D} Type Guard: user_address:",
|
|
1225
|
-
obj.user_address,
|
|
1226
|
-
typeof obj.user_address
|
|
1227
|
-
);
|
|
1228
|
-
if (typeof obj.user_address !== "string") {
|
|
1229
|
-
console.debug("\u{1F50D} Type Guard: Failed - user_address not string");
|
|
1230
|
-
return false;
|
|
1231
|
-
}
|
|
1232
|
-
console.debug(
|
|
1233
|
-
"\u{1F50D} Type Guard: personal_server:",
|
|
1234
|
-
obj.personal_server,
|
|
1235
|
-
typeof obj.personal_server
|
|
1236
|
-
);
|
|
1237
|
-
if (typeof obj.personal_server !== "object" || obj.personal_server === null) {
|
|
1238
|
-
console.debug("\u{1F50D} Type Guard: Failed - personal_server not object or null");
|
|
1239
|
-
return false;
|
|
1240
|
-
}
|
|
1241
|
-
const personalServer = obj.personal_server;
|
|
1242
|
-
console.debug(
|
|
1243
|
-
"\u{1F50D} Type Guard: Personal server keys:",
|
|
1244
|
-
Object.keys(personalServer)
|
|
1245
|
-
);
|
|
1246
|
-
console.debug("\u{1F50D} Type Guard: address:", personalServer.address);
|
|
1247
|
-
console.debug("\u{1F50D} Type Guard: public_key:", personalServer.public_key);
|
|
1248
|
-
const hasAddress = "address" in personalServer;
|
|
1249
|
-
const hasPublicKey = "public_key" in personalServer;
|
|
1250
|
-
console.debug(
|
|
1251
|
-
"\u{1F50D} Type Guard: Has address:",
|
|
1252
|
-
hasAddress,
|
|
1253
|
-
"Has public_key:",
|
|
1254
|
-
hasPublicKey
|
|
1255
|
-
);
|
|
1256
|
-
return hasAddress && hasPublicKey;
|
|
1257
|
-
}
|
|
1258
|
-
function isPersonalServerOutput(value) {
|
|
1259
|
-
if (typeof value !== "object" || value === null) return false;
|
|
1260
|
-
const obj = value;
|
|
1261
|
-
return "user_address" in obj && "identity" in obj && typeof obj.user_address === "string" && typeof obj.identity === "object";
|
|
1262
|
-
}
|
|
1263
1067
|
function isAPIResponse(value) {
|
|
1264
1068
|
if (typeof value !== "object" || value === null) return false;
|
|
1265
1069
|
const obj = value;
|
|
@@ -8290,6 +8094,12 @@ var DataRefinerRegistryABI = [
|
|
|
8290
8094
|
name: "schemaId",
|
|
8291
8095
|
type: "uint256"
|
|
8292
8096
|
},
|
|
8097
|
+
{
|
|
8098
|
+
indexed: false,
|
|
8099
|
+
internalType: "string",
|
|
8100
|
+
name: "schemaDefinitionUrl",
|
|
8101
|
+
type: "string"
|
|
8102
|
+
},
|
|
8293
8103
|
{
|
|
8294
8104
|
indexed: false,
|
|
8295
8105
|
internalType: "string",
|
|
@@ -8393,7 +8203,7 @@ var DataRefinerRegistryABI = [
|
|
|
8393
8203
|
{
|
|
8394
8204
|
indexed: false,
|
|
8395
8205
|
internalType: "string",
|
|
8396
|
-
name: "
|
|
8206
|
+
name: "dialect",
|
|
8397
8207
|
type: "string"
|
|
8398
8208
|
},
|
|
8399
8209
|
{
|
|
@@ -8489,6 +8299,40 @@ var DataRefinerRegistryABI = [
|
|
|
8489
8299
|
stateMutability: "nonpayable",
|
|
8490
8300
|
type: "function"
|
|
8491
8301
|
},
|
|
8302
|
+
{
|
|
8303
|
+
inputs: [
|
|
8304
|
+
{
|
|
8305
|
+
internalType: "uint256",
|
|
8306
|
+
name: "dlpId",
|
|
8307
|
+
type: "uint256"
|
|
8308
|
+
},
|
|
8309
|
+
{
|
|
8310
|
+
internalType: "string",
|
|
8311
|
+
name: "name",
|
|
8312
|
+
type: "string"
|
|
8313
|
+
},
|
|
8314
|
+
{
|
|
8315
|
+
internalType: "string",
|
|
8316
|
+
name: "schemaDefinitionUrl",
|
|
8317
|
+
type: "string"
|
|
8318
|
+
},
|
|
8319
|
+
{
|
|
8320
|
+
internalType: "string",
|
|
8321
|
+
name: "refinementInstructionUrl",
|
|
8322
|
+
type: "string"
|
|
8323
|
+
}
|
|
8324
|
+
],
|
|
8325
|
+
name: "addRefiner",
|
|
8326
|
+
outputs: [
|
|
8327
|
+
{
|
|
8328
|
+
internalType: "uint256",
|
|
8329
|
+
name: "",
|
|
8330
|
+
type: "uint256"
|
|
8331
|
+
}
|
|
8332
|
+
],
|
|
8333
|
+
stateMutability: "nonpayable",
|
|
8334
|
+
type: "function"
|
|
8335
|
+
},
|
|
8492
8336
|
{
|
|
8493
8337
|
inputs: [
|
|
8494
8338
|
{
|
|
@@ -8512,7 +8356,7 @@ var DataRefinerRegistryABI = [
|
|
|
8512
8356
|
type: "string"
|
|
8513
8357
|
}
|
|
8514
8358
|
],
|
|
8515
|
-
name: "
|
|
8359
|
+
name: "addRefinerWithSchemaId",
|
|
8516
8360
|
outputs: [
|
|
8517
8361
|
{
|
|
8518
8362
|
internalType: "uint256",
|
|
@@ -8532,7 +8376,7 @@ var DataRefinerRegistryABI = [
|
|
|
8532
8376
|
},
|
|
8533
8377
|
{
|
|
8534
8378
|
internalType: "string",
|
|
8535
|
-
name: "
|
|
8379
|
+
name: "dialect",
|
|
8536
8380
|
type: "string"
|
|
8537
8381
|
},
|
|
8538
8382
|
{
|
|
@@ -8895,7 +8739,7 @@ var DataRefinerRegistryABI = [
|
|
|
8895
8739
|
},
|
|
8896
8740
|
{
|
|
8897
8741
|
internalType: "string",
|
|
8898
|
-
name: "
|
|
8742
|
+
name: "dialect",
|
|
8899
8743
|
type: "string"
|
|
8900
8744
|
},
|
|
8901
8745
|
{
|
|
@@ -33812,7 +33656,7 @@ function getAbi(contract) {
|
|
|
33812
33656
|
var import_viem = require("viem");
|
|
33813
33657
|
function createGrantFile(params) {
|
|
33814
33658
|
const grantFile = {
|
|
33815
|
-
grantee: params.
|
|
33659
|
+
grantee: params.grantee,
|
|
33816
33660
|
operation: params.operation,
|
|
33817
33661
|
parameters: params.parameters
|
|
33818
33662
|
};
|
|
@@ -34232,7 +34076,7 @@ var PermissionsController = class {
|
|
|
34232
34076
|
* @example
|
|
34233
34077
|
* ```typescript
|
|
34234
34078
|
* const txHash = await vana.permissions.grant({
|
|
34235
|
-
*
|
|
34079
|
+
* grantee: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
|
|
34236
34080
|
* operation: "llm_inference",
|
|
34237
34081
|
* parameters: {
|
|
34238
34082
|
* model: "gpt-4",
|
|
@@ -34261,7 +34105,7 @@ var PermissionsController = class {
|
|
|
34261
34105
|
* @example
|
|
34262
34106
|
* ```typescript
|
|
34263
34107
|
* const { preview, confirm } = await vana.permissions.prepareGrant({
|
|
34264
|
-
*
|
|
34108
|
+
* grantee: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
|
|
34265
34109
|
* operation: "llm_inference",
|
|
34266
34110
|
* files: [1, 2, 3],
|
|
34267
34111
|
* parameters: { model: "gpt-4", prompt: "Analyze my social media data" }
|
|
@@ -34310,9 +34154,13 @@ var PermissionsController = class {
|
|
|
34310
34154
|
console.debug("\u{1F50D} Debug - Grant URL from params:", grantUrl);
|
|
34311
34155
|
if (!grantUrl) {
|
|
34312
34156
|
if (!this.context.relayerCallbacks?.storeGrantFile && !this.context.storageManager) {
|
|
34313
|
-
|
|
34314
|
-
|
|
34315
|
-
|
|
34157
|
+
if (this.context.validateStorageRequired) {
|
|
34158
|
+
this.context.validateStorageRequired();
|
|
34159
|
+
} else {
|
|
34160
|
+
throw new Error(
|
|
34161
|
+
"No storage available. Provide a grantUrl, configure relayerCallbacks.storeGrantFile, or storageManager."
|
|
34162
|
+
);
|
|
34163
|
+
}
|
|
34316
34164
|
}
|
|
34317
34165
|
if (this.context.relayerCallbacks?.storeGrantFile) {
|
|
34318
34166
|
grantUrl = await this.context.relayerCallbacks.storeGrantFile(grantFile);
|
|
@@ -34336,7 +34184,7 @@ var PermissionsController = class {
|
|
|
34336
34184
|
grantUrl
|
|
34337
34185
|
);
|
|
34338
34186
|
const typedData = await this.composePermissionGrantMessage({
|
|
34339
|
-
|
|
34187
|
+
grantee: params.grantee,
|
|
34340
34188
|
operation: params.operation,
|
|
34341
34189
|
// Placeholder - real data is in IPFS
|
|
34342
34190
|
files: params.files,
|
|
@@ -34383,7 +34231,7 @@ var PermissionsController = class {
|
|
|
34383
34231
|
* @example
|
|
34384
34232
|
* ```typescript
|
|
34385
34233
|
* const { typedData, signature } = await vana.permissions.createAndSign({
|
|
34386
|
-
*
|
|
34234
|
+
* grantee: "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36",
|
|
34387
34235
|
* operation: "data_analysis",
|
|
34388
34236
|
* parameters: { analysisType: "sentiment" },
|
|
34389
34237
|
* });
|
|
@@ -34399,9 +34247,13 @@ var PermissionsController = class {
|
|
|
34399
34247
|
console.debug("\u{1F50D} Debug - Grant URL from params:", grantUrl);
|
|
34400
34248
|
if (!grantUrl) {
|
|
34401
34249
|
if (!this.context.relayerCallbacks?.storeGrantFile && !this.context.storageManager) {
|
|
34402
|
-
|
|
34403
|
-
|
|
34404
|
-
|
|
34250
|
+
if (this.context.validateStorageRequired) {
|
|
34251
|
+
this.context.validateStorageRequired();
|
|
34252
|
+
} else {
|
|
34253
|
+
throw new Error(
|
|
34254
|
+
"No storage available. Provide a grantUrl, configure relayerCallbacks.storeGrantFile, or storageManager."
|
|
34255
|
+
);
|
|
34256
|
+
}
|
|
34405
34257
|
}
|
|
34406
34258
|
if (this.context.relayerCallbacks?.storeGrantFile) {
|
|
34407
34259
|
grantUrl = await this.context.relayerCallbacks.storeGrantFile(grantFile);
|
|
@@ -34425,7 +34277,7 @@ var PermissionsController = class {
|
|
|
34425
34277
|
grantUrl
|
|
34426
34278
|
);
|
|
34427
34279
|
const typedData = await this.composePermissionGrantMessage({
|
|
34428
|
-
|
|
34280
|
+
grantee: params.grantee,
|
|
34429
34281
|
operation: params.operation,
|
|
34430
34282
|
// Placeholder - real data is in IPFS
|
|
34431
34283
|
files: params.files,
|
|
@@ -34776,7 +34628,7 @@ var PermissionsController = class {
|
|
|
34776
34628
|
* Composes the EIP-712 typed data for PermissionGrant (new simplified format).
|
|
34777
34629
|
*
|
|
34778
34630
|
* @param params - The parameters for composing the permission grant message
|
|
34779
|
-
* @param params.
|
|
34631
|
+
* @param params.grantee - The recipient address for the permission grant
|
|
34780
34632
|
* @param params.operation - The type of operation being granted permission for
|
|
34781
34633
|
* @param params.files - Array of file IDs that the permission applies to
|
|
34782
34634
|
* @param params.grantUrl - URL where the grant details are stored
|
|
@@ -34869,36 +34721,45 @@ var PermissionsController = class {
|
|
|
34869
34721
|
return addresses[0];
|
|
34870
34722
|
}
|
|
34871
34723
|
/**
|
|
34872
|
-
*
|
|
34724
|
+
* Gets on-chain permission grant data without expensive off-chain resolution.
|
|
34873
34725
|
*
|
|
34874
34726
|
* @remarks
|
|
34875
|
-
* This method
|
|
34876
|
-
*
|
|
34877
|
-
*
|
|
34878
|
-
*
|
|
34879
|
-
*
|
|
34880
|
-
*
|
|
34881
|
-
*
|
|
34882
|
-
*
|
|
34883
|
-
*
|
|
34884
|
-
*
|
|
34727
|
+
* This method provides a fast, performance-focused way to retrieve permission grants
|
|
34728
|
+
* by querying only the subgraph without making expensive IPFS or individual contract calls.
|
|
34729
|
+
* It eliminates the N+1 query problem of the legacy `getUserPermissions()` method.
|
|
34730
|
+
*
|
|
34731
|
+
* The returned data contains all on-chain information but does NOT include resolved
|
|
34732
|
+
* operation details, parameters, or file IDs. Use `retrieveGrantFile()` separately
|
|
34733
|
+
* for specific grants when detailed data is needed.
|
|
34734
|
+
*
|
|
34735
|
+
* **Performance**: Completes in ~100-500ms regardless of permission count.
|
|
34736
|
+
* **Reliability**: Single point of failure (subgraph) with clear RPC fallback path.
|
|
34737
|
+
*
|
|
34738
|
+
* @param options - Options for retrieving permissions (limit, subgraph URL)
|
|
34739
|
+
* @returns A Promise that resolves to an array of `OnChainPermissionGrant` objects
|
|
34740
|
+
* @throws {BlockchainError} When subgraph query fails
|
|
34741
|
+
* @throws {NetworkError} When network requests fail
|
|
34885
34742
|
* @example
|
|
34886
34743
|
* ```typescript
|
|
34887
|
-
* // Get all
|
|
34888
|
-
* const
|
|
34744
|
+
* // Fast: Get all on-chain permission data
|
|
34745
|
+
* const grants = await vana.permissions.getUserPermissionGrantsOnChain({ limit: 20 });
|
|
34889
34746
|
*
|
|
34890
|
-
*
|
|
34891
|
-
*
|
|
34747
|
+
* // Display in UI immediately
|
|
34748
|
+
* grants.forEach(grant => {
|
|
34749
|
+
* console.log(`Permission ${grant.id}: ${grant.grantUrl}`);
|
|
34892
34750
|
* });
|
|
34893
34751
|
*
|
|
34894
|
-
* //
|
|
34895
|
-
* const
|
|
34752
|
+
* // Lazy load detailed data for specific permission when user clicks
|
|
34753
|
+
* const grantFile = await retrieveGrantFile(grants[0].grantUrl);
|
|
34754
|
+
* console.log(`Operation: ${grantFile.operation}`);
|
|
34755
|
+
* console.log(`Parameters:`, grantFile.parameters);
|
|
34896
34756
|
* ```
|
|
34897
34757
|
*/
|
|
34898
|
-
async
|
|
34758
|
+
async getUserPermissionGrantsOnChain(options = {}) {
|
|
34759
|
+
const { limit = 50, subgraphUrl } = options;
|
|
34899
34760
|
try {
|
|
34900
34761
|
const userAddress = await this.getUserAddress();
|
|
34901
|
-
const graphqlEndpoint =
|
|
34762
|
+
const graphqlEndpoint = subgraphUrl || this.context.subgraphUrl;
|
|
34902
34763
|
if (!graphqlEndpoint) {
|
|
34903
34764
|
throw new BlockchainError(
|
|
34904
34765
|
"subgraphUrl is required. Please provide a valid subgraph endpoint or configure it in Vana constructor."
|
|
@@ -34920,16 +34781,6 @@ var PermissionsController = class {
|
|
|
34920
34781
|
}
|
|
34921
34782
|
}
|
|
34922
34783
|
`;
|
|
34923
|
-
console.info("Query:", query);
|
|
34924
|
-
console.info(
|
|
34925
|
-
"Body:",
|
|
34926
|
-
JSON.stringify({
|
|
34927
|
-
query,
|
|
34928
|
-
variables: {
|
|
34929
|
-
userId: userAddress.toLowerCase()
|
|
34930
|
-
}
|
|
34931
|
-
})
|
|
34932
|
-
);
|
|
34933
34784
|
const response = await fetch(graphqlEndpoint, {
|
|
34934
34785
|
method: "POST",
|
|
34935
34786
|
headers: {
|
|
@@ -34948,7 +34799,6 @@ var PermissionsController = class {
|
|
|
34948
34799
|
);
|
|
34949
34800
|
}
|
|
34950
34801
|
const result = await response.json();
|
|
34951
|
-
console.info("Result:", result);
|
|
34952
34802
|
if (result.errors) {
|
|
34953
34803
|
throw new BlockchainError(
|
|
34954
34804
|
`Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
|
|
@@ -34956,64 +34806,32 @@ var PermissionsController = class {
|
|
|
34956
34806
|
}
|
|
34957
34807
|
const userData = result.data?.user;
|
|
34958
34808
|
if (!userData || !userData.permissions?.length) {
|
|
34959
|
-
console.warn("No permissions found for user:", userAddress);
|
|
34960
34809
|
return [];
|
|
34961
34810
|
}
|
|
34962
|
-
const
|
|
34963
|
-
|
|
34964
|
-
|
|
34965
|
-
|
|
34966
|
-
|
|
34967
|
-
|
|
34968
|
-
|
|
34969
|
-
|
|
34970
|
-
|
|
34971
|
-
|
|
34972
|
-
|
|
34973
|
-
|
|
34974
|
-
|
|
34975
|
-
|
|
34976
|
-
} catch {
|
|
34977
|
-
}
|
|
34978
|
-
try {
|
|
34979
|
-
const fileIds = await this.getPermissionFileIds(
|
|
34980
|
-
BigInt(permission.id)
|
|
34981
|
-
);
|
|
34982
|
-
files = fileIds.map((id) => Number(id));
|
|
34983
|
-
} catch {
|
|
34984
|
-
}
|
|
34985
|
-
userPermissions.push({
|
|
34986
|
-
id: BigInt(permission.id),
|
|
34987
|
-
files,
|
|
34988
|
-
operation: operation || "",
|
|
34989
|
-
parameters: parameters || {},
|
|
34990
|
-
grant: permission.grant,
|
|
34991
|
-
grantor: userAddress.toLowerCase(),
|
|
34992
|
-
// Current user is the grantor
|
|
34993
|
-
grantee: granteeAddress || userAddress,
|
|
34994
|
-
// Application that received permission
|
|
34995
|
-
active: true,
|
|
34996
|
-
// Default to active if not specified
|
|
34997
|
-
grantedAt: Number(permission.addedAtBlock),
|
|
34998
|
-
nonce: Number(permission.nonce)
|
|
34999
|
-
});
|
|
35000
|
-
} catch (error) {
|
|
35001
|
-
console.error(
|
|
35002
|
-
"SDK Error: Failed to process permission:",
|
|
35003
|
-
permission.id,
|
|
35004
|
-
error
|
|
35005
|
-
);
|
|
35006
|
-
}
|
|
35007
|
-
}
|
|
35008
|
-
return userPermissions.sort((a, b) => {
|
|
34811
|
+
const onChainGrants = userData.permissions.slice(0, limit).map((permission) => ({
|
|
34812
|
+
id: BigInt(permission.id),
|
|
34813
|
+
grantUrl: permission.grant,
|
|
34814
|
+
grantSignature: permission.grantSignature,
|
|
34815
|
+
grantHash: permission.grantHash,
|
|
34816
|
+
nonce: BigInt(permission.nonce),
|
|
34817
|
+
addedAtBlock: BigInt(permission.addedAtBlock),
|
|
34818
|
+
addedAtTimestamp: BigInt(permission.addedAtTimestamp || "0"),
|
|
34819
|
+
transactionHash: permission.transactionHash || "",
|
|
34820
|
+
grantor: userAddress,
|
|
34821
|
+
active: true
|
|
34822
|
+
// TODO: Add revocation status from subgraph when available
|
|
34823
|
+
}));
|
|
34824
|
+
return onChainGrants.sort((a, b) => {
|
|
35009
34825
|
if (a.id < b.id) return 1;
|
|
35010
34826
|
if (a.id > b.id) return -1;
|
|
35011
34827
|
return 0;
|
|
35012
34828
|
});
|
|
35013
34829
|
} catch (error) {
|
|
35014
|
-
|
|
34830
|
+
if (error instanceof BlockchainError || error instanceof NetworkError) {
|
|
34831
|
+
throw error;
|
|
34832
|
+
}
|
|
35015
34833
|
throw new BlockchainError(
|
|
35016
|
-
`Failed to fetch user
|
|
34834
|
+
`Failed to fetch user permission grants: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
35017
34835
|
);
|
|
35018
34836
|
}
|
|
35019
34837
|
}
|
|
@@ -35711,590 +35529,6 @@ var PermissionsController = class {
|
|
|
35711
35529
|
// src/controllers/data.ts
|
|
35712
35530
|
var import_viem2 = require("viem");
|
|
35713
35531
|
|
|
35714
|
-
// src/controllers/server.ts
|
|
35715
|
-
var ServerController = class {
|
|
35716
|
-
constructor(context) {
|
|
35717
|
-
this.context = context;
|
|
35718
|
-
}
|
|
35719
|
-
REPLICATE_API_URL = "https://api.replicate.com/v1/predictions";
|
|
35720
|
-
PERSONAL_SERVER_VERSION = "vana-com/personal-server:6dae0fead4017557a2e6bd020643359ac1769228a9cfe3bd2365eeeb9711610e";
|
|
35721
|
-
IDENTITY_SERVER_VERSION = "vana-com/identity-server:8e357fbeb87c0558b545809cabd0ef2f311082d8ce1f12b93cb8ad2f38cfbfd2";
|
|
35722
|
-
/**
|
|
35723
|
-
* Posts a computation request to a user's personal server.
|
|
35724
|
-
*
|
|
35725
|
-
* @remarks
|
|
35726
|
-
* This method submits a computation request to the specified user's personal server
|
|
35727
|
-
* via the Replicate API. It creates a signed request with the user address and
|
|
35728
|
-
* permission ID, then submits it for processing. The response includes URLs for
|
|
35729
|
-
* polling results and canceling the computation if needed.
|
|
35730
|
-
*
|
|
35731
|
-
* The method requires a valid Replicate API token and uses the application's
|
|
35732
|
-
* wallet client for request signing to ensure authenticity.
|
|
35733
|
-
* @param params - The request parameters object
|
|
35734
|
-
* @param params.permissionId - The permission ID authorizing this computation
|
|
35735
|
-
* @returns A Promise that resolves to a prediction response with status and control URLs
|
|
35736
|
-
* @throws {PersonalServerError} When server request fails or parameters are invalid
|
|
35737
|
-
* @throws {SignatureError} When request signing fails
|
|
35738
|
-
* @throws {NetworkError} When Replicate API communication fails
|
|
35739
|
-
* @example
|
|
35740
|
-
* ```typescript
|
|
35741
|
-
* const response = await vana.server.postRequest({
|
|
35742
|
-
* permissionId: 123,
|
|
35743
|
-
* });
|
|
35744
|
-
*
|
|
35745
|
-
* console.log(`Request submitted: ${response.id}`);
|
|
35746
|
-
* console.log(`Poll for results: ${response.urls.get}`);
|
|
35747
|
-
* ```
|
|
35748
|
-
*/
|
|
35749
|
-
async postRequest(params) {
|
|
35750
|
-
try {
|
|
35751
|
-
this.validatePostRequestParams(params);
|
|
35752
|
-
const requestJson = this.createRequestJson(params);
|
|
35753
|
-
const signature = await this.createSignature(requestJson);
|
|
35754
|
-
const replicateInput = {
|
|
35755
|
-
replicate_api_token: this.getReplicateApiToken(),
|
|
35756
|
-
signature,
|
|
35757
|
-
request_json: requestJson
|
|
35758
|
-
};
|
|
35759
|
-
console.debug("\u{1F50D} Debug - replicateInput", replicateInput);
|
|
35760
|
-
const response = await this.makeReplicateRequest(replicateInput);
|
|
35761
|
-
return response;
|
|
35762
|
-
} catch (error) {
|
|
35763
|
-
if (error instanceof Error) {
|
|
35764
|
-
if (error instanceof NetworkError || error instanceof SerializationError || error instanceof SignatureError || error instanceof PersonalServerError) {
|
|
35765
|
-
throw error;
|
|
35766
|
-
}
|
|
35767
|
-
throw new PersonalServerError(
|
|
35768
|
-
`Personal server request failed: ${error.message}`,
|
|
35769
|
-
error
|
|
35770
|
-
);
|
|
35771
|
-
}
|
|
35772
|
-
throw new PersonalServerError(
|
|
35773
|
-
"Personal server request failed with unknown error"
|
|
35774
|
-
);
|
|
35775
|
-
}
|
|
35776
|
-
}
|
|
35777
|
-
/**
|
|
35778
|
-
* Initializes the personal server and fetches user identity.
|
|
35779
|
-
*
|
|
35780
|
-
* @param params - The request parameters containing user address
|
|
35781
|
-
* @returns Promise resolving to the user's identity information
|
|
35782
|
-
*/
|
|
35783
|
-
async initPersonalServer(params) {
|
|
35784
|
-
try {
|
|
35785
|
-
this.validateInitPersonalServerParams(params);
|
|
35786
|
-
const response = await this.makePersonalServerRequest(params);
|
|
35787
|
-
const result = await this.pollPersonalServerResult(response);
|
|
35788
|
-
return result;
|
|
35789
|
-
} catch (error) {
|
|
35790
|
-
if (error instanceof Error) {
|
|
35791
|
-
if (error instanceof NetworkError || error instanceof SerializationError || error instanceof PersonalServerError) {
|
|
35792
|
-
throw error;
|
|
35793
|
-
}
|
|
35794
|
-
throw new PersonalServerError(
|
|
35795
|
-
`Personal server initialization failed: ${error.message}`,
|
|
35796
|
-
error
|
|
35797
|
-
);
|
|
35798
|
-
}
|
|
35799
|
-
throw new PersonalServerError(
|
|
35800
|
-
"Personal server initialization failed with unknown error"
|
|
35801
|
-
);
|
|
35802
|
-
}
|
|
35803
|
-
}
|
|
35804
|
-
/**
|
|
35805
|
-
* Retrieves the public key for a user's personal server via the Identity Server.
|
|
35806
|
-
*
|
|
35807
|
-
* @remarks
|
|
35808
|
-
* This method uses the Identity Server to deterministically derive the personal server's
|
|
35809
|
-
* public key from the user's EVM address. This enables anyone to encrypt data for a
|
|
35810
|
-
* specific user's server without requiring that server to be online. The Identity Server
|
|
35811
|
-
* provides a reliable way to obtain encryption keys for secure data sharing across the
|
|
35812
|
-
* Vana network.
|
|
35813
|
-
*
|
|
35814
|
-
* The derived public key is deterministic and consistent, allowing for predictable
|
|
35815
|
-
* encryption workflows in decentralized applications.
|
|
35816
|
-
* @param userAddress - The user's EVM address to derive the server public key for
|
|
35817
|
-
* @returns A Promise that resolves to the server's public key as a hex string
|
|
35818
|
-
* @throws {PersonalServerError} When user address is invalid or server lookup fails
|
|
35819
|
-
* @throws {NetworkError} When Identity Server API request fails
|
|
35820
|
-
* @example
|
|
35821
|
-
* ```typescript
|
|
35822
|
-
* // Get public key for encrypting data to a user's server
|
|
35823
|
-
* const publicKey = await vana.server.getTrustedServerPublicKey(
|
|
35824
|
-
* "0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36"
|
|
35825
|
-
* );
|
|
35826
|
-
*
|
|
35827
|
-
* // Use the public key for encryption
|
|
35828
|
-
* const encryptedData = await encryptForServer(data, publicKey);
|
|
35829
|
-
* ```
|
|
35830
|
-
*/
|
|
35831
|
-
async getTrustedServerPublicKey(userAddress) {
|
|
35832
|
-
try {
|
|
35833
|
-
if (!userAddress || typeof userAddress !== "string") {
|
|
35834
|
-
throw new PersonalServerError(
|
|
35835
|
-
"User address is required and must be a valid string"
|
|
35836
|
-
);
|
|
35837
|
-
}
|
|
35838
|
-
if (!userAddress.startsWith("0x") || userAddress.length !== 42) {
|
|
35839
|
-
throw new PersonalServerError(
|
|
35840
|
-
"User address must be a valid EVM address"
|
|
35841
|
-
);
|
|
35842
|
-
}
|
|
35843
|
-
const requestBody = {
|
|
35844
|
-
version: this.IDENTITY_SERVER_VERSION,
|
|
35845
|
-
input: {
|
|
35846
|
-
user_address: userAddress
|
|
35847
|
-
}
|
|
35848
|
-
};
|
|
35849
|
-
console.debug("Identity Server Request for Public Key:", {
|
|
35850
|
-
url: this.REPLICATE_API_URL,
|
|
35851
|
-
method: "POST",
|
|
35852
|
-
body: requestBody
|
|
35853
|
-
});
|
|
35854
|
-
const response = await fetch(this.REPLICATE_API_URL, {
|
|
35855
|
-
method: "POST",
|
|
35856
|
-
headers: {
|
|
35857
|
-
Authorization: `Token ${this.getReplicateApiToken()}`,
|
|
35858
|
-
"Content-Type": "application/json"
|
|
35859
|
-
},
|
|
35860
|
-
body: JSON.stringify(requestBody)
|
|
35861
|
-
});
|
|
35862
|
-
if (!response.ok) {
|
|
35863
|
-
const errorText = await response.text();
|
|
35864
|
-
console.debug("Identity Server Error Response:", {
|
|
35865
|
-
status: response.status,
|
|
35866
|
-
statusText: response.statusText,
|
|
35867
|
-
error: errorText
|
|
35868
|
-
});
|
|
35869
|
-
throw new NetworkError(
|
|
35870
|
-
`Identity Server API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
35871
|
-
);
|
|
35872
|
-
}
|
|
35873
|
-
const data = await response.json();
|
|
35874
|
-
console.debug("Identity Server Success Response:", data);
|
|
35875
|
-
const result = await this.pollIdentityServerResult({
|
|
35876
|
-
id: data.id,
|
|
35877
|
-
status: data.status,
|
|
35878
|
-
urls: {
|
|
35879
|
-
get: data.urls?.get || "",
|
|
35880
|
-
cancel: data.urls?.cancel || ""
|
|
35881
|
-
},
|
|
35882
|
-
input: data.input,
|
|
35883
|
-
output: data.output,
|
|
35884
|
-
error: data.error
|
|
35885
|
-
});
|
|
35886
|
-
return result;
|
|
35887
|
-
} catch (error) {
|
|
35888
|
-
if (error instanceof Error) {
|
|
35889
|
-
if (error instanceof NetworkError || error instanceof PersonalServerError) {
|
|
35890
|
-
throw error;
|
|
35891
|
-
}
|
|
35892
|
-
throw new PersonalServerError(
|
|
35893
|
-
`Failed to get trusted server public key: ${error.message}`,
|
|
35894
|
-
error
|
|
35895
|
-
);
|
|
35896
|
-
}
|
|
35897
|
-
throw new PersonalServerError(
|
|
35898
|
-
"Failed to get trusted server public key with unknown error"
|
|
35899
|
-
);
|
|
35900
|
-
}
|
|
35901
|
-
}
|
|
35902
|
-
/**
|
|
35903
|
-
* Polls the status of a computation request for updates and results.
|
|
35904
|
-
*
|
|
35905
|
-
* @remarks
|
|
35906
|
-
* This method checks the current status of a computation request by querying
|
|
35907
|
-
* the Replicate API using the provided polling URL. It returns the current
|
|
35908
|
-
* status, any available output, and error information. The method should be
|
|
35909
|
-
* called periodically until the computation completes or fails.
|
|
35910
|
-
*
|
|
35911
|
-
* Common status values include: `starting`, `processing`, `succeeded`, `failed`, `canceled`.
|
|
35912
|
-
* @param getUrl - The polling URL returned from the initial request submission
|
|
35913
|
-
* @returns A Promise that resolves to the current prediction response with status and results
|
|
35914
|
-
* @throws {NetworkError} When the polling request fails or returns invalid data
|
|
35915
|
-
* @example
|
|
35916
|
-
* ```typescript
|
|
35917
|
-
* // Poll until completion
|
|
35918
|
-
* let result = await vana.server.pollStatus(response.urls.get);
|
|
35919
|
-
*
|
|
35920
|
-
* while (result.status === "processing") {
|
|
35921
|
-
* await new Promise(resolve => setTimeout(resolve, 1000));
|
|
35922
|
-
* result = await vana.server.pollStatus(response.urls.get);
|
|
35923
|
-
* }
|
|
35924
|
-
*
|
|
35925
|
-
* if (result.status === "succeeded") {
|
|
35926
|
-
* console.log("Computation completed:", result.output);
|
|
35927
|
-
* }
|
|
35928
|
-
* ```
|
|
35929
|
-
*/
|
|
35930
|
-
async pollStatus(getUrl) {
|
|
35931
|
-
try {
|
|
35932
|
-
console.debug("Polling Replicate Status:", getUrl);
|
|
35933
|
-
const response = await fetch(getUrl, {
|
|
35934
|
-
method: "GET",
|
|
35935
|
-
headers: {
|
|
35936
|
-
Authorization: `Token ${this.getReplicateApiToken()}`,
|
|
35937
|
-
"Content-Type": "application/json"
|
|
35938
|
-
}
|
|
35939
|
-
});
|
|
35940
|
-
if (!response.ok) {
|
|
35941
|
-
const errorText = await response.text();
|
|
35942
|
-
console.debug("Polling Error Response:", {
|
|
35943
|
-
status: response.status,
|
|
35944
|
-
statusText: response.statusText,
|
|
35945
|
-
error: errorText
|
|
35946
|
-
});
|
|
35947
|
-
throw new NetworkError(
|
|
35948
|
-
`Status polling failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
35949
|
-
);
|
|
35950
|
-
}
|
|
35951
|
-
const data = await response.json();
|
|
35952
|
-
console.debug("Polling Success Response:", data);
|
|
35953
|
-
return {
|
|
35954
|
-
id: data.id,
|
|
35955
|
-
status: data.status,
|
|
35956
|
-
urls: {
|
|
35957
|
-
get: data.urls?.get || getUrl,
|
|
35958
|
-
cancel: data.urls?.cancel || ""
|
|
35959
|
-
},
|
|
35960
|
-
input: data.input,
|
|
35961
|
-
output: data.output,
|
|
35962
|
-
error: data.error
|
|
35963
|
-
};
|
|
35964
|
-
} catch (error) {
|
|
35965
|
-
if (error instanceof NetworkError) {
|
|
35966
|
-
throw error;
|
|
35967
|
-
}
|
|
35968
|
-
throw new NetworkError(
|
|
35969
|
-
`Failed to poll status: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
35970
|
-
);
|
|
35971
|
-
}
|
|
35972
|
-
}
|
|
35973
|
-
/**
|
|
35974
|
-
* Validates the post request parameters.
|
|
35975
|
-
*
|
|
35976
|
-
* @param params - The post request parameters to validate
|
|
35977
|
-
*/
|
|
35978
|
-
validatePostRequestParams(params) {
|
|
35979
|
-
if (typeof params.permissionId !== "number" || params.permissionId <= 0) {
|
|
35980
|
-
throw new PersonalServerError(
|
|
35981
|
-
"Permission ID is required and must be a valid positive number"
|
|
35982
|
-
);
|
|
35983
|
-
}
|
|
35984
|
-
}
|
|
35985
|
-
/**
|
|
35986
|
-
* Validates the init personal server parameters.
|
|
35987
|
-
*
|
|
35988
|
-
* @param params - The initialization parameters to validate
|
|
35989
|
-
*/
|
|
35990
|
-
validateInitPersonalServerParams(params) {
|
|
35991
|
-
if (!params.userAddress || typeof params.userAddress !== "string") {
|
|
35992
|
-
throw new PersonalServerError(
|
|
35993
|
-
"User address is required and must be a valid string"
|
|
35994
|
-
);
|
|
35995
|
-
}
|
|
35996
|
-
if (!params.userAddress.startsWith("0x") || params.userAddress.length !== 42) {
|
|
35997
|
-
throw new PersonalServerError(
|
|
35998
|
-
"User address must be a valid Vana address"
|
|
35999
|
-
);
|
|
36000
|
-
}
|
|
36001
|
-
}
|
|
36002
|
-
/**
|
|
36003
|
-
* Creates the request JSON string for the personal server.
|
|
36004
|
-
*
|
|
36005
|
-
* @param params - The post request parameters to serialize
|
|
36006
|
-
* @returns JSON string representation of the request data
|
|
36007
|
-
*/
|
|
36008
|
-
createRequestJson(params) {
|
|
36009
|
-
try {
|
|
36010
|
-
const requestData = {
|
|
36011
|
-
permission_id: params.permissionId
|
|
36012
|
-
};
|
|
36013
|
-
return JSON.stringify(requestData);
|
|
36014
|
-
} catch (error) {
|
|
36015
|
-
throw new SerializationError(
|
|
36016
|
-
`Failed to create request JSON: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
36017
|
-
);
|
|
36018
|
-
}
|
|
36019
|
-
}
|
|
36020
|
-
/**
|
|
36021
|
-
* Creates a signature for the request JSON.
|
|
36022
|
-
*
|
|
36023
|
-
* @param requestJson - The JSON string to sign
|
|
36024
|
-
* @returns Promise resolving to the cryptographic signature
|
|
36025
|
-
*/
|
|
36026
|
-
async createSignature(requestJson) {
|
|
36027
|
-
try {
|
|
36028
|
-
console.debug("\u{1F50D} Debug - createSignature", requestJson);
|
|
36029
|
-
const client = this.context.applicationClient || this.context.walletClient;
|
|
36030
|
-
const account = client.account;
|
|
36031
|
-
if (!account) {
|
|
36032
|
-
throw new SignatureError("No account available for signing");
|
|
36033
|
-
}
|
|
36034
|
-
if (account.type !== "local") {
|
|
36035
|
-
throw new SignatureError(
|
|
36036
|
-
"Only local accounts are supported for signing"
|
|
36037
|
-
);
|
|
36038
|
-
}
|
|
36039
|
-
const signature = await account.signMessage({
|
|
36040
|
-
message: requestJson
|
|
36041
|
-
});
|
|
36042
|
-
return signature;
|
|
36043
|
-
} catch (error) {
|
|
36044
|
-
if (error instanceof Error && error.message.includes("User rejected")) {
|
|
36045
|
-
throw new SignatureError("User rejected the signature request");
|
|
36046
|
-
}
|
|
36047
|
-
throw new SignatureError(
|
|
36048
|
-
`Failed to create signature: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
36049
|
-
);
|
|
36050
|
-
}
|
|
36051
|
-
}
|
|
36052
|
-
/**
|
|
36053
|
-
* Gets the Replicate API token from environment.
|
|
36054
|
-
*
|
|
36055
|
-
* @returns The Replicate API token from environment variables
|
|
36056
|
-
*/
|
|
36057
|
-
getReplicateApiToken() {
|
|
36058
|
-
const token = process.env.REPLICATE_API_TOKEN || process.env.NEXT_PUBLIC_REPLICATE_API_TOKEN;
|
|
36059
|
-
if (!token) {
|
|
36060
|
-
throw new PersonalServerError(
|
|
36061
|
-
"REPLICATE_API_TOKEN environment variable is required"
|
|
36062
|
-
);
|
|
36063
|
-
}
|
|
36064
|
-
return token;
|
|
36065
|
-
}
|
|
36066
|
-
/**
|
|
36067
|
-
* Makes the request to the Replicate API.
|
|
36068
|
-
*
|
|
36069
|
-
* @param input - The input parameters for the Replicate API request
|
|
36070
|
-
* @returns Promise resolving to the Replicate prediction response
|
|
36071
|
-
*/
|
|
36072
|
-
async makeReplicateRequest(input) {
|
|
36073
|
-
try {
|
|
36074
|
-
const requestBody = {
|
|
36075
|
-
version: this.PERSONAL_SERVER_VERSION,
|
|
36076
|
-
input
|
|
36077
|
-
};
|
|
36078
|
-
console.debug("Replicate Request:", {
|
|
36079
|
-
url: this.REPLICATE_API_URL,
|
|
36080
|
-
method: "POST",
|
|
36081
|
-
headers: {
|
|
36082
|
-
Authorization: `Token ${this.getReplicateApiToken().substring(0, 10)}...`,
|
|
36083
|
-
"Content-Type": "application/json"
|
|
36084
|
-
},
|
|
36085
|
-
body: requestBody
|
|
36086
|
-
});
|
|
36087
|
-
const response = await fetch(this.REPLICATE_API_URL, {
|
|
36088
|
-
method: "POST",
|
|
36089
|
-
headers: {
|
|
36090
|
-
Authorization: `Token ${this.getReplicateApiToken()}`,
|
|
36091
|
-
"Content-Type": "application/json"
|
|
36092
|
-
},
|
|
36093
|
-
body: JSON.stringify(requestBody)
|
|
36094
|
-
});
|
|
36095
|
-
if (!response.ok) {
|
|
36096
|
-
const errorText = await response.text();
|
|
36097
|
-
console.debug("Replicate Error Response:", {
|
|
36098
|
-
status: response.status,
|
|
36099
|
-
statusText: response.statusText,
|
|
36100
|
-
error: errorText
|
|
36101
|
-
});
|
|
36102
|
-
throw new NetworkError(
|
|
36103
|
-
`Replicate API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
36104
|
-
);
|
|
36105
|
-
}
|
|
36106
|
-
const data = await response.json();
|
|
36107
|
-
console.debug("Replicate Success Response:", data);
|
|
36108
|
-
return {
|
|
36109
|
-
id: data.id,
|
|
36110
|
-
status: data.status,
|
|
36111
|
-
urls: {
|
|
36112
|
-
get: data.urls?.get || "",
|
|
36113
|
-
cancel: data.urls?.cancel || ""
|
|
36114
|
-
},
|
|
36115
|
-
input: data.input,
|
|
36116
|
-
output: data.output,
|
|
36117
|
-
error: data.error
|
|
36118
|
-
};
|
|
36119
|
-
} catch (error) {
|
|
36120
|
-
if (error instanceof NetworkError) {
|
|
36121
|
-
throw error;
|
|
36122
|
-
}
|
|
36123
|
-
throw new NetworkError(
|
|
36124
|
-
`Failed to make Replicate API request: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
36125
|
-
);
|
|
36126
|
-
}
|
|
36127
|
-
}
|
|
36128
|
-
/**
|
|
36129
|
-
* Makes the request to the personal server.
|
|
36130
|
-
*
|
|
36131
|
-
* @param params - The initialization parameters for the personal server
|
|
36132
|
-
* @returns Promise resolving to the Replicate prediction response
|
|
36133
|
-
*/
|
|
36134
|
-
async makePersonalServerRequest(params) {
|
|
36135
|
-
try {
|
|
36136
|
-
const requestBody = {
|
|
36137
|
-
version: this.IDENTITY_SERVER_VERSION,
|
|
36138
|
-
input: {
|
|
36139
|
-
user_address: params.userAddress
|
|
36140
|
-
}
|
|
36141
|
-
};
|
|
36142
|
-
console.debug("Personal Server Request:", {
|
|
36143
|
-
url: this.REPLICATE_API_URL,
|
|
36144
|
-
method: "POST",
|
|
36145
|
-
headers: {
|
|
36146
|
-
Authorization: `Token ${this.getReplicateApiToken().substring(0, 10)}...`,
|
|
36147
|
-
"Content-Type": "application/json"
|
|
36148
|
-
},
|
|
36149
|
-
body: requestBody
|
|
36150
|
-
});
|
|
36151
|
-
const response = await fetch(this.REPLICATE_API_URL, {
|
|
36152
|
-
method: "POST",
|
|
36153
|
-
headers: {
|
|
36154
|
-
Authorization: `Token ${this.getReplicateApiToken()}`,
|
|
36155
|
-
"Content-Type": "application/json"
|
|
36156
|
-
},
|
|
36157
|
-
body: JSON.stringify(requestBody)
|
|
36158
|
-
});
|
|
36159
|
-
if (!response.ok) {
|
|
36160
|
-
const errorText = await response.text();
|
|
36161
|
-
console.debug("Personal Server Error Response:", {
|
|
36162
|
-
status: response.status,
|
|
36163
|
-
statusText: response.statusText,
|
|
36164
|
-
error: errorText
|
|
36165
|
-
});
|
|
36166
|
-
throw new NetworkError(
|
|
36167
|
-
`Personal Server API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
36168
|
-
);
|
|
36169
|
-
}
|
|
36170
|
-
const data = await response.json();
|
|
36171
|
-
console.debug("Personal Server Success Response:", data);
|
|
36172
|
-
return {
|
|
36173
|
-
id: data.id,
|
|
36174
|
-
status: data.status,
|
|
36175
|
-
urls: {
|
|
36176
|
-
get: data.urls?.get || "",
|
|
36177
|
-
cancel: data.urls?.cancel || ""
|
|
36178
|
-
},
|
|
36179
|
-
input: data.input,
|
|
36180
|
-
output: data.output,
|
|
36181
|
-
error: data.error
|
|
36182
|
-
};
|
|
36183
|
-
} catch (error) {
|
|
36184
|
-
if (error instanceof NetworkError) {
|
|
36185
|
-
throw error;
|
|
36186
|
-
}
|
|
36187
|
-
throw new NetworkError(
|
|
36188
|
-
`Failed to make Personal Server API request: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
36189
|
-
);
|
|
36190
|
-
}
|
|
36191
|
-
}
|
|
36192
|
-
/**
|
|
36193
|
-
* Polls the identity server result until completion and extracts the public key.
|
|
36194
|
-
*
|
|
36195
|
-
* @param initialResponse - The initial response from the identity server
|
|
36196
|
-
* @returns Promise resolving to the extracted public key
|
|
36197
|
-
*/
|
|
36198
|
-
async pollIdentityServerResult(initialResponse) {
|
|
36199
|
-
const maxAttempts = 60;
|
|
36200
|
-
let attempts = 0;
|
|
36201
|
-
let currentResponse = initialResponse;
|
|
36202
|
-
while (attempts < maxAttempts) {
|
|
36203
|
-
if (currentResponse.status === "succeeded") {
|
|
36204
|
-
const output = currentResponse.output;
|
|
36205
|
-
let parsedOutput;
|
|
36206
|
-
if (typeof output === "string") {
|
|
36207
|
-
try {
|
|
36208
|
-
parsedOutput = JSON.parse(output);
|
|
36209
|
-
} catch {
|
|
36210
|
-
throw new PersonalServerError(
|
|
36211
|
-
"Failed to parse Identity Server response as JSON"
|
|
36212
|
-
);
|
|
36213
|
-
}
|
|
36214
|
-
} else {
|
|
36215
|
-
parsedOutput = output;
|
|
36216
|
-
}
|
|
36217
|
-
const personalServer = parsedOutput.personal_server;
|
|
36218
|
-
if (!personalServer || !personalServer.public_key) {
|
|
36219
|
-
throw new PersonalServerError(
|
|
36220
|
-
"Identity Server response missing personal_server.public_key"
|
|
36221
|
-
);
|
|
36222
|
-
}
|
|
36223
|
-
return personalServer.public_key;
|
|
36224
|
-
} else if (currentResponse.status === "failed") {
|
|
36225
|
-
throw new PersonalServerError(
|
|
36226
|
-
`Identity Server request failed: ${currentResponse.error || "Unknown error"}`
|
|
36227
|
-
);
|
|
36228
|
-
} else if (currentResponse.status === "canceled") {
|
|
36229
|
-
throw new PersonalServerError("Identity Server request was canceled");
|
|
36230
|
-
}
|
|
36231
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
36232
|
-
attempts++;
|
|
36233
|
-
if (currentResponse.urls.get) {
|
|
36234
|
-
currentResponse = await this.pollStatus(currentResponse.urls.get);
|
|
36235
|
-
}
|
|
36236
|
-
}
|
|
36237
|
-
throw new PersonalServerError(
|
|
36238
|
-
"Identity Server request timed out after 60 seconds"
|
|
36239
|
-
);
|
|
36240
|
-
}
|
|
36241
|
-
/**
|
|
36242
|
-
* Polls the personal server result until completion.
|
|
36243
|
-
*
|
|
36244
|
-
* @param initialResponse - The initial response from the personal server
|
|
36245
|
-
* @returns Promise resolving to the personal server response data
|
|
36246
|
-
*/
|
|
36247
|
-
async pollPersonalServerResult(initialResponse) {
|
|
36248
|
-
const maxAttempts = 60;
|
|
36249
|
-
let attempts = 0;
|
|
36250
|
-
let currentResponse = initialResponse;
|
|
36251
|
-
while (attempts < maxAttempts) {
|
|
36252
|
-
if (currentResponse.status === "succeeded") {
|
|
36253
|
-
const output = currentResponse.output;
|
|
36254
|
-
let parsedOutput;
|
|
36255
|
-
if (typeof output === "string") {
|
|
36256
|
-
try {
|
|
36257
|
-
parsedOutput = JSON.parse(output);
|
|
36258
|
-
} catch {
|
|
36259
|
-
parsedOutput = output;
|
|
36260
|
-
}
|
|
36261
|
-
} else {
|
|
36262
|
-
parsedOutput = output;
|
|
36263
|
-
}
|
|
36264
|
-
const personalServer = parsedOutput.personal_server;
|
|
36265
|
-
const derivedAddress = personalServer?.address;
|
|
36266
|
-
const publicKey = personalServer?.public_key;
|
|
36267
|
-
return {
|
|
36268
|
-
userAddress: parsedOutput.user_address,
|
|
36269
|
-
identity: {
|
|
36270
|
-
metadata: {
|
|
36271
|
-
derivedAddress,
|
|
36272
|
-
publicKey
|
|
36273
|
-
}
|
|
36274
|
-
},
|
|
36275
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
36276
|
-
};
|
|
36277
|
-
} else if (currentResponse.status === "failed") {
|
|
36278
|
-
throw new PersonalServerError(
|
|
36279
|
-
`Personal server initialization failed: ${currentResponse.error || "Unknown error"}`
|
|
36280
|
-
);
|
|
36281
|
-
} else if (currentResponse.status === "canceled") {
|
|
36282
|
-
throw new PersonalServerError(
|
|
36283
|
-
"Personal server initialization was canceled"
|
|
36284
|
-
);
|
|
36285
|
-
}
|
|
36286
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
36287
|
-
attempts++;
|
|
36288
|
-
if (currentResponse.urls.get) {
|
|
36289
|
-
currentResponse = await this.pollStatus(currentResponse.urls.get);
|
|
36290
|
-
}
|
|
36291
|
-
}
|
|
36292
|
-
throw new PersonalServerError(
|
|
36293
|
-
"Personal server initialization timed out after 60 seconds"
|
|
36294
|
-
);
|
|
36295
|
-
}
|
|
36296
|
-
};
|
|
36297
|
-
|
|
36298
35532
|
// src/utils/encryption.ts
|
|
36299
35533
|
var DEFAULT_ENCRYPTION_SEED = "Please sign to retrieve your encryption key";
|
|
36300
35534
|
async function generateEncryptionKey(wallet, seed = DEFAULT_ENCRYPTION_SEED) {
|
|
@@ -36359,32 +35593,19 @@ async function decryptWithPrivateKey(encryptedData, privateKey, platformAdapter)
|
|
|
36359
35593
|
throw new Error(`Failed to decrypt with private key: ${error}`);
|
|
36360
35594
|
}
|
|
36361
35595
|
}
|
|
36362
|
-
async function
|
|
35596
|
+
async function encryptBlobWithSignedKey(data, key, platformAdapter) {
|
|
36363
35597
|
try {
|
|
36364
35598
|
const dataBuffer = data instanceof Blob ? await data.arrayBuffer() : new TextEncoder().encode(data);
|
|
36365
35599
|
const dataArray = new Uint8Array(dataBuffer);
|
|
36366
35600
|
const encrypted = await platformAdapter.crypto.encryptWithPassword(
|
|
36367
35601
|
dataArray,
|
|
36368
|
-
|
|
35602
|
+
key
|
|
36369
35603
|
);
|
|
36370
35604
|
return new Blob([encrypted], {
|
|
36371
35605
|
type: "application/octet-stream"
|
|
36372
35606
|
});
|
|
36373
35607
|
} catch (error) {
|
|
36374
|
-
throw new Error(`Failed to encrypt
|
|
36375
|
-
}
|
|
36376
|
-
}
|
|
36377
|
-
async function decryptUserData(encryptedData, walletSignature, platformAdapter) {
|
|
36378
|
-
try {
|
|
36379
|
-
const encryptedBuffer = encryptedData instanceof Blob ? await encryptedData.arrayBuffer() : new TextEncoder().encode(encryptedData);
|
|
36380
|
-
const encryptedArray = new Uint8Array(encryptedBuffer);
|
|
36381
|
-
const decrypted = await platformAdapter.crypto.decryptWithPassword(
|
|
36382
|
-
encryptedArray,
|
|
36383
|
-
walletSignature
|
|
36384
|
-
);
|
|
36385
|
-
return new Blob([decrypted], { type: "text/plain" });
|
|
36386
|
-
} catch (error) {
|
|
36387
|
-
throw new Error(`Failed to decrypt user data: ${error}`);
|
|
35608
|
+
throw new Error(`Failed to encrypt data: ${error}`);
|
|
36388
35609
|
}
|
|
36389
35610
|
}
|
|
36390
35611
|
async function generateEncryptionKeyPair(platformAdapter) {
|
|
@@ -36401,14 +35622,316 @@ async function generatePGPKeyPair(platformAdapter, options) {
|
|
|
36401
35622
|
throw new Error(`Failed to generate PGP key pair: ${error}`);
|
|
36402
35623
|
}
|
|
36403
35624
|
}
|
|
35625
|
+
async function decryptBlobWithSignedKey(encryptedData, key, platformAdapter) {
|
|
35626
|
+
try {
|
|
35627
|
+
const encryptedBuffer = encryptedData instanceof Blob ? await encryptedData.arrayBuffer() : new TextEncoder().encode(encryptedData);
|
|
35628
|
+
const encryptedArray = new Uint8Array(encryptedBuffer);
|
|
35629
|
+
const decrypted = await platformAdapter.crypto.decryptWithPassword(
|
|
35630
|
+
encryptedArray,
|
|
35631
|
+
key
|
|
35632
|
+
);
|
|
35633
|
+
return new Blob([decrypted], { type: "text/plain" });
|
|
35634
|
+
} catch (error) {
|
|
35635
|
+
throw new Error(`Failed to decrypt data: ${error}`);
|
|
35636
|
+
}
|
|
35637
|
+
}
|
|
36404
35638
|
|
|
36405
35639
|
// src/controllers/data.ts
|
|
36406
35640
|
var DataController = class {
|
|
36407
35641
|
constructor(context) {
|
|
36408
35642
|
this.context = context;
|
|
36409
|
-
this.serverController = new ServerController(context);
|
|
36410
35643
|
}
|
|
36411
|
-
|
|
35644
|
+
async upload(params) {
|
|
35645
|
+
const {
|
|
35646
|
+
content,
|
|
35647
|
+
filename,
|
|
35648
|
+
schemaId,
|
|
35649
|
+
permissions = [],
|
|
35650
|
+
encrypt: encrypt3 = true,
|
|
35651
|
+
providerName
|
|
35652
|
+
} = params;
|
|
35653
|
+
try {
|
|
35654
|
+
let blob;
|
|
35655
|
+
if (content instanceof Blob) {
|
|
35656
|
+
blob = content;
|
|
35657
|
+
} else if (typeof content === "string") {
|
|
35658
|
+
blob = new Blob([content], { type: "text/plain" });
|
|
35659
|
+
} else if (content instanceof Buffer) {
|
|
35660
|
+
blob = new Blob([content], { type: "application/octet-stream" });
|
|
35661
|
+
} else {
|
|
35662
|
+
blob = new Blob([JSON.stringify(content)], {
|
|
35663
|
+
type: "application/json"
|
|
35664
|
+
});
|
|
35665
|
+
}
|
|
35666
|
+
let isValid = true;
|
|
35667
|
+
let validationErrors = [];
|
|
35668
|
+
if (schemaId !== void 0) {
|
|
35669
|
+
try {
|
|
35670
|
+
const schema = await this.getSchema(schemaId);
|
|
35671
|
+
const response = await fetch(schema.definitionUrl);
|
|
35672
|
+
if (!response.ok) {
|
|
35673
|
+
throw new Error(
|
|
35674
|
+
`Failed to fetch schema definition: ${response.status}`
|
|
35675
|
+
);
|
|
35676
|
+
}
|
|
35677
|
+
const schemaDefinition = await response.json();
|
|
35678
|
+
const dataSchema = {
|
|
35679
|
+
name: schema.name,
|
|
35680
|
+
version: "1.0.0",
|
|
35681
|
+
dialect: "json",
|
|
35682
|
+
schema: schemaDefinition
|
|
35683
|
+
};
|
|
35684
|
+
let parsedContent;
|
|
35685
|
+
if (typeof content === "string") {
|
|
35686
|
+
try {
|
|
35687
|
+
parsedContent = JSON.parse(content);
|
|
35688
|
+
} catch {
|
|
35689
|
+
parsedContent = content;
|
|
35690
|
+
}
|
|
35691
|
+
} else {
|
|
35692
|
+
parsedContent = content;
|
|
35693
|
+
}
|
|
35694
|
+
validateDataAgainstSchema(parsedContent, dataSchema);
|
|
35695
|
+
} catch (error) {
|
|
35696
|
+
isValid = false;
|
|
35697
|
+
validationErrors = [
|
|
35698
|
+
error instanceof Error ? error.message : "Schema validation failed"
|
|
35699
|
+
];
|
|
35700
|
+
}
|
|
35701
|
+
}
|
|
35702
|
+
let finalBlob = blob;
|
|
35703
|
+
if (encrypt3) {
|
|
35704
|
+
const encryptionKey = await generateEncryptionKey(
|
|
35705
|
+
this.context.walletClient,
|
|
35706
|
+
DEFAULT_ENCRYPTION_SEED
|
|
35707
|
+
);
|
|
35708
|
+
finalBlob = await encryptBlobWithSignedKey(
|
|
35709
|
+
blob,
|
|
35710
|
+
encryptionKey,
|
|
35711
|
+
this.context.platform
|
|
35712
|
+
);
|
|
35713
|
+
}
|
|
35714
|
+
if (!this.context.storageManager) {
|
|
35715
|
+
if (this.context.validateStorageRequired) {
|
|
35716
|
+
this.context.validateStorageRequired();
|
|
35717
|
+
throw new Error("Storage validation failed");
|
|
35718
|
+
} else {
|
|
35719
|
+
throw new Error(
|
|
35720
|
+
"Storage manager not configured. Please provide storage providers in VanaConfig."
|
|
35721
|
+
);
|
|
35722
|
+
}
|
|
35723
|
+
}
|
|
35724
|
+
const uploadResult = await this.context.storageManager.upload(
|
|
35725
|
+
finalBlob,
|
|
35726
|
+
filename,
|
|
35727
|
+
providerName
|
|
35728
|
+
);
|
|
35729
|
+
const userAddress = await this.getUserAddress();
|
|
35730
|
+
let encryptedPermissions = [];
|
|
35731
|
+
if (permissions.length > 0 && encrypt3) {
|
|
35732
|
+
const userEncryptionKey = await generateEncryptionKey(
|
|
35733
|
+
this.context.walletClient,
|
|
35734
|
+
DEFAULT_ENCRYPTION_SEED
|
|
35735
|
+
);
|
|
35736
|
+
encryptedPermissions = await Promise.all(
|
|
35737
|
+
permissions.map(async (permission) => {
|
|
35738
|
+
const publicKey = permission.publicKey;
|
|
35739
|
+
if (!publicKey) {
|
|
35740
|
+
throw new Error(
|
|
35741
|
+
`Public key required for permission to ${permission.grantee} when encryption is enabled`
|
|
35742
|
+
);
|
|
35743
|
+
}
|
|
35744
|
+
const encryptedKey = await encryptWithWalletPublicKey(
|
|
35745
|
+
userEncryptionKey,
|
|
35746
|
+
publicKey,
|
|
35747
|
+
this.context.platform
|
|
35748
|
+
);
|
|
35749
|
+
return {
|
|
35750
|
+
account: permission.grantee,
|
|
35751
|
+
key: encryptedKey
|
|
35752
|
+
};
|
|
35753
|
+
})
|
|
35754
|
+
);
|
|
35755
|
+
}
|
|
35756
|
+
let result;
|
|
35757
|
+
if (this.context.relayerCallbacks?.submitFileAdditionComplete) {
|
|
35758
|
+
result = await this.context.relayerCallbacks.submitFileAdditionComplete(
|
|
35759
|
+
{
|
|
35760
|
+
url: uploadResult.url,
|
|
35761
|
+
userAddress,
|
|
35762
|
+
permissions: encryptedPermissions,
|
|
35763
|
+
schemaId: schemaId || 0
|
|
35764
|
+
}
|
|
35765
|
+
);
|
|
35766
|
+
} else if (this.context.relayerCallbacks?.submitFileAddition) {
|
|
35767
|
+
const needsComplexRegistration = schemaId !== void 0 || encryptedPermissions.length > 0;
|
|
35768
|
+
if (needsComplexRegistration) {
|
|
35769
|
+
throw new Error(
|
|
35770
|
+
"The configured relay callback does not support schemas or permissions. Please update your relay server implementation to provide the `submitFileAdditionComplete` callback."
|
|
35771
|
+
);
|
|
35772
|
+
}
|
|
35773
|
+
result = await this.context.relayerCallbacks.submitFileAddition(
|
|
35774
|
+
uploadResult.url,
|
|
35775
|
+
userAddress
|
|
35776
|
+
);
|
|
35777
|
+
} else {
|
|
35778
|
+
result = await this.addFileWithPermissionsAndSchema(
|
|
35779
|
+
uploadResult.url,
|
|
35780
|
+
userAddress,
|
|
35781
|
+
encryptedPermissions,
|
|
35782
|
+
schemaId || 0
|
|
35783
|
+
);
|
|
35784
|
+
}
|
|
35785
|
+
return {
|
|
35786
|
+
fileId: result.fileId,
|
|
35787
|
+
url: uploadResult.url,
|
|
35788
|
+
transactionHash: result.transactionHash,
|
|
35789
|
+
size: uploadResult.size,
|
|
35790
|
+
isValid,
|
|
35791
|
+
validationErrors: validationErrors.length > 0 ? validationErrors : void 0
|
|
35792
|
+
};
|
|
35793
|
+
} catch (error) {
|
|
35794
|
+
throw new Error(
|
|
35795
|
+
`Upload failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
35796
|
+
);
|
|
35797
|
+
}
|
|
35798
|
+
}
|
|
35799
|
+
/**
|
|
35800
|
+
* Decrypts a file owned by the user using their wallet signature.
|
|
35801
|
+
*
|
|
35802
|
+
* @remarks
|
|
35803
|
+
* This is the high-level convenience method for decrypting user files, serving as the
|
|
35804
|
+
* symmetrical counterpart to the `upload` method. It handles the complete decryption
|
|
35805
|
+
* workflow including key generation, URL protocol detection, content fetching, and
|
|
35806
|
+
* decryption.
|
|
35807
|
+
*
|
|
35808
|
+
* The method automatically:
|
|
35809
|
+
* - Generates the decryption key from the user's wallet signature
|
|
35810
|
+
* - Determines the appropriate fetch method based on the file URL protocol
|
|
35811
|
+
* - Fetches the encrypted content from IPFS or standard HTTP URLs
|
|
35812
|
+
* - Decrypts the content using the generated key
|
|
35813
|
+
*
|
|
35814
|
+
* For IPFS URLs, the method uses gateway fallback for improved reliability. For
|
|
35815
|
+
* standard HTTP URLs, it uses a simple fetch. If you need custom authentication
|
|
35816
|
+
* headers or specific gateway configurations, use the low-level primitives directly.
|
|
35817
|
+
*
|
|
35818
|
+
* @param file - The user file to decrypt (typically from getUserFiles)
|
|
35819
|
+
* @param encryptionSeed - Optional custom encryption seed (defaults to Vana standard)
|
|
35820
|
+
* @returns Promise resolving to the decrypted file content as a Blob
|
|
35821
|
+
* @throws {Error} When the wallet is not connected
|
|
35822
|
+
* @throws {Error} When fetching the encrypted content fails
|
|
35823
|
+
* @throws {Error} When decryption fails (wrong key or corrupted data)
|
|
35824
|
+
* @example
|
|
35825
|
+
* ```typescript
|
|
35826
|
+
* // Basic file decryption
|
|
35827
|
+
* const files = await vana.data.getUserFiles({ owner: userAddress });
|
|
35828
|
+
* const decryptedBlob = await vana.data.decryptFile(files[0]);
|
|
35829
|
+
*
|
|
35830
|
+
* // Convert to text
|
|
35831
|
+
* const text = await decryptedBlob.text();
|
|
35832
|
+
* console.log('Decrypted content:', text);
|
|
35833
|
+
*
|
|
35834
|
+
* // Convert to JSON
|
|
35835
|
+
* const json = JSON.parse(await decryptedBlob.text());
|
|
35836
|
+
* console.log('Decrypted data:', json);
|
|
35837
|
+
*
|
|
35838
|
+
* // With custom encryption seed
|
|
35839
|
+
* const decryptedBlob = await vana.data.decryptFile(
|
|
35840
|
+
* files[0],
|
|
35841
|
+
* "My custom encryption seed"
|
|
35842
|
+
* );
|
|
35843
|
+
*
|
|
35844
|
+
* // Save to file (in Node.js)
|
|
35845
|
+
* const buffer = await decryptedBlob.arrayBuffer();
|
|
35846
|
+
* fs.writeFileSync('decrypted-file.txt', Buffer.from(buffer));
|
|
35847
|
+
* ```
|
|
35848
|
+
*/
|
|
35849
|
+
async decryptFile(file, encryptionSeed) {
|
|
35850
|
+
try {
|
|
35851
|
+
const encryptionKey = await generateEncryptionKey(
|
|
35852
|
+
this.context.walletClient,
|
|
35853
|
+
encryptionSeed || DEFAULT_ENCRYPTION_SEED
|
|
35854
|
+
);
|
|
35855
|
+
let encryptedBlob;
|
|
35856
|
+
try {
|
|
35857
|
+
if (file.url.startsWith("ipfs://")) {
|
|
35858
|
+
encryptedBlob = await this.fetchFromIPFS(file.url);
|
|
35859
|
+
} else {
|
|
35860
|
+
encryptedBlob = await this.fetch(file.url);
|
|
35861
|
+
}
|
|
35862
|
+
} catch (fetchError) {
|
|
35863
|
+
const errorMessage = fetchError instanceof Error ? fetchError.message : "Unknown error";
|
|
35864
|
+
if (errorMessage.includes("Failed to fetch IPFS content") && errorMessage.includes("from all gateways")) {
|
|
35865
|
+
throw new Error(
|
|
35866
|
+
"Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
|
|
35867
|
+
);
|
|
35868
|
+
} else if (errorMessage.includes("Empty response")) {
|
|
35869
|
+
throw new Error("File is empty or could not be retrieved");
|
|
35870
|
+
} else if (errorMessage.includes("Network error:") || errorMessage.includes("Failed to fetch")) {
|
|
35871
|
+
throw new Error(
|
|
35872
|
+
"Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
|
|
35873
|
+
);
|
|
35874
|
+
} else if (errorMessage.includes("HTTP error!")) {
|
|
35875
|
+
const statusMatch = errorMessage.match(/status: (\d+)/);
|
|
35876
|
+
const status = statusMatch ? statusMatch[1] : "unknown";
|
|
35877
|
+
if (status === "500") {
|
|
35878
|
+
throw new Error(
|
|
35879
|
+
"Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
|
|
35880
|
+
);
|
|
35881
|
+
} else if (status === "403") {
|
|
35882
|
+
throw new Error(
|
|
35883
|
+
"Access denied. You may not have permission to access this file"
|
|
35884
|
+
);
|
|
35885
|
+
} else if (status === "404") {
|
|
35886
|
+
throw new Error(
|
|
35887
|
+
"File not found: The encrypted file is no longer available at the stored URL."
|
|
35888
|
+
);
|
|
35889
|
+
} else {
|
|
35890
|
+
throw new Error(
|
|
35891
|
+
"Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
|
|
35892
|
+
);
|
|
35893
|
+
}
|
|
35894
|
+
}
|
|
35895
|
+
throw fetchError;
|
|
35896
|
+
}
|
|
35897
|
+
if (encryptedBlob.size === 0) {
|
|
35898
|
+
throw new Error("File is empty or could not be retrieved");
|
|
35899
|
+
}
|
|
35900
|
+
let decryptedBlob;
|
|
35901
|
+
try {
|
|
35902
|
+
decryptedBlob = await decryptBlobWithSignedKey(
|
|
35903
|
+
encryptedBlob,
|
|
35904
|
+
encryptionKey,
|
|
35905
|
+
this.context.platform
|
|
35906
|
+
);
|
|
35907
|
+
} catch (decryptError) {
|
|
35908
|
+
const errorMessage = decryptError instanceof Error ? decryptError.message : "Unknown error";
|
|
35909
|
+
if (errorMessage.includes("not a valid OpenPGP message")) {
|
|
35910
|
+
throw new Error(
|
|
35911
|
+
"Invalid file format: This file doesn't appear to be encrypted with the Vana protocol"
|
|
35912
|
+
);
|
|
35913
|
+
} else if (errorMessage.includes("Session key decryption failed")) {
|
|
35914
|
+
throw new Error("Wrong encryption key");
|
|
35915
|
+
} else if (errorMessage.includes("Error decrypting message")) {
|
|
35916
|
+
throw new Error("Wrong encryption key");
|
|
35917
|
+
} else if (errorMessage.includes("File not found")) {
|
|
35918
|
+
throw new Error(
|
|
35919
|
+
"File not found: The encrypted file is no longer available"
|
|
35920
|
+
);
|
|
35921
|
+
} else {
|
|
35922
|
+
throw decryptError;
|
|
35923
|
+
}
|
|
35924
|
+
}
|
|
35925
|
+
return decryptedBlob;
|
|
35926
|
+
} catch (error) {
|
|
35927
|
+
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"))) {
|
|
35928
|
+
throw error;
|
|
35929
|
+
}
|
|
35930
|
+
throw new Error(
|
|
35931
|
+
`Failed to decrypt file: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
35932
|
+
);
|
|
35933
|
+
}
|
|
35934
|
+
}
|
|
36412
35935
|
/**
|
|
36413
35936
|
* Retrieves all data files owned by a specific user address.
|
|
36414
35937
|
*
|
|
@@ -36992,6 +36515,7 @@ var DataController = class {
|
|
|
36992
36515
|
/**
|
|
36993
36516
|
* Uploads an encrypted file to storage and registers it on the blockchain.
|
|
36994
36517
|
*
|
|
36518
|
+
* @deprecated Use vana.data.upload() instead for the high-level API with automatic encryption
|
|
36995
36519
|
* @param encryptedFile - The encrypted file blob to upload
|
|
36996
36520
|
* @param filename - Optional filename for the upload
|
|
36997
36521
|
* @param providerName - Optional storage provider to use
|
|
@@ -37079,6 +36603,7 @@ var DataController = class {
|
|
|
37079
36603
|
/**
|
|
37080
36604
|
* Uploads an encrypted file to storage and registers it on the blockchain with a schema.
|
|
37081
36605
|
*
|
|
36606
|
+
* @deprecated Use vana.data.upload() instead for the high-level API with automatic encryption and schema validation
|
|
37082
36607
|
* @param encryptedFile - The encrypted file blob to upload
|
|
37083
36608
|
* @param schemaId - The schema ID to associate with the file
|
|
37084
36609
|
* @param filename - Optional filename for the upload
|
|
@@ -37157,81 +36682,6 @@ var DataController = class {
|
|
|
37157
36682
|
);
|
|
37158
36683
|
}
|
|
37159
36684
|
}
|
|
37160
|
-
/**
|
|
37161
|
-
* Decrypts a file that was encrypted using the Vana protocol.
|
|
37162
|
-
*
|
|
37163
|
-
* @param file - The UserFile object containing the file URL and metadata
|
|
37164
|
-
* @param encryptionSeed - Optional custom encryption seed (defaults to Vana standard)
|
|
37165
|
-
* @returns Promise resolving to the decrypted file as a Blob
|
|
37166
|
-
*
|
|
37167
|
-
* This method handles the complete flow of:
|
|
37168
|
-
* 1. Generating the encryption key from the user's wallet signature
|
|
37169
|
-
* 2. Fetching the encrypted file from the stored URL
|
|
37170
|
-
* 3. Decrypting the file using the canonical Vana decryption method
|
|
37171
|
-
*/
|
|
37172
|
-
async decryptFile(file, encryptionSeed = DEFAULT_ENCRYPTION_SEED) {
|
|
37173
|
-
try {
|
|
37174
|
-
const encryptionKey = await generateEncryptionKey(
|
|
37175
|
-
this.context.walletClient,
|
|
37176
|
-
encryptionSeed
|
|
37177
|
-
);
|
|
37178
|
-
const fetchUrl = this.convertToDownloadUrl(file.url);
|
|
37179
|
-
console.debug(
|
|
37180
|
-
`Fetching encrypted file from URL: ${fetchUrl} (original: ${file.url})`
|
|
37181
|
-
);
|
|
37182
|
-
const response = await fetch(fetchUrl);
|
|
37183
|
-
if (!response.ok) {
|
|
37184
|
-
if (response.status === 404) {
|
|
37185
|
-
throw new Error(
|
|
37186
|
-
"File not found. The encrypted file may have been moved or deleted."
|
|
37187
|
-
);
|
|
37188
|
-
} else if (response.status === 403) {
|
|
37189
|
-
throw new Error(
|
|
37190
|
-
"Access denied. You may not have permission to access this file."
|
|
37191
|
-
);
|
|
37192
|
-
} else {
|
|
37193
|
-
throw new Error(
|
|
37194
|
-
`Network error: ${response.status} ${response.statusText}`
|
|
37195
|
-
);
|
|
37196
|
-
}
|
|
37197
|
-
}
|
|
37198
|
-
const encryptedBlob = await response.blob();
|
|
37199
|
-
console.debug(
|
|
37200
|
-
`Retrieved blob of size: ${encryptedBlob.size} bytes, type: ${encryptedBlob.type}`
|
|
37201
|
-
);
|
|
37202
|
-
if (encryptedBlob.size === 0) {
|
|
37203
|
-
throw new Error("File is empty or could not be retrieved.");
|
|
37204
|
-
}
|
|
37205
|
-
const decryptedBlob = await decryptUserData(
|
|
37206
|
-
encryptedBlob,
|
|
37207
|
-
encryptionKey,
|
|
37208
|
-
this.context.platform
|
|
37209
|
-
);
|
|
37210
|
-
return decryptedBlob;
|
|
37211
|
-
} catch (error) {
|
|
37212
|
-
console.error("Failed to decrypt file:", error);
|
|
37213
|
-
if (error instanceof Error) {
|
|
37214
|
-
if (error.message.includes("Session key decryption failed") || error.message.includes("Error decrypting message")) {
|
|
37215
|
-
throw new Error(
|
|
37216
|
-
"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."
|
|
37217
|
-
);
|
|
37218
|
-
} else if (error.message.includes("Failed to fetch") || error.message.includes("Network error")) {
|
|
37219
|
-
throw new Error(
|
|
37220
|
-
"Network error: Cannot access the file URL. The file may be stored on a server that's not accessible or has CORS restrictions."
|
|
37221
|
-
);
|
|
37222
|
-
} else if (error.message.includes("File not found")) {
|
|
37223
|
-
throw new Error(
|
|
37224
|
-
"File not found: The encrypted file is no longer available at the stored URL."
|
|
37225
|
-
);
|
|
37226
|
-
} else if (error.message.includes("not a valid OpenPGP message") || error.message.includes("does not conform to a valid OpenPGP format")) {
|
|
37227
|
-
throw new Error(
|
|
37228
|
-
"Invalid file format: This file doesn't appear to be encrypted with the Vana protocol."
|
|
37229
|
-
);
|
|
37230
|
-
}
|
|
37231
|
-
}
|
|
37232
|
-
throw error;
|
|
37233
|
-
}
|
|
37234
|
-
}
|
|
37235
36685
|
/**
|
|
37236
36686
|
* Registers a file URL directly on the blockchain with a schema ID.
|
|
37237
36687
|
*
|
|
@@ -37292,26 +36742,6 @@ var DataController = class {
|
|
|
37292
36742
|
);
|
|
37293
36743
|
}
|
|
37294
36744
|
}
|
|
37295
|
-
/**
|
|
37296
|
-
* Converts IPFS and Google Drive URLs to direct download URLs for fetching.
|
|
37297
|
-
*
|
|
37298
|
-
* @param url - The URL to convert to a direct download URL
|
|
37299
|
-
* @returns The converted direct download URL or the original URL if not a special URL
|
|
37300
|
-
*/
|
|
37301
|
-
convertToDownloadUrl(url) {
|
|
37302
|
-
if (url.startsWith("ipfs://")) {
|
|
37303
|
-
const hash = url.replace("ipfs://", "");
|
|
37304
|
-
return `https://ipfs.io/ipfs/${hash}`;
|
|
37305
|
-
}
|
|
37306
|
-
if (url.includes("drive.google.com/file/d/")) {
|
|
37307
|
-
const fileIdMatch = url.match(/\/file\/d\/([a-zA-Z0-9-_]+)/);
|
|
37308
|
-
if (fileIdMatch) {
|
|
37309
|
-
const fileId = fileIdMatch[1];
|
|
37310
|
-
return `https://drive.google.com/uc?id=${fileId}&export=download`;
|
|
37311
|
-
}
|
|
37312
|
-
}
|
|
37313
|
-
return url;
|
|
37314
|
-
}
|
|
37315
36745
|
/**
|
|
37316
36746
|
* Gets the user's address from the wallet client.
|
|
37317
36747
|
*
|
|
@@ -37386,9 +36816,70 @@ var DataController = class {
|
|
|
37386
36816
|
);
|
|
37387
36817
|
}
|
|
37388
36818
|
}
|
|
36819
|
+
/**
|
|
36820
|
+
* Adds a file to the registry with permissions and schema.
|
|
36821
|
+
* This combines the functionality of addFileWithPermissions and schema validation.
|
|
36822
|
+
*
|
|
36823
|
+
* @param url - The URL of the file to register
|
|
36824
|
+
* @param ownerAddress - The address of the file owner
|
|
36825
|
+
* @param permissions - Array of permissions to grant (account and encrypted key)
|
|
36826
|
+
* @param schemaId - The schema ID to associate with the file (0 for no schema)
|
|
36827
|
+
* @returns Promise resolving to object with fileId and transactionHash
|
|
36828
|
+
*/
|
|
36829
|
+
async addFileWithPermissionsAndSchema(url, ownerAddress, permissions = [], schemaId = 0) {
|
|
36830
|
+
try {
|
|
36831
|
+
const chainId = this.context.walletClient.chain?.id;
|
|
36832
|
+
if (!chainId) {
|
|
36833
|
+
throw new Error("Chain ID not available");
|
|
36834
|
+
}
|
|
36835
|
+
const dataRegistryAddress = getContractAddress(chainId, "DataRegistry");
|
|
36836
|
+
const dataRegistryAbi = getAbi("DataRegistry");
|
|
36837
|
+
const txHash = await this.context.walletClient.writeContract({
|
|
36838
|
+
address: dataRegistryAddress,
|
|
36839
|
+
abi: dataRegistryAbi,
|
|
36840
|
+
functionName: "addFileWithPermissionsAndSchema",
|
|
36841
|
+
args: [url, ownerAddress, permissions, BigInt(schemaId)],
|
|
36842
|
+
account: this.context.walletClient.account || ownerAddress,
|
|
36843
|
+
chain: this.context.walletClient.chain || null
|
|
36844
|
+
});
|
|
36845
|
+
const receipt = await this.context.publicClient.waitForTransactionReceipt(
|
|
36846
|
+
{
|
|
36847
|
+
hash: txHash,
|
|
36848
|
+
timeout: 3e4
|
|
36849
|
+
// 30 seconds timeout
|
|
36850
|
+
}
|
|
36851
|
+
);
|
|
36852
|
+
let fileId = 0;
|
|
36853
|
+
for (const log of receipt.logs) {
|
|
36854
|
+
try {
|
|
36855
|
+
const decoded = (0, import_viem2.decodeEventLog)({
|
|
36856
|
+
abi: dataRegistryAbi,
|
|
36857
|
+
data: log.data,
|
|
36858
|
+
topics: log.topics
|
|
36859
|
+
});
|
|
36860
|
+
if (decoded.eventName === "FileAdded") {
|
|
36861
|
+
fileId = Number(decoded.args.fileId);
|
|
36862
|
+
break;
|
|
36863
|
+
}
|
|
36864
|
+
} catch {
|
|
36865
|
+
continue;
|
|
36866
|
+
}
|
|
36867
|
+
}
|
|
36868
|
+
return {
|
|
36869
|
+
fileId,
|
|
36870
|
+
transactionHash: txHash
|
|
36871
|
+
};
|
|
36872
|
+
} catch (error) {
|
|
36873
|
+
console.error("Failed to add file with permissions and schema:", error);
|
|
36874
|
+
throw new Error(
|
|
36875
|
+
`Failed to add file with permissions and schema: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
36876
|
+
);
|
|
36877
|
+
}
|
|
36878
|
+
}
|
|
37389
36879
|
/**
|
|
37390
36880
|
* Adds a new schema to the DataRefinerRegistry.
|
|
37391
36881
|
*
|
|
36882
|
+
* @deprecated Use vana.schemas.create() instead for the high-level API with automatic IPFS upload
|
|
37392
36883
|
* @param params - Schema parameters including name, type, and definition URL
|
|
37393
36884
|
* @returns Promise resolving to the new schema ID and transaction hash
|
|
37394
36885
|
*/
|
|
@@ -37447,6 +36938,7 @@ var DataController = class {
|
|
|
37447
36938
|
/**
|
|
37448
36939
|
* Retrieves a schema by its ID.
|
|
37449
36940
|
*
|
|
36941
|
+
* @deprecated Use vana.schemas.get() instead
|
|
37450
36942
|
* @param schemaId - The schema ID to retrieve
|
|
37451
36943
|
* @returns Promise resolving to the schema information
|
|
37452
36944
|
*/
|
|
@@ -37472,11 +36964,15 @@ var DataController = class {
|
|
|
37472
36964
|
if (!schemaData) {
|
|
37473
36965
|
throw new Error("Schema not found");
|
|
37474
36966
|
}
|
|
36967
|
+
const schemaObj = schemaData;
|
|
36968
|
+
if (!schemaObj.name || !schemaObj.typ || !schemaObj.definitionUrl) {
|
|
36969
|
+
throw new Error("Incomplete schema data");
|
|
36970
|
+
}
|
|
37475
36971
|
return {
|
|
37476
36972
|
id: schemaId,
|
|
37477
|
-
name:
|
|
37478
|
-
type:
|
|
37479
|
-
definitionUrl:
|
|
36973
|
+
name: schemaObj.name,
|
|
36974
|
+
type: schemaObj.typ,
|
|
36975
|
+
definitionUrl: schemaObj.definitionUrl
|
|
37480
36976
|
};
|
|
37481
36977
|
} catch (error) {
|
|
37482
36978
|
console.error("Failed to get schema:", error);
|
|
@@ -37488,6 +36984,7 @@ var DataController = class {
|
|
|
37488
36984
|
/**
|
|
37489
36985
|
* Gets the total number of schemas in the registry.
|
|
37490
36986
|
*
|
|
36987
|
+
* @deprecated Use vana.schemas.count() instead
|
|
37491
36988
|
* @returns Promise resolving to the total schema count
|
|
37492
36989
|
*/
|
|
37493
36990
|
async getSchemasCount() {
|
|
@@ -37533,7 +37030,7 @@ var DataController = class {
|
|
|
37533
37030
|
const txHash = await this.context.walletClient.writeContract({
|
|
37534
37031
|
address: dataRefinerRegistryAddress,
|
|
37535
37032
|
abi: dataRefinerRegistryAbi,
|
|
37536
|
-
functionName: "
|
|
37033
|
+
functionName: "addRefinerWithSchemaId",
|
|
37537
37034
|
args: [
|
|
37538
37035
|
BigInt(params.dlpId),
|
|
37539
37036
|
params.name,
|
|
@@ -37738,7 +37235,7 @@ var DataController = class {
|
|
|
37738
37235
|
this.context.walletClient,
|
|
37739
37236
|
DEFAULT_ENCRYPTION_SEED
|
|
37740
37237
|
);
|
|
37741
|
-
const encryptedData = await
|
|
37238
|
+
const encryptedData = await encryptBlobWithSignedKey(
|
|
37742
37239
|
data,
|
|
37743
37240
|
userEncryptionKey,
|
|
37744
37241
|
this.context.platform
|
|
@@ -37872,25 +37369,6 @@ var DataController = class {
|
|
|
37872
37369
|
);
|
|
37873
37370
|
}
|
|
37874
37371
|
}
|
|
37875
|
-
/**
|
|
37876
|
-
* Gets the trusted server public key for a given server address.
|
|
37877
|
-
* This method reads from the permissions contract to find servers and their public keys.
|
|
37878
|
-
*
|
|
37879
|
-
* @param serverAddress - The address of the trusted server
|
|
37880
|
-
* @returns Promise resolving to the server's public key
|
|
37881
|
-
*/
|
|
37882
|
-
async getTrustedServerPublicKey(serverAddress) {
|
|
37883
|
-
try {
|
|
37884
|
-
return await this.serverController.getTrustedServerPublicKey(
|
|
37885
|
-
serverAddress
|
|
37886
|
-
);
|
|
37887
|
-
} catch (error) {
|
|
37888
|
-
console.error("Failed to get trusted server public key:", error);
|
|
37889
|
-
throw new Error(
|
|
37890
|
-
`Failed to get trusted server public key: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
37891
|
-
);
|
|
37892
|
-
}
|
|
37893
|
-
}
|
|
37894
37372
|
/**
|
|
37895
37373
|
* Decrypts a file that the user has permission to access using their private key.
|
|
37896
37374
|
*
|
|
@@ -37921,12 +37399,13 @@ var DataController = class {
|
|
|
37921
37399
|
privateKey,
|
|
37922
37400
|
this.context.platform
|
|
37923
37401
|
);
|
|
37924
|
-
|
|
37925
|
-
if (
|
|
37926
|
-
|
|
37402
|
+
let encryptedData;
|
|
37403
|
+
if (file.url.startsWith("ipfs://")) {
|
|
37404
|
+
encryptedData = await this.fetchFromIPFS(file.url);
|
|
37405
|
+
} else {
|
|
37406
|
+
encryptedData = await this.fetch(file.url);
|
|
37927
37407
|
}
|
|
37928
|
-
const
|
|
37929
|
-
const decryptedData = await decryptUserData(
|
|
37408
|
+
const decryptedData = await decryptBlobWithSignedKey(
|
|
37930
37409
|
encryptedData,
|
|
37931
37410
|
userEncryptionKey,
|
|
37932
37411
|
this.context.platform
|
|
@@ -37939,6 +37418,162 @@ var DataController = class {
|
|
|
37939
37418
|
);
|
|
37940
37419
|
}
|
|
37941
37420
|
}
|
|
37421
|
+
/**
|
|
37422
|
+
* Simple network-agnostic fetch utility for retrieving file content.
|
|
37423
|
+
*
|
|
37424
|
+
* @remarks
|
|
37425
|
+
* This is a thin wrapper around the global fetch API that returns the response as a Blob.
|
|
37426
|
+
* It provides a consistent interface for fetching encrypted content before decryption.
|
|
37427
|
+
* For IPFS URLs, consider using fetchFromIPFS for better reliability.
|
|
37428
|
+
*
|
|
37429
|
+
* @param url - The URL to fetch content from
|
|
37430
|
+
* @returns Promise resolving to the fetched content as a Blob
|
|
37431
|
+
* @throws {Error} When the fetch fails or returns a non-ok response
|
|
37432
|
+
*
|
|
37433
|
+
* @example
|
|
37434
|
+
* ```typescript
|
|
37435
|
+
* // Fetch and decrypt a file
|
|
37436
|
+
* const encryptionKey = await generateEncryptionKey(walletClient);
|
|
37437
|
+
* const encryptedBlob = await vana.data.fetch(file.url);
|
|
37438
|
+
* const decryptedBlob = await decryptBlob(encryptedBlob, encryptionKey, platform);
|
|
37439
|
+
*
|
|
37440
|
+
* // With custom headers for authentication
|
|
37441
|
+
* const response = await fetch(file.url, {
|
|
37442
|
+
* headers: { 'Authorization': 'Bearer token' }
|
|
37443
|
+
* });
|
|
37444
|
+
* const encryptedBlob = await response.blob();
|
|
37445
|
+
* ```
|
|
37446
|
+
*/
|
|
37447
|
+
async fetch(url) {
|
|
37448
|
+
try {
|
|
37449
|
+
const response = await fetch(url);
|
|
37450
|
+
if (!response.ok) {
|
|
37451
|
+
throw new Error(
|
|
37452
|
+
`HTTP error! status: ${response.status} ${response.statusText}`
|
|
37453
|
+
);
|
|
37454
|
+
}
|
|
37455
|
+
const blob = await response.blob();
|
|
37456
|
+
if (blob.size === 0) {
|
|
37457
|
+
throw new Error("Empty response");
|
|
37458
|
+
}
|
|
37459
|
+
return blob;
|
|
37460
|
+
} catch (error) {
|
|
37461
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
37462
|
+
throw new Error(
|
|
37463
|
+
`Network error: Failed to fetch from ${url}. The URL may be invalid or the server may not be accessible.`
|
|
37464
|
+
);
|
|
37465
|
+
}
|
|
37466
|
+
throw error;
|
|
37467
|
+
}
|
|
37468
|
+
}
|
|
37469
|
+
/**
|
|
37470
|
+
* Specialized IPFS fetcher with gateway fallback mechanism.
|
|
37471
|
+
*
|
|
37472
|
+
* @remarks
|
|
37473
|
+
* This method provides robust IPFS content fetching by trying multiple gateways
|
|
37474
|
+
* in sequence until one succeeds. It supports both ipfs:// URLs and raw CIDs.
|
|
37475
|
+
*
|
|
37476
|
+
* The default gateway list includes public gateways, but you should provide
|
|
37477
|
+
* your own gateways for production use to ensure reliability and privacy.
|
|
37478
|
+
*
|
|
37479
|
+
* @param url - The IPFS URL (ipfs://...) or CID to fetch
|
|
37480
|
+
* @param options - Optional configuration
|
|
37481
|
+
* @param options.gateways - Array of IPFS gateway URLs to try (must end with /)
|
|
37482
|
+
* @returns Promise resolving to the fetched content as a Blob
|
|
37483
|
+
* @throws {Error} When all gateways fail to fetch the content
|
|
37484
|
+
*
|
|
37485
|
+
* @example
|
|
37486
|
+
* ```typescript
|
|
37487
|
+
* // Fetch from IPFS with custom gateways
|
|
37488
|
+
* const encryptedBlob = await vana.data.fetchFromIPFS(file.url, {
|
|
37489
|
+
* gateways: [
|
|
37490
|
+
* 'https://my-private-gateway.com/ipfs/',
|
|
37491
|
+
* 'https://dweb.link/ipfs/',
|
|
37492
|
+
* 'https://ipfs.io/ipfs/'
|
|
37493
|
+
* ]
|
|
37494
|
+
* });
|
|
37495
|
+
*
|
|
37496
|
+
* // Decrypt the fetched content
|
|
37497
|
+
* const encryptionKey = await generateEncryptionKey(walletClient);
|
|
37498
|
+
* const decryptedBlob = await decryptBlob(encryptedBlob, encryptionKey, platform);
|
|
37499
|
+
*
|
|
37500
|
+
* // With raw CID
|
|
37501
|
+
* const blob = await vana.data.fetchFromIPFS('QmXxx...', {
|
|
37502
|
+
* gateways: ['https://ipfs.io/ipfs/']
|
|
37503
|
+
* });
|
|
37504
|
+
* ```
|
|
37505
|
+
*/
|
|
37506
|
+
async fetchFromIPFS(url, options) {
|
|
37507
|
+
const defaultGateways = [
|
|
37508
|
+
"https://dweb.link/ipfs/",
|
|
37509
|
+
"https://ipfs.io/ipfs/"
|
|
37510
|
+
];
|
|
37511
|
+
const gateways = options?.gateways || this.context.ipfsGateways || defaultGateways;
|
|
37512
|
+
let cid;
|
|
37513
|
+
if (url.startsWith("ipfs://")) {
|
|
37514
|
+
cid = url.replace("ipfs://", "");
|
|
37515
|
+
} else if (url.startsWith("Qm") || url.startsWith("bafy")) {
|
|
37516
|
+
cid = url;
|
|
37517
|
+
} else {
|
|
37518
|
+
throw new Error(
|
|
37519
|
+
`Invalid IPFS URL format. Expected ipfs://... or a raw CID, got: ${url}`
|
|
37520
|
+
);
|
|
37521
|
+
}
|
|
37522
|
+
const errors = [];
|
|
37523
|
+
for (let i = 0; i < gateways.length; i++) {
|
|
37524
|
+
const gateway = gateways[i];
|
|
37525
|
+
const isLastGateway = i === gateways.length - 1;
|
|
37526
|
+
const gatewayUrl = gateway.endsWith("/") ? `${gateway}${cid}` : `${gateway}/${cid}`;
|
|
37527
|
+
try {
|
|
37528
|
+
console.debug(`Trying IPFS gateway: ${gatewayUrl}`);
|
|
37529
|
+
const response = await fetch(gatewayUrl);
|
|
37530
|
+
if (response.ok) {
|
|
37531
|
+
const blob = await response.blob();
|
|
37532
|
+
if (blob.size > 0) {
|
|
37533
|
+
console.debug(`Successfully fetched from gateway: ${gateway}`);
|
|
37534
|
+
return blob;
|
|
37535
|
+
} else {
|
|
37536
|
+
if (isLastGateway) {
|
|
37537
|
+
throw new Error("Empty response");
|
|
37538
|
+
}
|
|
37539
|
+
errors.push({
|
|
37540
|
+
gateway,
|
|
37541
|
+
error: "Empty response"
|
|
37542
|
+
});
|
|
37543
|
+
}
|
|
37544
|
+
} else {
|
|
37545
|
+
if (isLastGateway) {
|
|
37546
|
+
if (response.status === 403) {
|
|
37547
|
+
throw new Error(`HTTP error! status: 403 ${response.statusText}`);
|
|
37548
|
+
} else if (response.status === 404) {
|
|
37549
|
+
throw new Error(`HTTP error! status: 404 ${response.statusText}`);
|
|
37550
|
+
} else {
|
|
37551
|
+
throw new Error(
|
|
37552
|
+
`HTTP error! status: ${response.status} ${response.statusText}`
|
|
37553
|
+
);
|
|
37554
|
+
}
|
|
37555
|
+
}
|
|
37556
|
+
errors.push({
|
|
37557
|
+
gateway,
|
|
37558
|
+
error: `HTTP ${response.status} ${response.statusText}`
|
|
37559
|
+
});
|
|
37560
|
+
}
|
|
37561
|
+
} catch (error) {
|
|
37562
|
+
if (isLastGateway && error instanceof Error && (error.message.includes("Empty response") || error.message.includes("HTTP error!"))) {
|
|
37563
|
+
throw error;
|
|
37564
|
+
}
|
|
37565
|
+
errors.push({
|
|
37566
|
+
gateway,
|
|
37567
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
37568
|
+
});
|
|
37569
|
+
}
|
|
37570
|
+
}
|
|
37571
|
+
const errorDetails = errors.map((e) => `${e.gateway}: ${e.error}`).join("\n ");
|
|
37572
|
+
throw new Error(
|
|
37573
|
+
`Failed to fetch IPFS content ${cid} from all gateways:
|
|
37574
|
+
${errorDetails}`
|
|
37575
|
+
);
|
|
37576
|
+
}
|
|
37942
37577
|
/**
|
|
37943
37578
|
* Validates a data schema against the Vana meta-schema.
|
|
37944
37579
|
*
|
|
@@ -38060,15 +37695,595 @@ var DataController = class {
|
|
|
38060
37695
|
}
|
|
38061
37696
|
};
|
|
38062
37697
|
|
|
37698
|
+
// src/controllers/schemas.ts
|
|
37699
|
+
var import_viem3 = require("viem");
|
|
37700
|
+
var SchemaController = class {
|
|
37701
|
+
constructor(context) {
|
|
37702
|
+
this.context = context;
|
|
37703
|
+
}
|
|
37704
|
+
/**
|
|
37705
|
+
* Creates a new schema with automatic validation and IPFS upload.
|
|
37706
|
+
*
|
|
37707
|
+
* @remarks
|
|
37708
|
+
* This is the primary method for creating schemas on the Vana network. It handles
|
|
37709
|
+
* the complete workflow including schema validation, IPFS upload, and blockchain
|
|
37710
|
+
* registration. The schema definition is stored unencrypted on IPFS to enable
|
|
37711
|
+
* public access and reusability.
|
|
37712
|
+
*
|
|
37713
|
+
* The method automatically:
|
|
37714
|
+
* - Validates the schema definition against the Vana metaschema
|
|
37715
|
+
* - Uploads the definition to IPFS to generate a permanent URL
|
|
37716
|
+
* - Registers the schema on the blockchain with the generated URL
|
|
37717
|
+
*
|
|
37718
|
+
* @param params - Schema creation parameters including name, type, and definition
|
|
37719
|
+
* @returns Promise resolving to creation results with schema ID and transaction hash
|
|
37720
|
+
* @throws {SchemaValidationError} When the schema definition is invalid
|
|
37721
|
+
* @throws {Error} When IPFS upload or blockchain registration fails
|
|
37722
|
+
* @example
|
|
37723
|
+
* ```typescript
|
|
37724
|
+
* // Create a JSON schema for user profiles
|
|
37725
|
+
* const result = await vana.schemas.create({
|
|
37726
|
+
* name: "User Profile",
|
|
37727
|
+
* type: "personal",
|
|
37728
|
+
* definition: {
|
|
37729
|
+
* type: "object",
|
|
37730
|
+
* properties: {
|
|
37731
|
+
* name: { type: "string" },
|
|
37732
|
+
* age: { type: "number", minimum: 0 }
|
|
37733
|
+
* },
|
|
37734
|
+
* required: ["name"]
|
|
37735
|
+
* }
|
|
37736
|
+
* });
|
|
37737
|
+
*
|
|
37738
|
+
* console.log(`Schema created with ID: ${result.schemaId}`);
|
|
37739
|
+
* ```
|
|
37740
|
+
*/
|
|
37741
|
+
async create(params) {
|
|
37742
|
+
const { name, type, definition } = params;
|
|
37743
|
+
try {
|
|
37744
|
+
let schemaDefinition;
|
|
37745
|
+
if (typeof definition === "string") {
|
|
37746
|
+
try {
|
|
37747
|
+
schemaDefinition = JSON.parse(definition);
|
|
37748
|
+
} catch {
|
|
37749
|
+
throw new SchemaValidationError(
|
|
37750
|
+
"Invalid JSON in schema definition",
|
|
37751
|
+
[]
|
|
37752
|
+
);
|
|
37753
|
+
}
|
|
37754
|
+
} else {
|
|
37755
|
+
schemaDefinition = definition;
|
|
37756
|
+
}
|
|
37757
|
+
const dataSchema = {
|
|
37758
|
+
name,
|
|
37759
|
+
version: "1.0.0",
|
|
37760
|
+
dialect: "json",
|
|
37761
|
+
schema: schemaDefinition
|
|
37762
|
+
};
|
|
37763
|
+
validateDataSchema(dataSchema);
|
|
37764
|
+
if (!this.context.storageManager) {
|
|
37765
|
+
if (this.context.validateStorageRequired) {
|
|
37766
|
+
this.context.validateStorageRequired();
|
|
37767
|
+
throw new Error("Storage validation failed");
|
|
37768
|
+
} else {
|
|
37769
|
+
throw new Error(
|
|
37770
|
+
"Storage manager not configured. Please provide storage providers in VanaConfig."
|
|
37771
|
+
);
|
|
37772
|
+
}
|
|
37773
|
+
}
|
|
37774
|
+
const schemaBlob = new Blob([JSON.stringify(schemaDefinition)], {
|
|
37775
|
+
type: "application/json"
|
|
37776
|
+
});
|
|
37777
|
+
const uploadResult = await this.context.storageManager.upload(
|
|
37778
|
+
schemaBlob,
|
|
37779
|
+
`${name.replace(/[^a-zA-Z0-9]/g, "_")}.json`,
|
|
37780
|
+
"ipfs"
|
|
37781
|
+
// Use IPFS for public schema storage
|
|
37782
|
+
);
|
|
37783
|
+
const chainId = this.context.walletClient.chain?.id;
|
|
37784
|
+
if (!chainId) {
|
|
37785
|
+
throw new Error("Chain ID not available");
|
|
37786
|
+
}
|
|
37787
|
+
const dataRefinerRegistryAddress = getContractAddress(
|
|
37788
|
+
chainId,
|
|
37789
|
+
"DataRefinerRegistry"
|
|
37790
|
+
);
|
|
37791
|
+
const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
|
|
37792
|
+
const userAddress = await this.getUserAddress();
|
|
37793
|
+
const txHash = await this.context.walletClient.writeContract({
|
|
37794
|
+
address: dataRefinerRegistryAddress,
|
|
37795
|
+
abi: dataRefinerRegistryAbi,
|
|
37796
|
+
functionName: "addSchema",
|
|
37797
|
+
args: [name, type, uploadResult.url],
|
|
37798
|
+
account: this.context.walletClient.account || userAddress,
|
|
37799
|
+
chain: this.context.walletClient.chain || null
|
|
37800
|
+
});
|
|
37801
|
+
const receipt = await this.context.publicClient.waitForTransactionReceipt(
|
|
37802
|
+
{
|
|
37803
|
+
hash: txHash,
|
|
37804
|
+
timeout: 3e4
|
|
37805
|
+
// 30 seconds timeout
|
|
37806
|
+
}
|
|
37807
|
+
);
|
|
37808
|
+
let schemaId = 0;
|
|
37809
|
+
for (const log of receipt.logs) {
|
|
37810
|
+
try {
|
|
37811
|
+
const decoded = (0, import_viem3.decodeEventLog)({
|
|
37812
|
+
abi: dataRefinerRegistryAbi,
|
|
37813
|
+
data: log.data,
|
|
37814
|
+
topics: log.topics
|
|
37815
|
+
});
|
|
37816
|
+
if (decoded.eventName === "SchemaAdded") {
|
|
37817
|
+
schemaId = Number(decoded.args.schemaId);
|
|
37818
|
+
break;
|
|
37819
|
+
}
|
|
37820
|
+
} catch {
|
|
37821
|
+
}
|
|
37822
|
+
}
|
|
37823
|
+
return {
|
|
37824
|
+
schemaId,
|
|
37825
|
+
definitionUrl: uploadResult.url,
|
|
37826
|
+
transactionHash: txHash
|
|
37827
|
+
};
|
|
37828
|
+
} catch (error) {
|
|
37829
|
+
if (error instanceof SchemaValidationError) {
|
|
37830
|
+
throw error;
|
|
37831
|
+
}
|
|
37832
|
+
throw new Error(
|
|
37833
|
+
`Schema creation failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
37834
|
+
);
|
|
37835
|
+
}
|
|
37836
|
+
}
|
|
37837
|
+
/**
|
|
37838
|
+
* Retrieves a schema by its ID.
|
|
37839
|
+
*
|
|
37840
|
+
* @param schemaId - The ID of the schema to retrieve
|
|
37841
|
+
* @returns Promise resolving to the schema object
|
|
37842
|
+
* @throws {Error} When the schema is not found or chain is unavailable
|
|
37843
|
+
* @example
|
|
37844
|
+
* ```typescript
|
|
37845
|
+
* const schema = await vana.schemas.get(1);
|
|
37846
|
+
* console.log(`Schema: ${schema.name} (${schema.type})`);
|
|
37847
|
+
* ```
|
|
37848
|
+
*/
|
|
37849
|
+
async get(schemaId) {
|
|
37850
|
+
try {
|
|
37851
|
+
const chainId = this.context.walletClient.chain?.id;
|
|
37852
|
+
if (!chainId) {
|
|
37853
|
+
throw new Error("Chain ID not available");
|
|
37854
|
+
}
|
|
37855
|
+
const dataRefinerRegistryAddress = getContractAddress(
|
|
37856
|
+
chainId,
|
|
37857
|
+
"DataRefinerRegistry"
|
|
37858
|
+
);
|
|
37859
|
+
const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
|
|
37860
|
+
const dataRefinerRegistry = (0, import_viem3.getContract)({
|
|
37861
|
+
address: dataRefinerRegistryAddress,
|
|
37862
|
+
abi: dataRefinerRegistryAbi,
|
|
37863
|
+
client: this.context.publicClient
|
|
37864
|
+
});
|
|
37865
|
+
const schemaData = await dataRefinerRegistry.read.schemas([
|
|
37866
|
+
BigInt(schemaId)
|
|
37867
|
+
]);
|
|
37868
|
+
if (!schemaData) {
|
|
37869
|
+
throw new Error(`Schema with ID ${schemaId} not found`);
|
|
37870
|
+
}
|
|
37871
|
+
const schemaObj = schemaData;
|
|
37872
|
+
if (!schemaObj.name || !schemaObj.typ || !schemaObj.definitionUrl) {
|
|
37873
|
+
throw new Error("Incomplete schema data");
|
|
37874
|
+
}
|
|
37875
|
+
return {
|
|
37876
|
+
id: schemaId,
|
|
37877
|
+
name: schemaObj.name,
|
|
37878
|
+
type: schemaObj.typ,
|
|
37879
|
+
definitionUrl: schemaObj.definitionUrl
|
|
37880
|
+
};
|
|
37881
|
+
} catch (error) {
|
|
37882
|
+
throw new Error(
|
|
37883
|
+
`Failed to get schema: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
37884
|
+
);
|
|
37885
|
+
}
|
|
37886
|
+
}
|
|
37887
|
+
/**
|
|
37888
|
+
* Gets the total number of schemas registered on the network.
|
|
37889
|
+
*
|
|
37890
|
+
* @returns Promise resolving to the total schema count
|
|
37891
|
+
* @throws {Error} When the count cannot be retrieved
|
|
37892
|
+
* @example
|
|
37893
|
+
* ```typescript
|
|
37894
|
+
* const count = await vana.schemas.count();
|
|
37895
|
+
* console.log(`Total schemas: ${count}`);
|
|
37896
|
+
* ```
|
|
37897
|
+
*/
|
|
37898
|
+
async count() {
|
|
37899
|
+
try {
|
|
37900
|
+
const chainId = this.context.walletClient.chain?.id;
|
|
37901
|
+
if (!chainId) {
|
|
37902
|
+
throw new Error("Chain ID not available");
|
|
37903
|
+
}
|
|
37904
|
+
const dataRefinerRegistryAddress = getContractAddress(
|
|
37905
|
+
chainId,
|
|
37906
|
+
"DataRefinerRegistry"
|
|
37907
|
+
);
|
|
37908
|
+
const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
|
|
37909
|
+
const dataRefinerRegistry = (0, import_viem3.getContract)({
|
|
37910
|
+
address: dataRefinerRegistryAddress,
|
|
37911
|
+
abi: dataRefinerRegistryAbi,
|
|
37912
|
+
client: this.context.publicClient
|
|
37913
|
+
});
|
|
37914
|
+
const count = await dataRefinerRegistry.read.schemasCount();
|
|
37915
|
+
return Number(count);
|
|
37916
|
+
} catch (error) {
|
|
37917
|
+
throw new Error(
|
|
37918
|
+
`Failed to get schemas count: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
37919
|
+
);
|
|
37920
|
+
}
|
|
37921
|
+
}
|
|
37922
|
+
/**
|
|
37923
|
+
* Lists all schemas with pagination.
|
|
37924
|
+
*
|
|
37925
|
+
* @param options - Optional parameters for listing schemas
|
|
37926
|
+
* @param options.limit - Maximum number of schemas to return
|
|
37927
|
+
* @param options.offset - Number of schemas to skip
|
|
37928
|
+
* @returns Promise resolving to an array of schemas
|
|
37929
|
+
* @example
|
|
37930
|
+
* ```typescript
|
|
37931
|
+
* // Get all schemas
|
|
37932
|
+
* const schemas = await vana.schemas.list();
|
|
37933
|
+
*
|
|
37934
|
+
* // Get schemas with pagination
|
|
37935
|
+
* const schemas = await vana.schemas.list({ limit: 10, offset: 0 });
|
|
37936
|
+
* ```
|
|
37937
|
+
*/
|
|
37938
|
+
async list(options = {}) {
|
|
37939
|
+
const { limit = 100, offset = 0 } = options;
|
|
37940
|
+
try {
|
|
37941
|
+
const totalCount = await this.count();
|
|
37942
|
+
const schemas = [];
|
|
37943
|
+
const start = offset;
|
|
37944
|
+
const end = Math.min(start + limit, totalCount);
|
|
37945
|
+
for (let i = start; i < end; i++) {
|
|
37946
|
+
try {
|
|
37947
|
+
const schema = await this.get(i + 1);
|
|
37948
|
+
schemas.push(schema);
|
|
37949
|
+
} catch (error) {
|
|
37950
|
+
console.warn(`Failed to retrieve schema ${i + 1}:`, error);
|
|
37951
|
+
}
|
|
37952
|
+
}
|
|
37953
|
+
return schemas;
|
|
37954
|
+
} catch (error) {
|
|
37955
|
+
throw new Error(
|
|
37956
|
+
`Failed to list schemas: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
37957
|
+
);
|
|
37958
|
+
}
|
|
37959
|
+
}
|
|
37960
|
+
/**
|
|
37961
|
+
* Adds a schema using the legacy method (low-level API).
|
|
37962
|
+
*
|
|
37963
|
+
* @deprecated Use create() instead for the high-level API with automatic IPFS upload
|
|
37964
|
+
* @param params - Schema parameters including pre-generated definition URL
|
|
37965
|
+
* @returns Promise resolving to the add schema result
|
|
37966
|
+
*/
|
|
37967
|
+
async addSchema(params) {
|
|
37968
|
+
try {
|
|
37969
|
+
const chainId = this.context.walletClient.chain?.id;
|
|
37970
|
+
if (!chainId) {
|
|
37971
|
+
throw new Error("Chain ID not available");
|
|
37972
|
+
}
|
|
37973
|
+
const dataRefinerRegistryAddress = getContractAddress(
|
|
37974
|
+
chainId,
|
|
37975
|
+
"DataRefinerRegistry"
|
|
37976
|
+
);
|
|
37977
|
+
const dataRefinerRegistryAbi = getAbi("DataRefinerRegistry");
|
|
37978
|
+
const userAddress = await this.getUserAddress();
|
|
37979
|
+
const txHash = await this.context.walletClient.writeContract({
|
|
37980
|
+
address: dataRefinerRegistryAddress,
|
|
37981
|
+
abi: dataRefinerRegistryAbi,
|
|
37982
|
+
functionName: "addSchema",
|
|
37983
|
+
args: [params.name, params.type, params.definitionUrl],
|
|
37984
|
+
account: this.context.walletClient.account || userAddress,
|
|
37985
|
+
chain: this.context.walletClient.chain || null
|
|
37986
|
+
});
|
|
37987
|
+
return {
|
|
37988
|
+
schemaId: 0,
|
|
37989
|
+
// TODO: Parse from transaction receipt
|
|
37990
|
+
transactionHash: txHash
|
|
37991
|
+
};
|
|
37992
|
+
} catch (error) {
|
|
37993
|
+
throw new Error(
|
|
37994
|
+
`Failed to add schema: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
37995
|
+
);
|
|
37996
|
+
}
|
|
37997
|
+
}
|
|
37998
|
+
/**
|
|
37999
|
+
* Gets the user's wallet address.
|
|
38000
|
+
*
|
|
38001
|
+
* @private
|
|
38002
|
+
* @returns Promise resolving to the user's address
|
|
38003
|
+
*/
|
|
38004
|
+
async getUserAddress() {
|
|
38005
|
+
if (!this.context.walletClient.account) {
|
|
38006
|
+
throw new Error("No wallet account connected");
|
|
38007
|
+
}
|
|
38008
|
+
if (typeof this.context.walletClient.account === "string") {
|
|
38009
|
+
return this.context.walletClient.account;
|
|
38010
|
+
}
|
|
38011
|
+
if (typeof this.context.walletClient.account === "object" && this.context.walletClient.account.address) {
|
|
38012
|
+
return this.context.walletClient.account.address;
|
|
38013
|
+
}
|
|
38014
|
+
throw new Error("Unable to determine wallet address");
|
|
38015
|
+
}
|
|
38016
|
+
};
|
|
38017
|
+
|
|
38018
|
+
// src/controllers/server.ts
|
|
38019
|
+
var ServerController = class {
|
|
38020
|
+
constructor(context) {
|
|
38021
|
+
this.context = context;
|
|
38022
|
+
}
|
|
38023
|
+
PERSONAL_SERVER_BASE_URL = process.env.NEXT_PUBLIC_PERSONAL_SERVER_BASE_URL;
|
|
38024
|
+
async getIdentity(request) {
|
|
38025
|
+
try {
|
|
38026
|
+
const response = await fetch(
|
|
38027
|
+
`${this.PERSONAL_SERVER_BASE_URL}/identity?address=${request.userAddress}`,
|
|
38028
|
+
{
|
|
38029
|
+
method: "GET",
|
|
38030
|
+
headers: {
|
|
38031
|
+
"Content-Type": "application/json"
|
|
38032
|
+
}
|
|
38033
|
+
}
|
|
38034
|
+
);
|
|
38035
|
+
console.debug("\u{1F50D} Debug - getIdentity response", response);
|
|
38036
|
+
if (!response.ok) {
|
|
38037
|
+
const errorText = await response.text();
|
|
38038
|
+
throw new NetworkError(
|
|
38039
|
+
`Local identity API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
38040
|
+
);
|
|
38041
|
+
}
|
|
38042
|
+
const serverResponse = await response.json();
|
|
38043
|
+
return {
|
|
38044
|
+
kind: serverResponse.personal_server.kind,
|
|
38045
|
+
address: serverResponse.personal_server.address,
|
|
38046
|
+
public_key: serverResponse.personal_server.public_key,
|
|
38047
|
+
base_url: this.PERSONAL_SERVER_BASE_URL || "",
|
|
38048
|
+
name: "Hosted Vana Server"
|
|
38049
|
+
};
|
|
38050
|
+
} catch (error) {
|
|
38051
|
+
if (error instanceof NetworkError || error instanceof PersonalServerError) {
|
|
38052
|
+
throw error;
|
|
38053
|
+
}
|
|
38054
|
+
throw new PersonalServerError(
|
|
38055
|
+
`Failed to get personal server identity: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
38056
|
+
);
|
|
38057
|
+
}
|
|
38058
|
+
}
|
|
38059
|
+
/**
|
|
38060
|
+
* Creates an operation via the personal server API.
|
|
38061
|
+
*
|
|
38062
|
+
* @remarks
|
|
38063
|
+
* This method submits a computation request to the personal server API.
|
|
38064
|
+
* The response includes the operation ID.
|
|
38065
|
+
* @param params - The request parameters object
|
|
38066
|
+
* @param params.permissionId - The permission ID authorizing this operation
|
|
38067
|
+
* @returns A Promise that resolves to an operation response with status and control URLs
|
|
38068
|
+
* @throws {PersonalServerError} When server request fails or parameters are invalid
|
|
38069
|
+
* @throws {NetworkError} When personal server API communication fails
|
|
38070
|
+
* @example
|
|
38071
|
+
* ```typescript
|
|
38072
|
+
* const response = await vana.server.createOperation({
|
|
38073
|
+
* permissionId: 123,
|
|
38074
|
+
* });
|
|
38075
|
+
*
|
|
38076
|
+
* console.log(`Operation created: ${response.id}`);
|
|
38077
|
+
* ```
|
|
38078
|
+
*/
|
|
38079
|
+
async createOperation(params) {
|
|
38080
|
+
try {
|
|
38081
|
+
const requestData = {
|
|
38082
|
+
permission_id: params.permissionId
|
|
38083
|
+
};
|
|
38084
|
+
const requestJson = JSON.stringify(requestData);
|
|
38085
|
+
const signature = await this.createSignature(requestJson);
|
|
38086
|
+
const requestBody = {
|
|
38087
|
+
app_signature: signature,
|
|
38088
|
+
operation_request_json: requestJson
|
|
38089
|
+
};
|
|
38090
|
+
console.debug("\u{1F50D} Debug - createOperation requestBody", requestBody);
|
|
38091
|
+
const response = await this.makeRequest(requestBody);
|
|
38092
|
+
return response;
|
|
38093
|
+
} catch (error) {
|
|
38094
|
+
if (error instanceof Error) {
|
|
38095
|
+
if (error instanceof NetworkError || error instanceof SerializationError || error instanceof SignatureError || error instanceof PersonalServerError) {
|
|
38096
|
+
throw error;
|
|
38097
|
+
}
|
|
38098
|
+
throw new PersonalServerError(
|
|
38099
|
+
`Personal server operation creation failed: ${error.message}`,
|
|
38100
|
+
error
|
|
38101
|
+
);
|
|
38102
|
+
}
|
|
38103
|
+
throw new PersonalServerError(
|
|
38104
|
+
"Personal server operation creation failed with unknown error"
|
|
38105
|
+
);
|
|
38106
|
+
}
|
|
38107
|
+
}
|
|
38108
|
+
/**
|
|
38109
|
+
* Polls the status of a computation request for updates and results.
|
|
38110
|
+
*
|
|
38111
|
+
* @remarks
|
|
38112
|
+
* This method checks the current status of a computation request by querying
|
|
38113
|
+
* the personal server API using the provided operation ID. It returns the current
|
|
38114
|
+
* status, any available output, and error information. The method can be
|
|
38115
|
+
* called periodically until the operation completes or fails.
|
|
38116
|
+
*
|
|
38117
|
+
* Common status values include: `starting`, `processing`, `succeeded`, `failed`, `canceled`.
|
|
38118
|
+
* @param operationId - The operation ID returned from the initial request submission
|
|
38119
|
+
* @returns A Promise that resolves to the current operation response with status and results
|
|
38120
|
+
* @throws {NetworkError} When the polling request fails or returns invalid data
|
|
38121
|
+
* @example
|
|
38122
|
+
* ```typescript
|
|
38123
|
+
* // Poll until completion
|
|
38124
|
+
* let result = await vana.server.getOperation(response.id);
|
|
38125
|
+
*
|
|
38126
|
+
* while (result.status === "processing") {
|
|
38127
|
+
* await new Promise(resolve => setTimeout(resolve, 1000));
|
|
38128
|
+
* result = await vana.server.getOperation(response.id);
|
|
38129
|
+
* }
|
|
38130
|
+
*
|
|
38131
|
+
* if (result.status === "succeeded") {
|
|
38132
|
+
* console.log("Computation completed:", result.output);
|
|
38133
|
+
* }
|
|
38134
|
+
* ```
|
|
38135
|
+
*/
|
|
38136
|
+
async getOperation(operationId) {
|
|
38137
|
+
try {
|
|
38138
|
+
console.debug("Polling Operation Status:", operationId);
|
|
38139
|
+
const response = await fetch(
|
|
38140
|
+
`${this.PERSONAL_SERVER_BASE_URL}/operations/${operationId}`,
|
|
38141
|
+
{
|
|
38142
|
+
method: "GET",
|
|
38143
|
+
headers: {
|
|
38144
|
+
"Content-Type": "application/json"
|
|
38145
|
+
}
|
|
38146
|
+
}
|
|
38147
|
+
);
|
|
38148
|
+
if (!response.ok) {
|
|
38149
|
+
const errorText = await response.text();
|
|
38150
|
+
console.debug("Polling Error Response:", {
|
|
38151
|
+
status: response.status,
|
|
38152
|
+
statusText: response.statusText,
|
|
38153
|
+
error: errorText
|
|
38154
|
+
});
|
|
38155
|
+
throw new NetworkError(
|
|
38156
|
+
`Status polling failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
38157
|
+
);
|
|
38158
|
+
}
|
|
38159
|
+
const data = await response.json();
|
|
38160
|
+
console.debug("Polling Success Response:", data);
|
|
38161
|
+
return data;
|
|
38162
|
+
} catch (error) {
|
|
38163
|
+
if (error instanceof NetworkError) {
|
|
38164
|
+
throw error;
|
|
38165
|
+
}
|
|
38166
|
+
throw new NetworkError(
|
|
38167
|
+
`Failed to poll status: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
38168
|
+
);
|
|
38169
|
+
}
|
|
38170
|
+
}
|
|
38171
|
+
async cancelOperation(operationId) {
|
|
38172
|
+
try {
|
|
38173
|
+
const response = await fetch(
|
|
38174
|
+
`${this.PERSONAL_SERVER_BASE_URL}/operations/${operationId}/cancel`,
|
|
38175
|
+
{
|
|
38176
|
+
method: "POST"
|
|
38177
|
+
}
|
|
38178
|
+
);
|
|
38179
|
+
if (!response.ok) {
|
|
38180
|
+
const errorText = await response.text();
|
|
38181
|
+
throw new PersonalServerError(
|
|
38182
|
+
`Failed to cancel operation: ${response.status} ${response.statusText} - ${errorText}`
|
|
38183
|
+
);
|
|
38184
|
+
}
|
|
38185
|
+
} catch (error) {
|
|
38186
|
+
if (error instanceof NetworkError) {
|
|
38187
|
+
throw error;
|
|
38188
|
+
}
|
|
38189
|
+
throw new NetworkError(
|
|
38190
|
+
`Failed to cancel operation: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
38191
|
+
);
|
|
38192
|
+
}
|
|
38193
|
+
}
|
|
38194
|
+
/**
|
|
38195
|
+
* Makes the request to the personal server API.
|
|
38196
|
+
*
|
|
38197
|
+
* @param requestBody - The post request parameters to serialize
|
|
38198
|
+
* @returns JSON string representation of the request data
|
|
38199
|
+
*/
|
|
38200
|
+
async makeRequest(requestBody) {
|
|
38201
|
+
try {
|
|
38202
|
+
console.debug("Personal Server Request:", {
|
|
38203
|
+
url: `${this.PERSONAL_SERVER_BASE_URL}/operations`,
|
|
38204
|
+
method: "POST",
|
|
38205
|
+
headers: {
|
|
38206
|
+
"Content-Type": "application/json"
|
|
38207
|
+
},
|
|
38208
|
+
body: requestBody
|
|
38209
|
+
});
|
|
38210
|
+
const response = await fetch(
|
|
38211
|
+
`${this.PERSONAL_SERVER_BASE_URL}/operations`,
|
|
38212
|
+
{
|
|
38213
|
+
method: "POST",
|
|
38214
|
+
headers: {
|
|
38215
|
+
"Content-Type": "application/json"
|
|
38216
|
+
},
|
|
38217
|
+
body: JSON.stringify(requestBody)
|
|
38218
|
+
}
|
|
38219
|
+
);
|
|
38220
|
+
if (!response.ok) {
|
|
38221
|
+
const errorText = await response.text();
|
|
38222
|
+
console.debug("Personal Server Error Response:", {
|
|
38223
|
+
status: response.status,
|
|
38224
|
+
statusText: response.statusText,
|
|
38225
|
+
error: errorText
|
|
38226
|
+
});
|
|
38227
|
+
throw new NetworkError(
|
|
38228
|
+
`Personal server API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
38229
|
+
);
|
|
38230
|
+
}
|
|
38231
|
+
const data = await response.json();
|
|
38232
|
+
console.debug("Personal Server Success Response:", data);
|
|
38233
|
+
return data;
|
|
38234
|
+
} catch (error) {
|
|
38235
|
+
if (error instanceof NetworkError) {
|
|
38236
|
+
throw error;
|
|
38237
|
+
}
|
|
38238
|
+
throw new NetworkError(
|
|
38239
|
+
`Failed to make personal server API request: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
38240
|
+
);
|
|
38241
|
+
}
|
|
38242
|
+
}
|
|
38243
|
+
/**
|
|
38244
|
+
* Creates a signature for the request JSON.
|
|
38245
|
+
*
|
|
38246
|
+
* @param requestJson - The JSON string to sign
|
|
38247
|
+
* @returns Promise resolving to the cryptographic signature
|
|
38248
|
+
*/
|
|
38249
|
+
async createSignature(requestJson) {
|
|
38250
|
+
try {
|
|
38251
|
+
console.debug("\u{1F50D} Debug - createSignature", requestJson);
|
|
38252
|
+
const client = this.context.applicationClient || this.context.walletClient;
|
|
38253
|
+
const account = client.account;
|
|
38254
|
+
if (!account) {
|
|
38255
|
+
throw new SignatureError("No account available for signing");
|
|
38256
|
+
}
|
|
38257
|
+
if (account.type !== "local") {
|
|
38258
|
+
throw new SignatureError(
|
|
38259
|
+
"Only local accounts are supported for signing"
|
|
38260
|
+
);
|
|
38261
|
+
}
|
|
38262
|
+
console.debug("\u{1F50D} Debug - createSignature account", account);
|
|
38263
|
+
const signature = await account.signMessage({
|
|
38264
|
+
message: requestJson
|
|
38265
|
+
});
|
|
38266
|
+
return signature;
|
|
38267
|
+
} catch (error) {
|
|
38268
|
+
if (error instanceof Error && error.message.includes("User rejected")) {
|
|
38269
|
+
throw new SignatureError("User rejected the signature request");
|
|
38270
|
+
}
|
|
38271
|
+
throw new SignatureError(
|
|
38272
|
+
`Failed to create signature: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
38273
|
+
);
|
|
38274
|
+
}
|
|
38275
|
+
}
|
|
38276
|
+
};
|
|
38277
|
+
|
|
38063
38278
|
// src/contracts/contractController.ts
|
|
38064
|
-
var
|
|
38279
|
+
var import_viem6 = require("viem");
|
|
38065
38280
|
|
|
38066
38281
|
// src/core/client.ts
|
|
38067
|
-
var
|
|
38282
|
+
var import_viem5 = require("viem");
|
|
38068
38283
|
|
|
38069
38284
|
// src/config/chains.ts
|
|
38070
|
-
var
|
|
38071
|
-
var mokshaTestnet = (0,
|
|
38285
|
+
var import_viem4 = require("viem");
|
|
38286
|
+
var mokshaTestnet = (0, import_viem4.defineChain)({
|
|
38072
38287
|
id: 14800,
|
|
38073
38288
|
caipNetworkId: "eip155:14800",
|
|
38074
38289
|
chainNamespace: "eip155",
|
|
@@ -38096,7 +38311,7 @@ var mokshaTestnet = (0, import_viem3.defineChain)({
|
|
|
38096
38311
|
contracts: {},
|
|
38097
38312
|
abis: {}
|
|
38098
38313
|
});
|
|
38099
|
-
var vanaMainnet = (0,
|
|
38314
|
+
var vanaMainnet = (0, import_viem4.defineChain)({
|
|
38100
38315
|
id: 1480,
|
|
38101
38316
|
caipNetworkId: "eip155:1480",
|
|
38102
38317
|
chainNamespace: "eip155",
|
|
@@ -38138,9 +38353,9 @@ var createClient = (chainId = mokshaTestnet.id) => {
|
|
|
38138
38353
|
if (!chain) {
|
|
38139
38354
|
throw new Error(`Chain ${chainId} not found`);
|
|
38140
38355
|
}
|
|
38141
|
-
_client = (0,
|
|
38356
|
+
_client = (0, import_viem5.createPublicClient)({
|
|
38142
38357
|
chain,
|
|
38143
|
-
transport: (0,
|
|
38358
|
+
transport: (0, import_viem5.http)()
|
|
38144
38359
|
});
|
|
38145
38360
|
}
|
|
38146
38361
|
return _client;
|
|
@@ -38157,7 +38372,7 @@ function getContractController(contract, client = createClient()) {
|
|
|
38157
38372
|
const cacheKey = createCacheKey(contract, chainId);
|
|
38158
38373
|
let controller = contractCache.get(cacheKey);
|
|
38159
38374
|
if (!controller) {
|
|
38160
|
-
controller = (0,
|
|
38375
|
+
controller = (0, import_viem6.getContract)({
|
|
38161
38376
|
address: getContractAddress(chainId, contract),
|
|
38162
38377
|
abi: getAbi(contract),
|
|
38163
38378
|
client
|
|
@@ -39771,7 +39986,7 @@ var StorageManager = class {
|
|
|
39771
39986
|
};
|
|
39772
39987
|
|
|
39773
39988
|
// src/core.ts
|
|
39774
|
-
var
|
|
39989
|
+
var import_viem7 = require("viem");
|
|
39775
39990
|
|
|
39776
39991
|
// src/chains/definitions.ts
|
|
39777
39992
|
var vanaMainnet2 = {
|
|
@@ -39814,7 +40029,7 @@ var moksha = {
|
|
|
39814
40029
|
url: "https://moksha.vanascan.io"
|
|
39815
40030
|
}
|
|
39816
40031
|
},
|
|
39817
|
-
subgraphUrl: "https://api.goldsky.com/api/public/project_cm168cz887zva010j39il7a6p/subgraphs/moksha/7.0.
|
|
40032
|
+
subgraphUrl: "https://api.goldsky.com/api/public/project_cm168cz887zva010j39il7a6p/subgraphs/moksha/7.0.3/gn"
|
|
39818
40033
|
};
|
|
39819
40034
|
function getChainConfig(chainId) {
|
|
39820
40035
|
switch (chainId) {
|
|
@@ -39826,16 +40041,60 @@ function getChainConfig(chainId) {
|
|
|
39826
40041
|
return void 0;
|
|
39827
40042
|
}
|
|
39828
40043
|
}
|
|
40044
|
+
var mokshaTestnet2 = moksha;
|
|
39829
40045
|
function getAllChains() {
|
|
39830
40046
|
return [vanaMainnet2, moksha];
|
|
39831
40047
|
}
|
|
39832
40048
|
|
|
39833
40049
|
// src/core.ts
|
|
40050
|
+
var VanaCoreFactory = class {
|
|
40051
|
+
/**
|
|
40052
|
+
* Creates a VanaCore instance that enforces storage requirements at compile time.
|
|
40053
|
+
* Use this factory when you know you'll need storage-dependent operations.
|
|
40054
|
+
*
|
|
40055
|
+
* @param platform - The platform adapter for environment-specific operations
|
|
40056
|
+
* @param config - Configuration that includes required storage providers
|
|
40057
|
+
* @returns VanaCore instance with storage validation
|
|
40058
|
+
* @example
|
|
40059
|
+
* ```typescript
|
|
40060
|
+
* const vanaCore = VanaCoreFactory.createWithStorage(platformAdapter, {
|
|
40061
|
+
* walletClient: myWalletClient,
|
|
40062
|
+
* storage: {
|
|
40063
|
+
* providers: { ipfs: new IPFSStorage() },
|
|
40064
|
+
* defaultProvider: 'ipfs'
|
|
40065
|
+
* }
|
|
40066
|
+
* });
|
|
40067
|
+
* ```
|
|
40068
|
+
*/
|
|
40069
|
+
static createWithStorage(platform, config) {
|
|
40070
|
+
const core = new VanaCore(platform, config);
|
|
40071
|
+
return core;
|
|
40072
|
+
}
|
|
40073
|
+
/**
|
|
40074
|
+
* Creates a VanaCore instance without storage requirements.
|
|
40075
|
+
* Storage-dependent operations will fail at runtime if not configured.
|
|
40076
|
+
*
|
|
40077
|
+
* @param platform - The platform adapter for environment-specific operations
|
|
40078
|
+
* @param config - Basic configuration without required storage
|
|
40079
|
+
* @returns VanaCore instance
|
|
40080
|
+
* @example
|
|
40081
|
+
* ```typescript
|
|
40082
|
+
* const vanaCore = VanaCoreFactory.create(platformAdapter, {
|
|
40083
|
+
* walletClient: myWalletClient
|
|
40084
|
+
* });
|
|
40085
|
+
* ```
|
|
40086
|
+
*/
|
|
40087
|
+
static create(platform, config) {
|
|
40088
|
+
return new VanaCore(platform, config);
|
|
40089
|
+
}
|
|
40090
|
+
};
|
|
39834
40091
|
var VanaCore = class {
|
|
39835
40092
|
/** Manages gasless data access permissions and trusted server registry. */
|
|
39836
40093
|
permissions;
|
|
39837
|
-
/** Handles user data file operations
|
|
40094
|
+
/** Handles user data file operations. */
|
|
39838
40095
|
data;
|
|
40096
|
+
/** Manages data schemas and refiners. */
|
|
40097
|
+
schemas;
|
|
39839
40098
|
/** Provides personal server setup and trusted server interactions. */
|
|
39840
40099
|
server;
|
|
39841
40100
|
/** Offers low-level access to Vana protocol smart contracts. */
|
|
@@ -39844,12 +40103,18 @@ var VanaCore = class {
|
|
|
39844
40103
|
platform;
|
|
39845
40104
|
relayerCallbacks;
|
|
39846
40105
|
storageManager;
|
|
40106
|
+
hasRequiredStorage;
|
|
40107
|
+
ipfsGateways;
|
|
39847
40108
|
/**
|
|
39848
40109
|
* Initializes a new VanaCore client instance with the provided configuration.
|
|
39849
40110
|
*
|
|
39850
40111
|
* @remarks
|
|
39851
40112
|
* The constructor validates the configuration, initializes storage providers if configured,
|
|
39852
40113
|
* creates wallet and public clients, and sets up all SDK controllers with shared context.
|
|
40114
|
+
*
|
|
40115
|
+
* IMPORTANT: This constructor will validate storage requirements at runtime to fail fast.
|
|
40116
|
+
* Methods that require storage will throw runtime errors if storage is not configured.
|
|
40117
|
+
*
|
|
39853
40118
|
* @param platform - The platform adapter for environment-specific operations
|
|
39854
40119
|
* @param config - The configuration object specifying wallet or chain settings
|
|
39855
40120
|
* @throws {InvalidConfigurationError} When the configuration is invalid or incomplete
|
|
@@ -39865,6 +40130,8 @@ var VanaCore = class {
|
|
|
39865
40130
|
this.platform = platform;
|
|
39866
40131
|
this.validateConfig(config);
|
|
39867
40132
|
this.relayerCallbacks = config.relayerCallbacks;
|
|
40133
|
+
this.ipfsGateways = config.ipfsGateways;
|
|
40134
|
+
this.hasRequiredStorage = hasStorageConfig(config);
|
|
39868
40135
|
if (config.storage?.providers) {
|
|
39869
40136
|
this.storageManager = new StorageManager();
|
|
39870
40137
|
for (const [name, provider] of Object.entries(config.storage.providers)) {
|
|
@@ -39895,9 +40162,9 @@ var VanaCore = class {
|
|
|
39895
40162
|
`Unsupported chain ID: ${config.chainId}`
|
|
39896
40163
|
);
|
|
39897
40164
|
}
|
|
39898
|
-
walletClient = (0,
|
|
40165
|
+
walletClient = (0, import_viem7.createWalletClient)({
|
|
39899
40166
|
chain,
|
|
39900
|
-
transport: (0,
|
|
40167
|
+
transport: (0, import_viem7.http)(config.rpcUrl || chain.rpcUrls.default.http[0]),
|
|
39901
40168
|
account: config.account
|
|
39902
40169
|
});
|
|
39903
40170
|
} else {
|
|
@@ -39905,9 +40172,9 @@ var VanaCore = class {
|
|
|
39905
40172
|
"Invalid configuration: must be either WalletConfig or ChainConfig"
|
|
39906
40173
|
);
|
|
39907
40174
|
}
|
|
39908
|
-
const publicClient = (0,
|
|
40175
|
+
const publicClient = (0, import_viem7.createPublicClient)({
|
|
39909
40176
|
chain: walletClient.chain,
|
|
39910
|
-
transport: (0,
|
|
40177
|
+
transport: (0, import_viem7.http)()
|
|
39911
40178
|
});
|
|
39912
40179
|
const chainConfig = getChainConfig(walletClient.chain.id);
|
|
39913
40180
|
const subgraphUrl = config.subgraphUrl || chainConfig?.subgraphUrl;
|
|
@@ -39919,14 +40186,70 @@ var VanaCore = class {
|
|
|
39919
40186
|
relayerCallbacks: this.relayerCallbacks,
|
|
39920
40187
|
storageManager: this.storageManager,
|
|
39921
40188
|
subgraphUrl,
|
|
39922
|
-
platform: this.platform
|
|
40189
|
+
platform: this.platform,
|
|
39923
40190
|
// Pass the platform adapter to controllers
|
|
40191
|
+
validateStorageRequired: this.validateStorageRequired.bind(this),
|
|
40192
|
+
hasStorage: this.hasStorage.bind(this),
|
|
40193
|
+
ipfsGateways: this.ipfsGateways
|
|
39924
40194
|
};
|
|
39925
40195
|
this.permissions = new PermissionsController(sharedContext);
|
|
39926
40196
|
this.data = new DataController(sharedContext);
|
|
40197
|
+
this.schemas = new SchemaController(sharedContext);
|
|
39927
40198
|
this.server = new ServerController(sharedContext);
|
|
39928
40199
|
this.protocol = new ProtocolController(sharedContext);
|
|
39929
40200
|
}
|
|
40201
|
+
/**
|
|
40202
|
+
* Validates that storage is available for storage-dependent operations.
|
|
40203
|
+
* This method enforces the fail-fast principle by checking storage availability
|
|
40204
|
+
* at method call time rather than during expensive operations.
|
|
40205
|
+
*
|
|
40206
|
+
* @throws {InvalidConfigurationError} When storage is required but not configured
|
|
40207
|
+
* @example
|
|
40208
|
+
* ```typescript
|
|
40209
|
+
* // This will throw if storage is not configured
|
|
40210
|
+
* vana.validateStorageRequired();
|
|
40211
|
+
* await vana.data.uploadFile(file); // Safe to proceed
|
|
40212
|
+
* ```
|
|
40213
|
+
*/
|
|
40214
|
+
validateStorageRequired() {
|
|
40215
|
+
if (!this.hasRequiredStorage) {
|
|
40216
|
+
throw new InvalidConfigurationError(
|
|
40217
|
+
"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."
|
|
40218
|
+
);
|
|
40219
|
+
}
|
|
40220
|
+
}
|
|
40221
|
+
/**
|
|
40222
|
+
* Checks whether storage is configured without throwing an error.
|
|
40223
|
+
*
|
|
40224
|
+
* @returns True if storage is properly configured
|
|
40225
|
+
* @example
|
|
40226
|
+
* ```typescript
|
|
40227
|
+
* if (vana.hasStorage()) {
|
|
40228
|
+
* await vana.data.uploadFile(file);
|
|
40229
|
+
* } else {
|
|
40230
|
+
* console.warn('Storage not configured - using pre-stored URLs only');
|
|
40231
|
+
* }
|
|
40232
|
+
* ```
|
|
40233
|
+
*/
|
|
40234
|
+
hasStorage() {
|
|
40235
|
+
return this.hasRequiredStorage;
|
|
40236
|
+
}
|
|
40237
|
+
/**
|
|
40238
|
+
* Type guard to check if this instance has storage enabled at compile time.
|
|
40239
|
+
* Use this when you need TypeScript to understand that storage is available.
|
|
40240
|
+
*
|
|
40241
|
+
* @returns True if storage is configured, with type narrowing
|
|
40242
|
+
* @example
|
|
40243
|
+
* ```typescript
|
|
40244
|
+
* if (vana.isStorageEnabled()) {
|
|
40245
|
+
* // TypeScript knows storage is available here
|
|
40246
|
+
* await vana.data.uploadFile(file);
|
|
40247
|
+
* }
|
|
40248
|
+
* ```
|
|
40249
|
+
*/
|
|
40250
|
+
isStorageEnabled() {
|
|
40251
|
+
return this.hasRequiredStorage;
|
|
40252
|
+
}
|
|
39930
40253
|
/**
|
|
39931
40254
|
* Validates the provided configuration object against all requirements.
|
|
39932
40255
|
*
|
|
@@ -40115,23 +40438,23 @@ var VanaCore = class {
|
|
|
40115
40438
|
return this.platform;
|
|
40116
40439
|
}
|
|
40117
40440
|
/**
|
|
40118
|
-
* Encrypts
|
|
40441
|
+
* Encrypts data using the Vana protocol standard encryption.
|
|
40119
40442
|
* This method automatically uses the correct platform adapter for the current environment.
|
|
40120
40443
|
*
|
|
40121
40444
|
* @param data The data to encrypt (string or Blob)
|
|
40122
|
-
* @param
|
|
40445
|
+
* @param key The key to use as encryption key
|
|
40123
40446
|
* @returns The encrypted data as Blob
|
|
40124
40447
|
* @example
|
|
40125
40448
|
* ```typescript
|
|
40126
40449
|
* const encryptionKey = await generateEncryptionKey(walletClient);
|
|
40127
|
-
* const encrypted = await vana.
|
|
40450
|
+
* const encrypted = await vana.encryptBlob("sensitive data", encryptionKey);
|
|
40128
40451
|
* ```
|
|
40129
40452
|
*/
|
|
40130
|
-
async
|
|
40131
|
-
return
|
|
40453
|
+
async encryptBlob(data, key) {
|
|
40454
|
+
return encryptBlobWithSignedKey(data, key, this.platform);
|
|
40132
40455
|
}
|
|
40133
40456
|
/**
|
|
40134
|
-
* Decrypts
|
|
40457
|
+
* Decrypts data that was encrypted using the Vana protocol.
|
|
40135
40458
|
* This method automatically uses the correct platform adapter for the current environment.
|
|
40136
40459
|
*
|
|
40137
40460
|
* @param encryptedData The encrypted data (string or Blob)
|
|
@@ -40140,25 +40463,29 @@ var VanaCore = class {
|
|
|
40140
40463
|
* @example
|
|
40141
40464
|
* ```typescript
|
|
40142
40465
|
* const encryptionKey = await generateEncryptionKey(walletClient);
|
|
40143
|
-
* const decrypted = await vana.
|
|
40466
|
+
* const decrypted = await vana.decryptBlob(encryptedData, encryptionKey);
|
|
40144
40467
|
* const text = await decrypted.text();
|
|
40145
40468
|
* ```
|
|
40146
40469
|
*/
|
|
40147
|
-
async
|
|
40148
|
-
return
|
|
40470
|
+
async decryptBlob(encryptedData, walletSignature) {
|
|
40471
|
+
return decryptBlobWithSignedKey(
|
|
40472
|
+
encryptedData,
|
|
40473
|
+
walletSignature,
|
|
40474
|
+
this.platform
|
|
40475
|
+
);
|
|
40149
40476
|
}
|
|
40150
40477
|
};
|
|
40151
40478
|
|
|
40152
40479
|
// src/utils/formatters.ts
|
|
40153
|
-
var
|
|
40480
|
+
var import_viem8 = require("viem");
|
|
40154
40481
|
function formatNumber(value) {
|
|
40155
40482
|
return Number(value);
|
|
40156
40483
|
}
|
|
40157
40484
|
function formatEth(wei, decimals = 4) {
|
|
40158
|
-
return (0,
|
|
40485
|
+
return (0, import_viem8.formatEther)(BigInt(wei.toString())).slice(0, decimals + 2);
|
|
40159
40486
|
}
|
|
40160
40487
|
function formatToken(amount, decimals = 18, displayDecimals = 4) {
|
|
40161
|
-
const value = (0,
|
|
40488
|
+
const value = (0, import_viem8.formatUnits)(BigInt(amount.toString()), decimals);
|
|
40162
40489
|
const parts = value.split(".");
|
|
40163
40490
|
if (parts.length === 1) {
|
|
40164
40491
|
return parts[0];
|
|
@@ -40176,7 +40503,7 @@ function createValidatedGrant(params) {
|
|
|
40176
40503
|
try {
|
|
40177
40504
|
validateGrant(grantFile, {
|
|
40178
40505
|
schema: true,
|
|
40179
|
-
grantee: params.
|
|
40506
|
+
grantee: params.grantee,
|
|
40180
40507
|
operation: params.operation
|
|
40181
40508
|
});
|
|
40182
40509
|
} catch (error) {
|
|
@@ -40590,10 +40917,10 @@ var CircuitBreaker = class {
|
|
|
40590
40917
|
};
|
|
40591
40918
|
|
|
40592
40919
|
// src/server/handler.ts
|
|
40593
|
-
var
|
|
40920
|
+
var import_viem9 = require("viem");
|
|
40594
40921
|
async function handleRelayerRequest(sdk, payload) {
|
|
40595
40922
|
const { typedData, signature, expectedUserAddress } = payload;
|
|
40596
|
-
const signerAddress = await (0,
|
|
40923
|
+
const signerAddress = await (0, import_viem9.recoverTypedDataAddress)({
|
|
40597
40924
|
domain: typedData.domain,
|
|
40598
40925
|
types: typedData.types,
|
|
40599
40926
|
primaryType: typedData.primaryType,
|
|
@@ -41039,25 +41366,15 @@ var ApiClient = class {
|
|
|
41039
41366
|
};
|
|
41040
41367
|
|
|
41041
41368
|
// src/index.node.ts
|
|
41042
|
-
var
|
|
41043
|
-
/**
|
|
41044
|
-
* Creates a Vana SDK instance configured for Node.js environments.
|
|
41045
|
-
*
|
|
41046
|
-
* @param config - SDK configuration object (wallet client or chain config)
|
|
41047
|
-
* @example
|
|
41048
|
-
* ```typescript
|
|
41049
|
-
* // With wallet client
|
|
41050
|
-
* const vana = new Vana({ walletClient });
|
|
41051
|
-
*
|
|
41052
|
-
* // With chain configuration
|
|
41053
|
-
* const vana = new Vana({ chainId: 14800, account });
|
|
41054
|
-
* ```
|
|
41055
|
-
*/
|
|
41369
|
+
var VanaNodeImpl = class extends VanaCore {
|
|
41056
41370
|
constructor(config) {
|
|
41057
41371
|
super(new NodePlatformAdapter(), config);
|
|
41058
41372
|
}
|
|
41059
41373
|
};
|
|
41060
|
-
|
|
41374
|
+
function Vana(config) {
|
|
41375
|
+
return new VanaNodeImpl(config);
|
|
41376
|
+
}
|
|
41377
|
+
var index_node_default = Vana;
|
|
41061
41378
|
// Annotate the CommonJS export names for ESM import in node:
|
|
41062
41379
|
0 && (module.exports = {
|
|
41063
41380
|
ApiClient,
|
|
@@ -41094,6 +41411,7 @@ var index_node_default = VanaNode;
|
|
|
41094
41411
|
RateLimiter,
|
|
41095
41412
|
RelayerError,
|
|
41096
41413
|
RetryUtility,
|
|
41414
|
+
SchemaController,
|
|
41097
41415
|
SchemaValidationError,
|
|
41098
41416
|
SchemaValidator,
|
|
41099
41417
|
SerializationError,
|
|
@@ -41106,8 +41424,9 @@ var index_node_default = VanaNode;
|
|
|
41106
41424
|
UserRejectedRequestError,
|
|
41107
41425
|
Vana,
|
|
41108
41426
|
VanaCore,
|
|
41427
|
+
VanaCoreFactory,
|
|
41109
41428
|
VanaError,
|
|
41110
|
-
|
|
41429
|
+
VanaNodeImpl,
|
|
41111
41430
|
__contractCache,
|
|
41112
41431
|
chains,
|
|
41113
41432
|
checkGrantAccess,
|
|
@@ -41122,12 +41441,12 @@ var index_node_default = VanaNode;
|
|
|
41122
41441
|
createPlatformAdapterFor,
|
|
41123
41442
|
createPlatformAdapterSafe,
|
|
41124
41443
|
createValidatedGrant,
|
|
41125
|
-
|
|
41444
|
+
decryptBlobWithSignedKey,
|
|
41126
41445
|
decryptWithPrivateKey,
|
|
41127
41446
|
decryptWithWalletPrivateKey,
|
|
41128
41447
|
detectPlatform,
|
|
41448
|
+
encryptBlobWithSignedKey,
|
|
41129
41449
|
encryptFileKey,
|
|
41130
|
-
encryptUserData,
|
|
41131
41450
|
encryptWithWalletPublicKey,
|
|
41132
41451
|
extractIpfsHash,
|
|
41133
41452
|
fetchAndValidateSchema,
|
|
@@ -41152,9 +41471,7 @@ var index_node_default = VanaNode;
|
|
|
41152
41471
|
handleRelayerRequest,
|
|
41153
41472
|
isAPIResponse,
|
|
41154
41473
|
isGrantExpired,
|
|
41155
|
-
isIdentityServerOutput,
|
|
41156
41474
|
isIpfsUrl,
|
|
41157
|
-
isPersonalServerOutput,
|
|
41158
41475
|
isPlatformSupported,
|
|
41159
41476
|
isReplicateAPIResponse,
|
|
41160
41477
|
moksha,
|