@opendatalabs/vana-sdk 3.21.0 → 3.22.0-pr.207.0a5d07b
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 +64 -0
- package/dist/crypto/envelope/job.cjs +263 -0
- package/dist/crypto/envelope/job.cjs.map +1 -0
- package/dist/crypto/envelope/job.d.ts +122 -0
- package/dist/crypto/envelope/job.js +240 -0
- package/dist/crypto/envelope/job.js.map +1 -0
- package/dist/errors.cjs +77 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +123 -0
- package/dist/errors.js +67 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.browser.d.ts +5 -1
- package/dist/index.browser.js +721 -24
- package/dist/index.browser.js.map +4 -4
- package/dist/index.node.cjs +1309 -107
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +6 -1
- package/dist/index.node.js +1261 -97
- package/dist/index.node.js.map +4 -4
- package/dist/protocol/derivative-questions.cjs +22 -0
- package/dist/protocol/derivative-questions.cjs.map +1 -1
- package/dist/protocol/derivative-questions.d.ts +53 -0
- package/dist/protocol/derivative-questions.js +19 -0
- package/dist/protocol/derivative-questions.js.map +1 -1
- package/dist/protocol/derivative-status.cjs +209 -0
- package/dist/protocol/derivative-status.cjs.map +1 -0
- package/dist/protocol/derivative-status.d.ts +196 -0
- package/dist/protocol/derivative-status.js +190 -0
- package/dist/protocol/derivative-status.js.map +1 -0
- package/dist/protocol/derivative-status.test.d.ts +1 -0
- package/dist/protocol/identity.cjs +219 -0
- package/dist/protocol/identity.cjs.map +1 -0
- package/dist/protocol/identity.d.ts +193 -0
- package/dist/protocol/identity.js +183 -0
- package/dist/protocol/identity.js.map +1 -0
- package/dist/protocol/identity.test.d.ts +1 -0
- package/dist/protocol/identity.vector.test.d.ts +1 -0
- package/dist/protocol/jobs-client.cjs +493 -0
- package/dist/protocol/jobs-client.cjs.map +1 -0
- package/dist/protocol/jobs-client.d.ts +167 -0
- package/dist/protocol/jobs-client.js +498 -0
- package/dist/protocol/jobs-client.js.map +1 -0
- package/dist/protocol/jobs-client.test.d.ts +1 -0
- package/dist/protocol/jobs.cjs +67 -0
- package/dist/protocol/jobs.cjs.map +1 -0
- package/dist/protocol/jobs.d.ts +185 -0
- package/dist/protocol/jobs.js +33 -0
- package/dist/protocol/jobs.js.map +1 -0
- package/dist/protocol/jobs.test.d.ts +1 -0
- package/dist/tests/mock-personal-server.d.ts +9 -0
- package/package.json +7 -1
package/dist/index.node.js
CHANGED
|
@@ -1347,6 +1347,63 @@ var WriteRejectedError = class extends PersonalServerWriteError {
|
|
|
1347
1347
|
super(message, "WRITE_REJECTED", status, errorCode, details);
|
|
1348
1348
|
}
|
|
1349
1349
|
};
|
|
1350
|
+
var JobsClientError = class extends VanaError {
|
|
1351
|
+
constructor(message, code, status, errorCode = null, details) {
|
|
1352
|
+
super(message, code);
|
|
1353
|
+
this.status = status;
|
|
1354
|
+
this.errorCode = errorCode;
|
|
1355
|
+
this.details = details;
|
|
1356
|
+
}
|
|
1357
|
+
status;
|
|
1358
|
+
errorCode;
|
|
1359
|
+
details;
|
|
1360
|
+
};
|
|
1361
|
+
var BuilderUnknownError = class extends JobsClientError {
|
|
1362
|
+
constructor(message, details) {
|
|
1363
|
+
super(message, "JOB_BUILDER_UNKNOWN", 403, "BUILDER_UNKNOWN", details);
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
var GrantInvalidError = class extends JobsClientError {
|
|
1367
|
+
constructor(message, details) {
|
|
1368
|
+
super(message, "JOB_GRANT_INVALID", 403, "GRANT_INVALID", details);
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
var OwnerNotReadyError = class extends JobsClientError {
|
|
1372
|
+
constructor(message, details) {
|
|
1373
|
+
super(message, "JOB_OWNER_NOT_READY", 403, "OWNER_NOT_READY", details);
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
var JobIdTakenError = class extends JobsClientError {
|
|
1377
|
+
constructor(message, details) {
|
|
1378
|
+
super(message, "JOB_ID_TAKEN", 409, "JOB_ID_TAKEN", details);
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
var JobNotFoundError = class extends JobsClientError {
|
|
1382
|
+
constructor(message, details) {
|
|
1383
|
+
super(message, "JOB_NOT_FOUND", 404, "JOB_NOT_FOUND", details);
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
var JobRequestTooLargeError = class extends JobsClientError {
|
|
1387
|
+
constructor(message, errorCode = "BODY_TOO_LARGE", details) {
|
|
1388
|
+
super(message, "JOB_REQUEST_TOO_LARGE", 413, errorCode, details);
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
var JobTimeoutError = class extends JobsClientError {
|
|
1392
|
+
constructor(message, details) {
|
|
1393
|
+
super(message, "JOB_TIMEOUT", void 0, null, details);
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
var JobRejectedError = class extends JobsClientError {
|
|
1397
|
+
constructor(message, status, errorCode = null, details) {
|
|
1398
|
+
super(message, "JOB_REJECTED", status, errorCode, details);
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
var JobTransportError = class extends JobsClientError {
|
|
1402
|
+
constructor(message, cause) {
|
|
1403
|
+
super(message, "JOB_TRANSPORT_ERROR");
|
|
1404
|
+
this.cause = cause;
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1350
1407
|
var LineageReadError = class extends VanaError {
|
|
1351
1408
|
constructor(message, status, errorCode = null, details) {
|
|
1352
1409
|
super(message, "LINEAGE_READ_ERROR");
|
|
@@ -31347,13 +31404,13 @@ var NodeCryptoAdapter = class {
|
|
|
31347
31404
|
*/
|
|
31348
31405
|
async generateKeyPair() {
|
|
31349
31406
|
try {
|
|
31350
|
-
const
|
|
31407
|
+
const secp256k15 = secp256k1Import2;
|
|
31351
31408
|
let privateKey;
|
|
31352
31409
|
do {
|
|
31353
31410
|
privateKey = randomBytes2(32);
|
|
31354
|
-
} while (!
|
|
31411
|
+
} while (!secp256k15.privateKeyVerify(privateKey));
|
|
31355
31412
|
const publicKey = Buffer.from(
|
|
31356
|
-
|
|
31413
|
+
secp256k15.publicKeyCreate(privateKey, true)
|
|
31357
31414
|
);
|
|
31358
31415
|
return {
|
|
31359
31416
|
privateKey: privateKey.toString("hex"),
|
|
@@ -32363,9 +32420,929 @@ var RECORD_DATA_ACCESS_TYPES = {
|
|
|
32363
32420
|
]
|
|
32364
32421
|
};
|
|
32365
32422
|
|
|
32423
|
+
// src/protocol/identity.ts
|
|
32424
|
+
init_interface();
|
|
32425
|
+
import * as secp256k14 from "@noble/secp256k1";
|
|
32426
|
+
import {
|
|
32427
|
+
concat as concat4,
|
|
32428
|
+
encodePacked,
|
|
32429
|
+
fromHex as fromHex5,
|
|
32430
|
+
getAddress,
|
|
32431
|
+
isAddressEqual,
|
|
32432
|
+
keccak256,
|
|
32433
|
+
recoverPublicKey,
|
|
32434
|
+
toBytes,
|
|
32435
|
+
toHex as toHex7
|
|
32436
|
+
} from "viem";
|
|
32437
|
+
import { publicKeyToAddress } from "viem/accounts";
|
|
32438
|
+
var ENCLAVE_IDENTITY_EVIDENCE_VERSION = 1;
|
|
32439
|
+
var USER_PS_ID_DOMAIN = "vana.ps-enclave.v1";
|
|
32440
|
+
var ENCLAVE_WALLET_PURPOSE = "vana.ps-enclave.wallet.v1";
|
|
32441
|
+
var MASTER_SIGNATURE_DELIVERY_VERSION = "vana.ps-enclave.delivery.v1";
|
|
32442
|
+
var MASTER_SIGNATURE_DELIVERY_MAX_AGE_SECONDS = 600;
|
|
32443
|
+
var SEALED_ENVELOPE_VERSION = 1;
|
|
32444
|
+
var VANA_MAINNET_CHAIN_ID = 1480;
|
|
32445
|
+
var MOKSHA_CHAIN_ID = 14800;
|
|
32446
|
+
var KMS_ISSUED_PREFIX = "dstack-kms-issued";
|
|
32447
|
+
var PREIMAGE_SEPARATOR = ":";
|
|
32448
|
+
var UNCOMPRESSED_PUBLIC_KEY_BYTES = 65;
|
|
32449
|
+
var UNCOMPRESSED_PUBLIC_KEY_PREFIX = "04";
|
|
32450
|
+
var EMPTY_HEX = "0x";
|
|
32451
|
+
function emptyAnchor() {
|
|
32452
|
+
return Object.freeze({
|
|
32453
|
+
kmsRootPubkey: EMPTY_HEX,
|
|
32454
|
+
appIds: Object.freeze([])
|
|
32455
|
+
});
|
|
32456
|
+
}
|
|
32457
|
+
var ENCLAVE_TRUST_ANCHORS = Object.freeze({
|
|
32458
|
+
// filled at fleet provisioning; verify fails closed while empty
|
|
32459
|
+
[VANA_MAINNET_CHAIN_ID]: emptyAnchor(),
|
|
32460
|
+
// filled at fleet provisioning; verify fails closed while empty
|
|
32461
|
+
[MOKSHA_CHAIN_ID]: emptyAnchor()
|
|
32462
|
+
});
|
|
32463
|
+
function userPsId(chainId, ownerAddress) {
|
|
32464
|
+
const packed = encodePacked(
|
|
32465
|
+
["string", "uint256", "address"],
|
|
32466
|
+
[USER_PS_ID_DOMAIN, BigInt(chainId), getAddress(ownerAddress)]
|
|
32467
|
+
);
|
|
32468
|
+
return keccak256(packed);
|
|
32469
|
+
}
|
|
32470
|
+
function compressPublicKey(publicKey) {
|
|
32471
|
+
return secp256k14.ProjectivePoint.fromHex(
|
|
32472
|
+
fromHex5(publicKey, "bytes")
|
|
32473
|
+
).toRawBytes(true);
|
|
32474
|
+
}
|
|
32475
|
+
function sameKey(a, b) {
|
|
32476
|
+
return toHex7(compressPublicKey(a)) === toHex7(compressPublicKey(b));
|
|
32477
|
+
}
|
|
32478
|
+
function assertUncompressedKey(publicKey) {
|
|
32479
|
+
const hex = publicKey.slice(2);
|
|
32480
|
+
if (hex.length !== UNCOMPRESSED_PUBLIC_KEY_BYTES * 2 || !hex.startsWith(UNCOMPRESSED_PUBLIC_KEY_PREFIX) || !/^[0-9a-fA-F]+$/.test(hex)) {
|
|
32481
|
+
throw new Error("Public key must be a 65-byte uncompressed secp256k1 key");
|
|
32482
|
+
}
|
|
32483
|
+
}
|
|
32484
|
+
function appRootPreimage(purpose, publicKey) {
|
|
32485
|
+
const keyHex = toHex7(compressPublicKey(publicKey)).slice(2);
|
|
32486
|
+
return keccak256(toBytes(`${purpose}${PREIMAGE_SEPARATOR}${keyHex}`));
|
|
32487
|
+
}
|
|
32488
|
+
function kmsIssuedPreimage(appId, appRootPublicKey) {
|
|
32489
|
+
const prefix = concat4([
|
|
32490
|
+
toBytes(`${KMS_ISSUED_PREFIX}${PREIMAGE_SEPARATOR}`),
|
|
32491
|
+
fromHex5(appId, "bytes")
|
|
32492
|
+
]);
|
|
32493
|
+
const compressed = compressPublicKey(appRootPublicKey);
|
|
32494
|
+
return keccak256(concat4([prefix, compressed]));
|
|
32495
|
+
}
|
|
32496
|
+
async function recoverChainKey(hash, signature, link) {
|
|
32497
|
+
try {
|
|
32498
|
+
return (await recoverPublicKey({ hash, signature })).toLowerCase();
|
|
32499
|
+
} catch {
|
|
32500
|
+
throw new Error(`Invalid enclave signature chain link ${link}`);
|
|
32501
|
+
}
|
|
32502
|
+
}
|
|
32503
|
+
async function verifyEnclaveIdentityEvidence(evidence, anchors, expected) {
|
|
32504
|
+
if (evidence.v !== ENCLAVE_IDENTITY_EVIDENCE_VERSION) {
|
|
32505
|
+
throw new Error("Unsupported enclave identity evidence version");
|
|
32506
|
+
}
|
|
32507
|
+
if (!Number.isInteger(evidence.epoch) || evidence.epoch < 1) {
|
|
32508
|
+
throw new Error("Invalid enclave identity epoch");
|
|
32509
|
+
}
|
|
32510
|
+
if (evidence.chainId !== expected.chainId) {
|
|
32511
|
+
throw new Error(
|
|
32512
|
+
"Enclave identity chain ID does not match expected chain ID"
|
|
32513
|
+
);
|
|
32514
|
+
}
|
|
32515
|
+
if (!isAddressEqual(evidence.ownerAddress, expected.ownerAddress)) {
|
|
32516
|
+
throw new Error("Enclave identity owner does not match expected owner");
|
|
32517
|
+
}
|
|
32518
|
+
if (evidence.epoch !== expected.epoch) {
|
|
32519
|
+
throw new Error("Enclave identity epoch does not match expected epoch");
|
|
32520
|
+
}
|
|
32521
|
+
const expectedUserPsId = userPsId(expected.chainId, expected.ownerAddress);
|
|
32522
|
+
if (evidence.userPsId.toLowerCase() !== expectedUserPsId.toLowerCase()) {
|
|
32523
|
+
throw new Error("Enclave userPsId does not match expected identity");
|
|
32524
|
+
}
|
|
32525
|
+
if (evidence.purpose !== ENCLAVE_WALLET_PURPOSE) {
|
|
32526
|
+
throw new Error("Unexpected enclave wallet purpose");
|
|
32527
|
+
}
|
|
32528
|
+
if (anchors.kmsRootPubkey === EMPTY_HEX) {
|
|
32529
|
+
throw new Error("KMS root trust anchor is not provisioned");
|
|
32530
|
+
}
|
|
32531
|
+
assertUncompressedKey(evidence.publicKey);
|
|
32532
|
+
const derivedAddress = publicKeyToAddress(evidence.publicKey);
|
|
32533
|
+
if (getAddress(derivedAddress) !== getAddress(evidence.address)) {
|
|
32534
|
+
throw new Error("Enclave public key does not match its address");
|
|
32535
|
+
}
|
|
32536
|
+
const appRootPublicKey = await recoverChainKey(
|
|
32537
|
+
appRootPreimage(evidence.purpose, evidence.publicKey),
|
|
32538
|
+
evidence.signatureChain[0],
|
|
32539
|
+
0
|
|
32540
|
+
);
|
|
32541
|
+
const kmsRootPublicKey = await recoverChainKey(
|
|
32542
|
+
kmsIssuedPreimage(evidence.appId, appRootPublicKey),
|
|
32543
|
+
evidence.signatureChain[1],
|
|
32544
|
+
1
|
|
32545
|
+
);
|
|
32546
|
+
let matchesAnchor;
|
|
32547
|
+
try {
|
|
32548
|
+
matchesAnchor = sameKey(kmsRootPublicKey, anchors.kmsRootPubkey);
|
|
32549
|
+
} catch {
|
|
32550
|
+
throw new Error("KMS root trust anchor is malformed");
|
|
32551
|
+
}
|
|
32552
|
+
if (!matchesAnchor) {
|
|
32553
|
+
throw new Error("KMS root public key does not match the trust anchor");
|
|
32554
|
+
}
|
|
32555
|
+
if (keccak256(kmsRootPublicKey) !== evidence.kmsRootFingerprint.toLowerCase()) {
|
|
32556
|
+
throw new Error("KMS root fingerprint does not match the evidence");
|
|
32557
|
+
}
|
|
32558
|
+
const appId = evidence.appId.toLowerCase();
|
|
32559
|
+
if (!anchors.appIds.some((allowedAppId) => allowedAppId.toLowerCase() === appId)) {
|
|
32560
|
+
throw new Error("Enclave app ID is not trusted");
|
|
32561
|
+
}
|
|
32562
|
+
}
|
|
32563
|
+
async function buildMasterSignatureDelivery(evidence, masterSignature, now = Math.floor(Date.now() / 1e3)) {
|
|
32564
|
+
deriveMasterKey(masterSignature);
|
|
32565
|
+
const signerAddress = await recoverServerOwner(masterSignature);
|
|
32566
|
+
if (!isAddressEqual(signerAddress, evidence.ownerAddress)) {
|
|
32567
|
+
throw new Error("Master signature signer does not match evidence owner");
|
|
32568
|
+
}
|
|
32569
|
+
return {
|
|
32570
|
+
v: MASTER_SIGNATURE_DELIVERY_VERSION,
|
|
32571
|
+
userPsId: evidence.userPsId,
|
|
32572
|
+
epoch: evidence.epoch,
|
|
32573
|
+
enclaveAddress: evidence.address,
|
|
32574
|
+
ownerAddress: evidence.ownerAddress,
|
|
32575
|
+
masterSignature,
|
|
32576
|
+
issuedAt: now
|
|
32577
|
+
};
|
|
32578
|
+
}
|
|
32579
|
+
async function encryptMasterSignatureDelivery(delivery, publicKey, ecies) {
|
|
32580
|
+
assertUncompressedKey(publicKey);
|
|
32581
|
+
if (!isAddressEqual(publicKeyToAddress(publicKey), delivery.enclaveAddress)) {
|
|
32582
|
+
throw new Error(
|
|
32583
|
+
"Public key does not belong to the delivery's enclave address"
|
|
32584
|
+
);
|
|
32585
|
+
}
|
|
32586
|
+
const plaintext = toBytes(JSON.stringify(delivery));
|
|
32587
|
+
const encrypted = await ecies.encrypt(fromHex5(publicKey, "bytes"), plaintext);
|
|
32588
|
+
return `0x${serializeECIES(encrypted)}`;
|
|
32589
|
+
}
|
|
32590
|
+
|
|
32591
|
+
// src/protocol/jobs.ts
|
|
32592
|
+
var JOB_PROTOCOL_VERSION = 1;
|
|
32593
|
+
var JOB_OPERATIONS = ["raw_read", "inference"];
|
|
32594
|
+
var JOB_STATES = [
|
|
32595
|
+
"queued",
|
|
32596
|
+
"claimed",
|
|
32597
|
+
"running",
|
|
32598
|
+
"completed",
|
|
32599
|
+
"failed",
|
|
32600
|
+
"expired",
|
|
32601
|
+
"cancelled"
|
|
32602
|
+
];
|
|
32603
|
+
var DEFAULT_LEASE_SECONDS = 30;
|
|
32604
|
+
var MAX_LEASE_SECONDS = 300;
|
|
32605
|
+
var MAX_ATTEMPTS = 3;
|
|
32606
|
+
var MAX_WAIT_SECONDS = 25;
|
|
32607
|
+
var CLAIM_POLL_FLOOR_MS = 1e3;
|
|
32608
|
+
var MAX_INLINE_RESULT_BYTES = 1048576;
|
|
32609
|
+
var DEFAULT_JOB_DEADLINE_SECONDS = 600;
|
|
32610
|
+
var MAX_JOB_DEADLINE_SECONDS = 3600;
|
|
32611
|
+
|
|
32612
|
+
// src/protocol/jobs-client.ts
|
|
32613
|
+
import { randomUUID } from "node:crypto";
|
|
32614
|
+
import {
|
|
32615
|
+
isAddress as isAddress2,
|
|
32616
|
+
isHex as isHex2
|
|
32617
|
+
} from "viem";
|
|
32618
|
+
import { privateKeyToAccount, publicKeyToAddress as publicKeyToAddress2 } from "viem/accounts";
|
|
32619
|
+
|
|
32620
|
+
// src/crypto/envelope/job.ts
|
|
32621
|
+
init_interface();
|
|
32622
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha2";
|
|
32623
|
+
import { bytesToHex as bytesToHex2, fromHex as fromHex6, isAddress, isHex, toHex as toHex8 } from "viem";
|
|
32624
|
+
var textDecoder = new TextDecoder();
|
|
32625
|
+
var textEncoder = new TextEncoder();
|
|
32626
|
+
var JobEnvelopeError = class extends Error {
|
|
32627
|
+
constructor(message) {
|
|
32628
|
+
super(message);
|
|
32629
|
+
this.name = "JobEnvelopeError";
|
|
32630
|
+
}
|
|
32631
|
+
};
|
|
32632
|
+
function sortJsonKeys(value) {
|
|
32633
|
+
if (Array.isArray(value)) {
|
|
32634
|
+
return value.map(sortJsonKeys);
|
|
32635
|
+
}
|
|
32636
|
+
if (value !== null && typeof value === "object") {
|
|
32637
|
+
return Object.fromEntries(
|
|
32638
|
+
Object.keys(value).sort().map((key) => [
|
|
32639
|
+
key,
|
|
32640
|
+
sortJsonKeys(value[key])
|
|
32641
|
+
])
|
|
32642
|
+
);
|
|
32643
|
+
}
|
|
32644
|
+
return value;
|
|
32645
|
+
}
|
|
32646
|
+
function canonicalJsonBytes(value) {
|
|
32647
|
+
return textEncoder.encode(JSON.stringify(sortJsonKeys(value)));
|
|
32648
|
+
}
|
|
32649
|
+
function canonicalJobRequestBytes(request) {
|
|
32650
|
+
validateJobRequest(request);
|
|
32651
|
+
return canonicalJsonBytes(request);
|
|
32652
|
+
}
|
|
32653
|
+
function requestPlaintext(envelope) {
|
|
32654
|
+
validateRequestEnvelope(envelope);
|
|
32655
|
+
return canonicalJsonBytes(envelope);
|
|
32656
|
+
}
|
|
32657
|
+
function resultPlaintext(result) {
|
|
32658
|
+
return textEncoder.encode(
|
|
32659
|
+
JSON.stringify({
|
|
32660
|
+
v: result.v,
|
|
32661
|
+
jobId: result.jobId,
|
|
32662
|
+
scope: result.scope,
|
|
32663
|
+
version: result.version,
|
|
32664
|
+
contentType: result.contentType,
|
|
32665
|
+
body: result.body
|
|
32666
|
+
})
|
|
32667
|
+
);
|
|
32668
|
+
}
|
|
32669
|
+
function encryptedBytesToBase64(encrypted) {
|
|
32670
|
+
return toBase64(fromHex6(`0x${serializeECIES(encrypted)}`, "bytes"));
|
|
32671
|
+
}
|
|
32672
|
+
function base64ToEncrypted(ciphertext) {
|
|
32673
|
+
return deserializeECIES(toHex8(fromBase64(ciphertext)));
|
|
32674
|
+
}
|
|
32675
|
+
function parseObject(plaintext, kind) {
|
|
32676
|
+
try {
|
|
32677
|
+
const value = JSON.parse(textDecoder.decode(plaintext));
|
|
32678
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
32679
|
+
throw new JobEnvelopeError(`Invalid ${kind}: expected an object`);
|
|
32680
|
+
}
|
|
32681
|
+
return value;
|
|
32682
|
+
} catch (error) {
|
|
32683
|
+
if (error instanceof JobEnvelopeError) throw error;
|
|
32684
|
+
throw new JobEnvelopeError(`Invalid ${kind}: malformed JSON`);
|
|
32685
|
+
}
|
|
32686
|
+
}
|
|
32687
|
+
function isPlainObject2(value) {
|
|
32688
|
+
if (value === null || typeof value !== "object") return false;
|
|
32689
|
+
const prototype = Object.getPrototypeOf(value);
|
|
32690
|
+
return prototype === Object.prototype || prototype === null;
|
|
32691
|
+
}
|
|
32692
|
+
function requirePlainObject(value, field, kind) {
|
|
32693
|
+
if (!isPlainObject2(value)) {
|
|
32694
|
+
throw new JobEnvelopeError(`Invalid ${kind}: invalid ${field}`);
|
|
32695
|
+
}
|
|
32696
|
+
}
|
|
32697
|
+
function requireExactKeys(value, expectedKeys, kind) {
|
|
32698
|
+
for (const key of expectedKeys) {
|
|
32699
|
+
if (!Object.hasOwn(value, key) || value[key] === void 0) {
|
|
32700
|
+
throw new JobEnvelopeError(`Invalid ${kind}: missing ${key}`);
|
|
32701
|
+
}
|
|
32702
|
+
}
|
|
32703
|
+
const expected = new Set(expectedKeys);
|
|
32704
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
32705
|
+
if (!expected.has(key)) {
|
|
32706
|
+
throw new JobEnvelopeError(
|
|
32707
|
+
`Invalid ${kind}: unknown field ${String(key)}`
|
|
32708
|
+
);
|
|
32709
|
+
}
|
|
32710
|
+
}
|
|
32711
|
+
}
|
|
32712
|
+
function requireString(value, field, kind) {
|
|
32713
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
32714
|
+
throw new JobEnvelopeError(`Invalid ${kind}: missing ${field}`);
|
|
32715
|
+
}
|
|
32716
|
+
}
|
|
32717
|
+
function validateJobRequest(value) {
|
|
32718
|
+
requirePlainObject(value, "request", "job request");
|
|
32719
|
+
requireExactKeys(
|
|
32720
|
+
value,
|
|
32721
|
+
[
|
|
32722
|
+
"v",
|
|
32723
|
+
"jobId",
|
|
32724
|
+
"owner",
|
|
32725
|
+
"builder",
|
|
32726
|
+
"builderPublicKey",
|
|
32727
|
+
"grantId",
|
|
32728
|
+
"scope",
|
|
32729
|
+
"operation",
|
|
32730
|
+
"pinnedVersion",
|
|
32731
|
+
"deadline"
|
|
32732
|
+
],
|
|
32733
|
+
"job request"
|
|
32734
|
+
);
|
|
32735
|
+
if (value.v !== JOB_PROTOCOL_VERSION) {
|
|
32736
|
+
throw new JobEnvelopeError(
|
|
32737
|
+
`Unsupported job request version: ${String(value.v)}`
|
|
32738
|
+
);
|
|
32739
|
+
}
|
|
32740
|
+
requireString(value.jobId, "jobId", "job request");
|
|
32741
|
+
if (typeof value.owner !== "string" || !isAddress(value.owner)) {
|
|
32742
|
+
throw new JobEnvelopeError("Invalid job request: invalid owner");
|
|
32743
|
+
}
|
|
32744
|
+
if (typeof value.builder !== "string" || !isAddress(value.builder)) {
|
|
32745
|
+
throw new JobEnvelopeError("Invalid job request: invalid builder");
|
|
32746
|
+
}
|
|
32747
|
+
if (typeof value.builderPublicKey !== "string" || !isHex(value.builderPublicKey)) {
|
|
32748
|
+
throw new JobEnvelopeError("Invalid job request: invalid builderPublicKey");
|
|
32749
|
+
}
|
|
32750
|
+
if (typeof value.grantId !== "string" || !isHex(value.grantId)) {
|
|
32751
|
+
throw new JobEnvelopeError("Invalid job request: invalid grantId");
|
|
32752
|
+
}
|
|
32753
|
+
requireString(value.scope, "scope", "job request");
|
|
32754
|
+
if (!JOB_OPERATIONS.includes(value.operation)) {
|
|
32755
|
+
throw new JobEnvelopeError("Invalid job request: invalid operation");
|
|
32756
|
+
}
|
|
32757
|
+
if (value.pinnedVersion !== null && typeof value.pinnedVersion !== "string") {
|
|
32758
|
+
throw new JobEnvelopeError("Invalid job request: missing pinnedVersion");
|
|
32759
|
+
}
|
|
32760
|
+
if (typeof value.deadline !== "string" || !Number.isFinite(Date.parse(value.deadline))) {
|
|
32761
|
+
throw new JobEnvelopeError("Invalid job request: invalid deadline");
|
|
32762
|
+
}
|
|
32763
|
+
return value;
|
|
32764
|
+
}
|
|
32765
|
+
function validateRequestEnvelope(value) {
|
|
32766
|
+
requirePlainObject(value, "envelope", "job request envelope");
|
|
32767
|
+
requireExactKeys(value, ["request", "auth"], "job request envelope");
|
|
32768
|
+
validateJobRequest(value.request);
|
|
32769
|
+
requireString(value.auth, "auth", "job request envelope");
|
|
32770
|
+
return value;
|
|
32771
|
+
}
|
|
32772
|
+
function validateResult(value) {
|
|
32773
|
+
requirePlainObject(value, "result", "job result");
|
|
32774
|
+
requireExactKeys(
|
|
32775
|
+
value,
|
|
32776
|
+
["v", "jobId", "scope", "version", "contentType", "body"],
|
|
32777
|
+
"job result"
|
|
32778
|
+
);
|
|
32779
|
+
if (value.v !== JOB_PROTOCOL_VERSION) {
|
|
32780
|
+
throw new JobEnvelopeError(
|
|
32781
|
+
`Unsupported job result version: ${String(value.v)}`
|
|
32782
|
+
);
|
|
32783
|
+
}
|
|
32784
|
+
for (const field of ["jobId", "scope", "contentType"]) {
|
|
32785
|
+
requireString(value[field], field, "job result");
|
|
32786
|
+
}
|
|
32787
|
+
if (typeof value.body !== "string") {
|
|
32788
|
+
throw new JobEnvelopeError("Invalid job result: missing body");
|
|
32789
|
+
}
|
|
32790
|
+
if (value.version !== null && typeof value.version !== "string") {
|
|
32791
|
+
throw new JobEnvelopeError("Invalid job result: missing version");
|
|
32792
|
+
}
|
|
32793
|
+
return value;
|
|
32794
|
+
}
|
|
32795
|
+
async function sealJobRequest(envelope, enclavePublicKey, ecies) {
|
|
32796
|
+
const encrypted = await ecies.encrypt(
|
|
32797
|
+
fromHex6(enclavePublicKey, "bytes"),
|
|
32798
|
+
requestPlaintext(envelope)
|
|
32799
|
+
);
|
|
32800
|
+
return encryptedBytesToBase64(encrypted);
|
|
32801
|
+
}
|
|
32802
|
+
async function openJobRequest(ciphertext, privateKey, ecies) {
|
|
32803
|
+
const plaintext = await ecies.decrypt(
|
|
32804
|
+
privateKey,
|
|
32805
|
+
base64ToEncrypted(ciphertext)
|
|
32806
|
+
);
|
|
32807
|
+
return validateRequestEnvelope(
|
|
32808
|
+
parseObject(plaintext, "job request envelope")
|
|
32809
|
+
);
|
|
32810
|
+
}
|
|
32811
|
+
async function sealJobResult(result, builderPublicKey, ecies) {
|
|
32812
|
+
validateResult(result);
|
|
32813
|
+
const encrypted = await ecies.encrypt(
|
|
32814
|
+
fromHex6(builderPublicKey, "bytes"),
|
|
32815
|
+
resultPlaintext(result)
|
|
32816
|
+
);
|
|
32817
|
+
const ciphertext = encryptedBytesToBase64(encrypted);
|
|
32818
|
+
const bytes = fromBase64(ciphertext);
|
|
32819
|
+
return { ciphertext, hash: bytesToHex2(sha2565(bytes)), size: bytes.length };
|
|
32820
|
+
}
|
|
32821
|
+
async function openJobResult(ciphertext, builderPrivateKey, ecies, expect) {
|
|
32822
|
+
const plaintext = await ecies.decrypt(
|
|
32823
|
+
fromHex6(builderPrivateKey, "bytes"),
|
|
32824
|
+
base64ToEncrypted(ciphertext)
|
|
32825
|
+
);
|
|
32826
|
+
const result = validateResult(parseObject(plaintext, "job result"));
|
|
32827
|
+
if (result.jobId !== expect.jobId) {
|
|
32828
|
+
throw new JobEnvelopeError(
|
|
32829
|
+
`Job result ID ${result.jobId} does not match expected job ID ${expect.jobId}`
|
|
32830
|
+
);
|
|
32831
|
+
}
|
|
32832
|
+
if (expect.scope !== void 0 && result.scope !== expect.scope) {
|
|
32833
|
+
throw new JobEnvelopeError(
|
|
32834
|
+
`Job result scope ${result.scope} does not match expected scope ${expect.scope}`
|
|
32835
|
+
);
|
|
32836
|
+
}
|
|
32837
|
+
if (expect.version !== void 0 && result.version !== expect.version) {
|
|
32838
|
+
throw new JobEnvelopeError(
|
|
32839
|
+
`Job result version ${String(result.version)} does not match expected version ${String(expect.version)}`
|
|
32840
|
+
);
|
|
32841
|
+
}
|
|
32842
|
+
return result;
|
|
32843
|
+
}
|
|
32844
|
+
|
|
32845
|
+
// src/protocol/write-signer.ts
|
|
32846
|
+
function isRecord(value) {
|
|
32847
|
+
return value !== null && typeof value === "object";
|
|
32848
|
+
}
|
|
32849
|
+
function isViemWriteAccount(source) {
|
|
32850
|
+
return isRecord(source) && source.type === "local" && typeof source.address === "string" && typeof source.signMessage === "function";
|
|
32851
|
+
}
|
|
32852
|
+
function isViemWriteWalletClient(source) {
|
|
32853
|
+
return isRecord(source) && typeof source.signMessage === "function" && source.type !== "local" && (source.type === "walletClient" || "transport" in source);
|
|
32854
|
+
}
|
|
32855
|
+
function accountAddress(account) {
|
|
32856
|
+
return typeof account === "string" ? account : account.address;
|
|
32857
|
+
}
|
|
32858
|
+
function resolveWriteSigner(source, options = {}) {
|
|
32859
|
+
if (isViemWriteWalletClient(source)) {
|
|
32860
|
+
const account = options.account ?? source.account;
|
|
32861
|
+
if (account === void 0) {
|
|
32862
|
+
throw new WriteRequestError(
|
|
32863
|
+
"Viem wallet client requires an account option or account property"
|
|
32864
|
+
);
|
|
32865
|
+
}
|
|
32866
|
+
return {
|
|
32867
|
+
address: accountAddress(account),
|
|
32868
|
+
signMessage: (message) => source.signMessage({ account, message })
|
|
32869
|
+
};
|
|
32870
|
+
}
|
|
32871
|
+
if (isViemWriteAccount(source)) {
|
|
32872
|
+
return {
|
|
32873
|
+
address: source.address,
|
|
32874
|
+
signMessage: (message) => source.signMessage({ message })
|
|
32875
|
+
};
|
|
32876
|
+
}
|
|
32877
|
+
if (!isRecord(source) || typeof source.signMessage !== "function") {
|
|
32878
|
+
throw new WriteRequestError(
|
|
32879
|
+
"signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
|
|
32880
|
+
);
|
|
32881
|
+
}
|
|
32882
|
+
return source;
|
|
32883
|
+
}
|
|
32884
|
+
|
|
32885
|
+
// src/protocol/jobs-client.ts
|
|
32886
|
+
var IDENTITY_PATH = "/v1/identity";
|
|
32887
|
+
var JOBS_PATH = "/v1/jobs";
|
|
32888
|
+
var JOB_EXECUTE_PATH = "/v1/jobs/execute";
|
|
32889
|
+
var AUTHORIZATION_HEADER = "Authorization";
|
|
32890
|
+
var CONTENT_TYPE_HEADER = "Content-Type";
|
|
32891
|
+
var JSON_CONTENT_TYPE = "application/json";
|
|
32892
|
+
var GET_METHOD = "GET";
|
|
32893
|
+
var POST_METHOD = "POST";
|
|
32894
|
+
var RAW_READ_OPERATION = "raw_read";
|
|
32895
|
+
var SEALED_IDENTITY_STATE = "sealed";
|
|
32896
|
+
var HTTP_OK = 200;
|
|
32897
|
+
var HTTP_ACCEPTED = 202;
|
|
32898
|
+
var HTTP_FORBIDDEN = 403;
|
|
32899
|
+
var HTTP_NOT_FOUND = 404;
|
|
32900
|
+
var HTTP_CONFLICT = 409;
|
|
32901
|
+
var HTTP_PAYLOAD_TOO_LARGE = 413;
|
|
32902
|
+
var MILLISECONDS_PER_SECOND = 1e3;
|
|
32903
|
+
var DEFAULT_JOB_TIMEOUT_MS = 12e4;
|
|
32904
|
+
var DEFAULT_JOB_POLL_MS = CLAIM_POLL_FLOOR_MS;
|
|
32905
|
+
var TERMINAL_JOB_STATES = /* @__PURE__ */ new Set([
|
|
32906
|
+
"completed",
|
|
32907
|
+
"failed",
|
|
32908
|
+
"expired",
|
|
32909
|
+
"cancelled"
|
|
32910
|
+
]);
|
|
32911
|
+
function isRecord2(value) {
|
|
32912
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32913
|
+
}
|
|
32914
|
+
function normalizeGateway(gatewayUrl) {
|
|
32915
|
+
try {
|
|
32916
|
+
const url = new URL(gatewayUrl);
|
|
32917
|
+
if (url.pathname !== "/" || url.search !== "" || url.hash !== "") {
|
|
32918
|
+
throw new JobRejectedError(
|
|
32919
|
+
"gatewayUrl must be an origin without a path, query, or fragment"
|
|
32920
|
+
);
|
|
32921
|
+
}
|
|
32922
|
+
return {
|
|
32923
|
+
baseUrl: url.origin,
|
|
32924
|
+
audience: url.origin
|
|
32925
|
+
};
|
|
32926
|
+
} catch (error) {
|
|
32927
|
+
if (error instanceof JobRejectedError) throw error;
|
|
32928
|
+
throw new JobRejectedError(
|
|
32929
|
+
"gatewayUrl must be an absolute URL",
|
|
32930
|
+
void 0,
|
|
32931
|
+
null,
|
|
32932
|
+
{
|
|
32933
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
32934
|
+
}
|
|
32935
|
+
);
|
|
32936
|
+
}
|
|
32937
|
+
}
|
|
32938
|
+
function resolveFetch(fetchFn) {
|
|
32939
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
32940
|
+
if (resolved === void 0) {
|
|
32941
|
+
throw new JobRejectedError("No fetch implementation available");
|
|
32942
|
+
}
|
|
32943
|
+
return resolved;
|
|
32944
|
+
}
|
|
32945
|
+
function sourcePublicKey(source) {
|
|
32946
|
+
if (isRecord2(source) && typeof source["publicKey"] === "string") {
|
|
32947
|
+
return source["publicKey"];
|
|
32948
|
+
}
|
|
32949
|
+
return void 0;
|
|
32950
|
+
}
|
|
32951
|
+
function resolveBuilder(options) {
|
|
32952
|
+
if (options.builderPrivateKey && options.builderAccount) {
|
|
32953
|
+
throw new JobRejectedError(
|
|
32954
|
+
"Provide builderPrivateKey or builderAccount, not both"
|
|
32955
|
+
);
|
|
32956
|
+
}
|
|
32957
|
+
let source;
|
|
32958
|
+
try {
|
|
32959
|
+
source = options.builderPrivateKey ? privateKeyToAccount(options.builderPrivateKey) : options.builderAccount;
|
|
32960
|
+
} catch (error) {
|
|
32961
|
+
throw new JobRejectedError("Invalid builder private key", void 0, null, {
|
|
32962
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
32963
|
+
});
|
|
32964
|
+
}
|
|
32965
|
+
if (!source) {
|
|
32966
|
+
throw new JobRejectedError(
|
|
32967
|
+
"builderPrivateKey or builderAccount is required"
|
|
32968
|
+
);
|
|
32969
|
+
}
|
|
32970
|
+
let signer;
|
|
32971
|
+
try {
|
|
32972
|
+
signer = resolveWriteSigner(source);
|
|
32973
|
+
} catch (error) {
|
|
32974
|
+
throw new JobRejectedError("Invalid builder signer", void 0, null, {
|
|
32975
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
32976
|
+
});
|
|
32977
|
+
}
|
|
32978
|
+
const publicKey = sourcePublicKey(source);
|
|
32979
|
+
if (!signer.address || !publicKey) {
|
|
32980
|
+
throw new JobRejectedError(
|
|
32981
|
+
"Builder signer must expose both address and publicKey"
|
|
32982
|
+
);
|
|
32983
|
+
}
|
|
32984
|
+
return {
|
|
32985
|
+
builder: {
|
|
32986
|
+
address: signer.address,
|
|
32987
|
+
publicKey,
|
|
32988
|
+
signMessage: signer.signMessage
|
|
32989
|
+
},
|
|
32990
|
+
...options.builderPrivateKey ? { privateKey: options.builderPrivateKey } : {}
|
|
32991
|
+
};
|
|
32992
|
+
}
|
|
32993
|
+
function clampInteger(value, fallback, minimum, maximum, field) {
|
|
32994
|
+
const resolved = value ?? fallback;
|
|
32995
|
+
if (!Number.isFinite(resolved)) {
|
|
32996
|
+
throw new JobRejectedError(`${field} must be a finite number`);
|
|
32997
|
+
}
|
|
32998
|
+
return Math.min(maximum, Math.max(minimum, Math.trunc(resolved)));
|
|
32999
|
+
}
|
|
33000
|
+
async function responseBody(response) {
|
|
33001
|
+
try {
|
|
33002
|
+
return await response.json();
|
|
33003
|
+
} catch {
|
|
33004
|
+
return null;
|
|
33005
|
+
}
|
|
33006
|
+
}
|
|
33007
|
+
function gatewayErrorBody(body, fallback) {
|
|
33008
|
+
if (!isRecord2(body)) return { code: null, message: fallback };
|
|
33009
|
+
const code = typeof body["code"] === "string" ? body["code"] : null;
|
|
33010
|
+
const message = typeof body["error"] === "string" ? body["error"] : typeof body["message"] === "string" ? body["message"] : fallback;
|
|
33011
|
+
const details = isRecord2(body["details"]) ? body["details"] : void 0;
|
|
33012
|
+
return { code, message, ...details ? { details } : {} };
|
|
33013
|
+
}
|
|
33014
|
+
async function rejectedResponse(response, fallback) {
|
|
33015
|
+
const parsed = gatewayErrorBody(await responseBody(response), fallback);
|
|
33016
|
+
const details = parsed.details;
|
|
33017
|
+
if (response.status === HTTP_FORBIDDEN) {
|
|
33018
|
+
if (parsed.code === "BUILDER_UNKNOWN") {
|
|
33019
|
+
return new BuilderUnknownError(parsed.message, details);
|
|
33020
|
+
}
|
|
33021
|
+
if (parsed.code === "GRANT_INVALID") {
|
|
33022
|
+
return new GrantInvalidError(parsed.message, details);
|
|
33023
|
+
}
|
|
33024
|
+
if (parsed.code === "OWNER_NOT_READY") {
|
|
33025
|
+
return new OwnerNotReadyError(parsed.message, details);
|
|
33026
|
+
}
|
|
33027
|
+
}
|
|
33028
|
+
if (response.status === HTTP_NOT_FOUND) {
|
|
33029
|
+
return new JobNotFoundError(parsed.message, details);
|
|
33030
|
+
}
|
|
33031
|
+
if (response.status === HTTP_CONFLICT && parsed.code === "JOB_ID_TAKEN") {
|
|
33032
|
+
return new JobIdTakenError(parsed.message, details);
|
|
33033
|
+
}
|
|
33034
|
+
if (response.status === HTTP_PAYLOAD_TOO_LARGE) {
|
|
33035
|
+
return new JobRequestTooLargeError(parsed.message, parsed.code, details);
|
|
33036
|
+
}
|
|
33037
|
+
return new JobRejectedError(
|
|
33038
|
+
parsed.message,
|
|
33039
|
+
response.status,
|
|
33040
|
+
parsed.code,
|
|
33041
|
+
details
|
|
33042
|
+
);
|
|
33043
|
+
}
|
|
33044
|
+
function requireStatus(value, status) {
|
|
33045
|
+
if (!isRecord2(value) || !isNonEmptyString(value["jobId"]) || typeof value["state"] !== "string" || !JOB_STATES.includes(value["state"]) || !isNonEmptyString(value["owner"]) || !isNonEmptyString(value["grantId"]) || !isNonEmptyString(value["scope"]) || !isNonEmptyString(value["operation"]) || !JOB_OPERATIONS.includes(value["operation"])) {
|
|
33046
|
+
throw new JobRejectedError(
|
|
33047
|
+
"Gateway response did not contain a job status",
|
|
33048
|
+
status
|
|
33049
|
+
);
|
|
33050
|
+
}
|
|
33051
|
+
return value;
|
|
33052
|
+
}
|
|
33053
|
+
function isNonEmptyString(value) {
|
|
33054
|
+
return typeof value === "string" && value.length > 0;
|
|
33055
|
+
}
|
|
33056
|
+
function hasMatchingIdentityKey(value) {
|
|
33057
|
+
const address = value["address"];
|
|
33058
|
+
const publicKey = value["publicKey"];
|
|
33059
|
+
if (typeof address !== "string" || !isAddress2(address) || typeof publicKey !== "string" || !isHex2(publicKey)) {
|
|
33060
|
+
return false;
|
|
33061
|
+
}
|
|
33062
|
+
try {
|
|
33063
|
+
return publicKeyToAddress2(publicKey).toLowerCase() === address.toLowerCase();
|
|
33064
|
+
} catch {
|
|
33065
|
+
return false;
|
|
33066
|
+
}
|
|
33067
|
+
}
|
|
33068
|
+
function jobDeadline(job) {
|
|
33069
|
+
const candidate = job;
|
|
33070
|
+
for (const field of ["deadlineAt", "deadline"]) {
|
|
33071
|
+
if (typeof candidate[field] === "string") {
|
|
33072
|
+
const parsed = Date.parse(candidate[field]);
|
|
33073
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
33074
|
+
}
|
|
33075
|
+
}
|
|
33076
|
+
return void 0;
|
|
33077
|
+
}
|
|
33078
|
+
function sleep2(ms) {
|
|
33079
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
33080
|
+
}
|
|
33081
|
+
function requireFiniteDuration(value, field) {
|
|
33082
|
+
if (!Number.isFinite(value)) {
|
|
33083
|
+
throw new JobRejectedError(`${field} must be a finite number`);
|
|
33084
|
+
}
|
|
33085
|
+
return Math.max(0, value);
|
|
33086
|
+
}
|
|
33087
|
+
function createJobsClient(options) {
|
|
33088
|
+
const { baseUrl, audience } = normalizeGateway(options.gatewayUrl);
|
|
33089
|
+
const fetchFn = resolveFetch(options.fetch);
|
|
33090
|
+
const { builder, privateKey } = resolveBuilder(options);
|
|
33091
|
+
const ecies = options.ecies ?? new NodeECIESUint8Provider();
|
|
33092
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
33093
|
+
async function request(url, init, description) {
|
|
33094
|
+
try {
|
|
33095
|
+
return await fetchFn(url, init);
|
|
33096
|
+
} catch (error) {
|
|
33097
|
+
throw new JobTransportError(
|
|
33098
|
+
`${description} failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
33099
|
+
error
|
|
33100
|
+
);
|
|
33101
|
+
}
|
|
33102
|
+
}
|
|
33103
|
+
async function getIdentity(owner) {
|
|
33104
|
+
const query = new URLSearchParams({
|
|
33105
|
+
owner,
|
|
33106
|
+
chainId: String(options.chainId)
|
|
33107
|
+
});
|
|
33108
|
+
const response = await request(
|
|
33109
|
+
`${baseUrl}${IDENTITY_PATH}?${query.toString()}`,
|
|
33110
|
+
{ method: GET_METHOD },
|
|
33111
|
+
"Owner identity lookup"
|
|
33112
|
+
);
|
|
33113
|
+
if (!response.ok) {
|
|
33114
|
+
throw await rejectedResponse(response, "Owner identity lookup rejected");
|
|
33115
|
+
}
|
|
33116
|
+
const body = await responseBody(response);
|
|
33117
|
+
if (!isRecord2(body) || body["state"] !== SEALED_IDENTITY_STATE || !isRecord2(body["identity"])) {
|
|
33118
|
+
throw new OwnerNotReadyError("Owner identity is not sealed", {
|
|
33119
|
+
state: isRecord2(body) ? body["state"] : void 0
|
|
33120
|
+
});
|
|
33121
|
+
}
|
|
33122
|
+
if (!hasMatchingIdentityKey(body["identity"])) {
|
|
33123
|
+
throw new JobRejectedError(
|
|
33124
|
+
"Gateway returned a malformed or mismatched owner identity",
|
|
33125
|
+
response.status
|
|
33126
|
+
);
|
|
33127
|
+
}
|
|
33128
|
+
return body["identity"];
|
|
33129
|
+
}
|
|
33130
|
+
const client = {
|
|
33131
|
+
async submitRawRead(params) {
|
|
33132
|
+
const identity = await getIdentity(params.owner);
|
|
33133
|
+
const deadlineSeconds = clampInteger(
|
|
33134
|
+
params.deadlineSeconds,
|
|
33135
|
+
DEFAULT_JOB_DEADLINE_SECONDS,
|
|
33136
|
+
1,
|
|
33137
|
+
MAX_JOB_DEADLINE_SECONDS,
|
|
33138
|
+
"deadlineSeconds"
|
|
33139
|
+
);
|
|
33140
|
+
const wait = clampInteger(params.wait, 0, 0, MAX_WAIT_SECONDS, "wait");
|
|
33141
|
+
const jobId = randomUUID();
|
|
33142
|
+
const nowMs = now().getTime();
|
|
33143
|
+
if (!Number.isFinite(nowMs)) {
|
|
33144
|
+
throw new JobRejectedError("now must return a valid Date");
|
|
33145
|
+
}
|
|
33146
|
+
const deadline = new Date(
|
|
33147
|
+
nowMs + deadlineSeconds * MILLISECONDS_PER_SECOND
|
|
33148
|
+
).toISOString();
|
|
33149
|
+
const requestBody = {
|
|
33150
|
+
v: JOB_PROTOCOL_VERSION,
|
|
33151
|
+
jobId,
|
|
33152
|
+
owner: params.owner,
|
|
33153
|
+
builder: builder.address,
|
|
33154
|
+
builderPublicKey: builder.publicKey,
|
|
33155
|
+
grantId: params.grantId,
|
|
33156
|
+
scope: params.scope,
|
|
33157
|
+
operation: RAW_READ_OPERATION,
|
|
33158
|
+
pinnedVersion: params.pinnedVersion ?? null,
|
|
33159
|
+
deadline
|
|
33160
|
+
};
|
|
33161
|
+
const auth = await buildWeb3SignedHeader({
|
|
33162
|
+
signMessage: builder.signMessage,
|
|
33163
|
+
aud: audience,
|
|
33164
|
+
method: POST_METHOD,
|
|
33165
|
+
uri: JOB_EXECUTE_PATH,
|
|
33166
|
+
bodyHash: computeBodyHash(canonicalJobRequestBytes(requestBody)),
|
|
33167
|
+
nonce: randomUUID()
|
|
33168
|
+
});
|
|
33169
|
+
const requestCiphertext = await sealJobRequest(
|
|
33170
|
+
{ request: requestBody, auth },
|
|
33171
|
+
identity.publicKey,
|
|
33172
|
+
ecies
|
|
33173
|
+
);
|
|
33174
|
+
const submission = {
|
|
33175
|
+
owner: requestBody.owner,
|
|
33176
|
+
grantId: requestBody.grantId,
|
|
33177
|
+
scope: requestBody.scope,
|
|
33178
|
+
operation: requestBody.operation,
|
|
33179
|
+
idempotencyKey: randomUUID(),
|
|
33180
|
+
jobId,
|
|
33181
|
+
deadline,
|
|
33182
|
+
requestCiphertext
|
|
33183
|
+
};
|
|
33184
|
+
const bodyBytes = new TextEncoder().encode(JSON.stringify(submission));
|
|
33185
|
+
const authorization = await buildWeb3SignedHeader({
|
|
33186
|
+
signMessage: builder.signMessage,
|
|
33187
|
+
aud: audience,
|
|
33188
|
+
method: POST_METHOD,
|
|
33189
|
+
uri: JOBS_PATH,
|
|
33190
|
+
body: bodyBytes,
|
|
33191
|
+
nonce: randomUUID()
|
|
33192
|
+
});
|
|
33193
|
+
const response = await request(
|
|
33194
|
+
`${baseUrl}${JOBS_PATH}?wait=${wait}`,
|
|
33195
|
+
{
|
|
33196
|
+
method: POST_METHOD,
|
|
33197
|
+
headers: {
|
|
33198
|
+
[AUTHORIZATION_HEADER]: authorization,
|
|
33199
|
+
[CONTENT_TYPE_HEADER]: JSON_CONTENT_TYPE
|
|
33200
|
+
},
|
|
33201
|
+
body: bodyBytes
|
|
33202
|
+
},
|
|
33203
|
+
"Job submission"
|
|
33204
|
+
);
|
|
33205
|
+
if (!response.ok) {
|
|
33206
|
+
throw await rejectedResponse(response, "Job submission rejected");
|
|
33207
|
+
}
|
|
33208
|
+
const body = await responseBody(response);
|
|
33209
|
+
if (response.status === HTTP_OK && isRecord2(body)) {
|
|
33210
|
+
const job = requireStatus(body["job"], response.status);
|
|
33211
|
+
if (job.jobId !== jobId) {
|
|
33212
|
+
throw new JobRejectedError(
|
|
33213
|
+
"Gateway returned a job id that does not match the submission",
|
|
33214
|
+
response.status
|
|
33215
|
+
);
|
|
33216
|
+
}
|
|
33217
|
+
return { jobId, state: job.state, job };
|
|
33218
|
+
}
|
|
33219
|
+
if (response.status === HTTP_ACCEPTED && isRecord2(body) && body["jobId"] === jobId && typeof body["state"] === "string" && JOB_STATES.includes(body["state"])) {
|
|
33220
|
+
return { jobId, state: body["state"] };
|
|
33221
|
+
}
|
|
33222
|
+
throw new JobRejectedError(
|
|
33223
|
+
"Gateway returned an undocumented job submission response",
|
|
33224
|
+
response.status
|
|
33225
|
+
);
|
|
33226
|
+
},
|
|
33227
|
+
async getJob(jobId) {
|
|
33228
|
+
const path = `${JOBS_PATH}/${encodeURIComponent(jobId)}`;
|
|
33229
|
+
const authorization = await buildWeb3SignedHeader({
|
|
33230
|
+
signMessage: builder.signMessage,
|
|
33231
|
+
aud: audience,
|
|
33232
|
+
method: GET_METHOD,
|
|
33233
|
+
uri: path,
|
|
33234
|
+
nonce: randomUUID()
|
|
33235
|
+
});
|
|
33236
|
+
const response = await request(
|
|
33237
|
+
`${baseUrl}${path}`,
|
|
33238
|
+
{
|
|
33239
|
+
method: GET_METHOD,
|
|
33240
|
+
headers: { [AUTHORIZATION_HEADER]: authorization }
|
|
33241
|
+
},
|
|
33242
|
+
"Job status read"
|
|
33243
|
+
);
|
|
33244
|
+
if (!response.ok) {
|
|
33245
|
+
throw await rejectedResponse(response, "Job status read rejected");
|
|
33246
|
+
}
|
|
33247
|
+
const body = await responseBody(response);
|
|
33248
|
+
return requireStatus(
|
|
33249
|
+
isRecord2(body) ? body["job"] : void 0,
|
|
33250
|
+
response.status
|
|
33251
|
+
);
|
|
33252
|
+
},
|
|
33253
|
+
async waitForJob(jobId, waitOptions = {}) {
|
|
33254
|
+
const timeoutMs = requireFiniteDuration(
|
|
33255
|
+
waitOptions.timeoutMs ?? DEFAULT_JOB_TIMEOUT_MS,
|
|
33256
|
+
"timeoutMs"
|
|
33257
|
+
);
|
|
33258
|
+
const pollMs = Math.max(
|
|
33259
|
+
CLAIM_POLL_FLOOR_MS,
|
|
33260
|
+
requireFiniteDuration(
|
|
33261
|
+
waitOptions.pollMs ?? DEFAULT_JOB_POLL_MS,
|
|
33262
|
+
"pollMs"
|
|
33263
|
+
)
|
|
33264
|
+
);
|
|
33265
|
+
const startedAt = Date.now();
|
|
33266
|
+
const callerDeadline = startedAt + timeoutMs;
|
|
33267
|
+
let latest;
|
|
33268
|
+
for (; ; ) {
|
|
33269
|
+
if (Date.now() >= callerDeadline || latest && Date.now() >= (jobDeadline(latest) ?? Infinity)) {
|
|
33270
|
+
throw new JobTimeoutError(
|
|
33271
|
+
`Timed out waiting for terminal job ${jobId}`,
|
|
33272
|
+
{
|
|
33273
|
+
jobId,
|
|
33274
|
+
timeoutMs,
|
|
33275
|
+
state: latest?.state
|
|
33276
|
+
}
|
|
33277
|
+
);
|
|
33278
|
+
}
|
|
33279
|
+
latest = await client.getJob(jobId);
|
|
33280
|
+
if (TERMINAL_JOB_STATES.has(latest.state)) return latest;
|
|
33281
|
+
const effectiveDeadline = Math.min(
|
|
33282
|
+
callerDeadline,
|
|
33283
|
+
jobDeadline(latest) ?? Infinity
|
|
33284
|
+
);
|
|
33285
|
+
const remaining = effectiveDeadline - Date.now();
|
|
33286
|
+
if (remaining <= 0) {
|
|
33287
|
+
throw new JobTimeoutError(
|
|
33288
|
+
`Timed out waiting for terminal job ${jobId}`,
|
|
33289
|
+
{
|
|
33290
|
+
jobId,
|
|
33291
|
+
timeoutMs,
|
|
33292
|
+
state: latest.state
|
|
33293
|
+
}
|
|
33294
|
+
);
|
|
33295
|
+
}
|
|
33296
|
+
await sleep2(Math.min(pollMs, remaining));
|
|
33297
|
+
}
|
|
33298
|
+
},
|
|
33299
|
+
async openResult(job, openOptions) {
|
|
33300
|
+
if (!job.resultCiphertext) {
|
|
33301
|
+
throw new JobRejectedError(
|
|
33302
|
+
"Job status does not include inline resultCiphertext",
|
|
33303
|
+
void 0,
|
|
33304
|
+
null,
|
|
33305
|
+
{
|
|
33306
|
+
jobId: job.jobId,
|
|
33307
|
+
state: job.state,
|
|
33308
|
+
resultHandle: job.resultHandle,
|
|
33309
|
+
maxInlineResultBytes: MAX_INLINE_RESULT_BYTES
|
|
33310
|
+
}
|
|
33311
|
+
);
|
|
33312
|
+
}
|
|
33313
|
+
if (!privateKey) {
|
|
33314
|
+
throw new JobRejectedError(
|
|
33315
|
+
"openResult requires createJobsClient({ builderPrivateKey })"
|
|
33316
|
+
);
|
|
33317
|
+
}
|
|
33318
|
+
return openJobResult(
|
|
33319
|
+
job.resultCiphertext,
|
|
33320
|
+
privateKey,
|
|
33321
|
+
ecies,
|
|
33322
|
+
openOptions.expect
|
|
33323
|
+
);
|
|
33324
|
+
},
|
|
33325
|
+
async readRaw(params) {
|
|
33326
|
+
const submitted = await client.submitRawRead(params);
|
|
33327
|
+
const job = submitted.job && TERMINAL_JOB_STATES.has(submitted.job.state) ? submitted.job : await client.waitForJob(submitted.jobId, {
|
|
33328
|
+
timeoutMs: params.timeoutMs,
|
|
33329
|
+
pollMs: params.pollMs
|
|
33330
|
+
});
|
|
33331
|
+
return client.openResult(job, {
|
|
33332
|
+
expect: {
|
|
33333
|
+
jobId: submitted.jobId,
|
|
33334
|
+
scope: params.scope,
|
|
33335
|
+
...params.pinnedVersion !== void 0 && params.pinnedVersion !== null ? { version: params.pinnedVersion } : {}
|
|
33336
|
+
}
|
|
33337
|
+
});
|
|
33338
|
+
}
|
|
33339
|
+
};
|
|
33340
|
+
return client;
|
|
33341
|
+
}
|
|
33342
|
+
|
|
32366
33343
|
// src/protocol/personal-server-registration.ts
|
|
32367
33344
|
import {
|
|
32368
|
-
isAddress
|
|
33345
|
+
isAddress as isAddress3
|
|
32369
33346
|
} from "viem";
|
|
32370
33347
|
var PERSONAL_SERVER_REGISTRATION_DEFAULT_CHAIN_ID = vanaMainnet2.id;
|
|
32371
33348
|
var PERSONAL_SERVER_REGISTRATION_DEFAULT_VERIFYING_CONTRACT = getContractAddress(
|
|
@@ -32373,7 +33350,7 @@ var PERSONAL_SERVER_REGISTRATION_DEFAULT_VERIFYING_CONTRACT = getContractAddress
|
|
|
32373
33350
|
"DataPortabilityServers"
|
|
32374
33351
|
);
|
|
32375
33352
|
function assertAddress(value, name) {
|
|
32376
|
-
if (!
|
|
33353
|
+
if (!isAddress3(value)) {
|
|
32377
33354
|
throw new Error(`${name} must be a valid EVM address`);
|
|
32378
33355
|
}
|
|
32379
33356
|
}
|
|
@@ -32460,13 +33437,13 @@ var registerPersonalServerSignature = buildPersonalServerRegistrationSignature;
|
|
|
32460
33437
|
|
|
32461
33438
|
// src/personal-server-lite/owner-binding.ts
|
|
32462
33439
|
import {
|
|
32463
|
-
isAddress as
|
|
33440
|
+
isAddress as isAddress4
|
|
32464
33441
|
} from "viem";
|
|
32465
33442
|
var PERSONAL_SERVER_LITE_OWNER_BINDING_VERSION = "vana.ps-lite.owner-binding.v1";
|
|
32466
33443
|
var PERSONAL_SERVER_LITE_OWNER_BINDING_PURPOSE = "ps-lite-owner";
|
|
32467
33444
|
var PERSONAL_SERVER_LITE_OWNER_BINDING_PREFIX = `${PERSONAL_SERVER_LITE_OWNER_BINDING_VERSION}:${PERSONAL_SERVER_LITE_OWNER_BINDING_PURPOSE}:`;
|
|
32468
33445
|
function assertAddress2(value, name) {
|
|
32469
|
-
if (!
|
|
33446
|
+
if (!isAddress4(value)) {
|
|
32470
33447
|
throw new Error(`${name} must be a valid EVM address`);
|
|
32471
33448
|
}
|
|
32472
33449
|
}
|
|
@@ -32516,7 +33493,7 @@ async function buildPersonalServerLiteOwnerBindingSignature(input) {
|
|
|
32516
33493
|
var signPersonalServerLiteOwnerBinding = buildPersonalServerLiteOwnerBindingSignature;
|
|
32517
33494
|
|
|
32518
33495
|
// src/account/personal-server-registration.ts
|
|
32519
|
-
import { isAddress as
|
|
33496
|
+
import { isAddress as isAddress5 } from "viem";
|
|
32520
33497
|
var ACCOUNT_PERSONAL_SERVER_REGISTRATION_INTENT = "personal_server.server_registration.v1";
|
|
32521
33498
|
var AccountPersonalServerRegistrationError = class extends Error {
|
|
32522
33499
|
status;
|
|
@@ -32535,7 +33512,7 @@ function trimTrailingSlash(value) {
|
|
|
32535
33512
|
return value.replace(/\/+$/, "");
|
|
32536
33513
|
}
|
|
32537
33514
|
function assertAddress3(value, name) {
|
|
32538
|
-
if (!
|
|
33515
|
+
if (!isAddress5(value)) {
|
|
32539
33516
|
throw new Error(`${name} must be a valid EVM address`);
|
|
32540
33517
|
}
|
|
32541
33518
|
}
|
|
@@ -32556,7 +33533,7 @@ function accountErrorMessage(status, body) {
|
|
|
32556
33533
|
if (nestedMessage) {
|
|
32557
33534
|
return nestedMessage;
|
|
32558
33535
|
}
|
|
32559
|
-
if (
|
|
33536
|
+
if (isRecord3(body) && typeof body.message === "string") {
|
|
32560
33537
|
return body.message;
|
|
32561
33538
|
}
|
|
32562
33539
|
const code = accountErrorCode(body);
|
|
@@ -32570,7 +33547,7 @@ function accountErrorCode(body) {
|
|
|
32570
33547
|
if (nestedCode) {
|
|
32571
33548
|
return nestedCode;
|
|
32572
33549
|
}
|
|
32573
|
-
if (
|
|
33550
|
+
if (isRecord3(body)) {
|
|
32574
33551
|
if (typeof body.code === "string") {
|
|
32575
33552
|
return body.code;
|
|
32576
33553
|
}
|
|
@@ -32581,13 +33558,13 @@ function accountErrorCode(body) {
|
|
|
32581
33558
|
return void 0;
|
|
32582
33559
|
}
|
|
32583
33560
|
function nestedAccountErrorField(body, field) {
|
|
32584
|
-
if (!
|
|
33561
|
+
if (!isRecord3(body) || !isRecord3(body.error)) {
|
|
32585
33562
|
return void 0;
|
|
32586
33563
|
}
|
|
32587
33564
|
const value = body.error[field];
|
|
32588
33565
|
return typeof value === "string" ? value : void 0;
|
|
32589
33566
|
}
|
|
32590
|
-
function
|
|
33567
|
+
function isRecord3(value) {
|
|
32591
33568
|
return typeof value === "object" && value !== null;
|
|
32592
33569
|
}
|
|
32593
33570
|
function normalizeAccountResponse(response) {
|
|
@@ -33061,8 +34038,8 @@ function buildMarkDataPointUnavailableRequest(config, input) {
|
|
|
33061
34038
|
|
|
33062
34039
|
// src/protocol/data-point-deletion.ts
|
|
33063
34040
|
import {
|
|
33064
|
-
isAddress as
|
|
33065
|
-
keccak256 as
|
|
34041
|
+
isAddress as isAddress7,
|
|
34042
|
+
keccak256 as keccak2563,
|
|
33066
34043
|
maxUint256,
|
|
33067
34044
|
stringToBytes as stringToBytes3
|
|
33068
34045
|
} from "viem";
|
|
@@ -33070,13 +34047,13 @@ import {
|
|
|
33070
34047
|
// src/protocol/lineage.ts
|
|
33071
34048
|
import {
|
|
33072
34049
|
encodeAbiParameters,
|
|
33073
|
-
isAddress as
|
|
33074
|
-
keccak256
|
|
34050
|
+
isAddress as isAddress6,
|
|
34051
|
+
keccak256 as keccak2562
|
|
33075
34052
|
} from "viem";
|
|
33076
34053
|
import { z } from "zod";
|
|
33077
34054
|
|
|
33078
34055
|
// src/protocol/personal-server-error-body.ts
|
|
33079
|
-
function
|
|
34056
|
+
function isRecord4(value) {
|
|
33080
34057
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
33081
34058
|
}
|
|
33082
34059
|
async function readPersonalServerErrorBody(response) {
|
|
@@ -33086,8 +34063,8 @@ async function readPersonalServerErrorBody(response) {
|
|
|
33086
34063
|
} catch {
|
|
33087
34064
|
return { errorCode: null, message: null };
|
|
33088
34065
|
}
|
|
33089
|
-
if (!
|
|
33090
|
-
const nested =
|
|
34066
|
+
if (!isRecord4(body)) return { errorCode: null, message: null };
|
|
34067
|
+
const nested = isRecord4(body.error) ? body.error : null;
|
|
33091
34068
|
const gatewayShape = typeof body.error === "string" && typeof body.code === "string";
|
|
33092
34069
|
const code = nested?.errorCode ?? nested?.code ?? body.errorCode ?? (gatewayShape ? body.code : void 0) ?? (typeof body.error === "string" ? body.error : void 0) ?? body.code;
|
|
33093
34070
|
const message = nested?.message ?? body.message ?? (gatewayShape ? body.error : void 0);
|
|
@@ -33100,62 +34077,22 @@ async function readPersonalServerErrorBody(response) {
|
|
|
33100
34077
|
return {
|
|
33101
34078
|
errorCode: typeof code === "string" ? code : null,
|
|
33102
34079
|
message: typeof message === "string" ? message : null,
|
|
33103
|
-
...
|
|
34080
|
+
...isRecord4(details) ? { details } : {}
|
|
33104
34081
|
};
|
|
33105
34082
|
}
|
|
33106
34083
|
|
|
33107
|
-
// src/protocol/write-signer.ts
|
|
33108
|
-
function isRecord3(value) {
|
|
33109
|
-
return value !== null && typeof value === "object";
|
|
33110
|
-
}
|
|
33111
|
-
function isViemWriteAccount(source) {
|
|
33112
|
-
return isRecord3(source) && source.type === "local" && typeof source.address === "string" && typeof source.signMessage === "function";
|
|
33113
|
-
}
|
|
33114
|
-
function isViemWriteWalletClient(source) {
|
|
33115
|
-
return isRecord3(source) && typeof source.signMessage === "function" && source.type !== "local" && (source.type === "walletClient" || "transport" in source);
|
|
33116
|
-
}
|
|
33117
|
-
function accountAddress(account) {
|
|
33118
|
-
return typeof account === "string" ? account : account.address;
|
|
33119
|
-
}
|
|
33120
|
-
function resolveWriteSigner(source, options = {}) {
|
|
33121
|
-
if (isViemWriteWalletClient(source)) {
|
|
33122
|
-
const account = options.account ?? source.account;
|
|
33123
|
-
if (account === void 0) {
|
|
33124
|
-
throw new WriteRequestError(
|
|
33125
|
-
"Viem wallet client requires an account option or account property"
|
|
33126
|
-
);
|
|
33127
|
-
}
|
|
33128
|
-
return {
|
|
33129
|
-
address: accountAddress(account),
|
|
33130
|
-
signMessage: (message) => source.signMessage({ account, message })
|
|
33131
|
-
};
|
|
33132
|
-
}
|
|
33133
|
-
if (isViemWriteAccount(source)) {
|
|
33134
|
-
return {
|
|
33135
|
-
address: source.address,
|
|
33136
|
-
signMessage: (message) => source.signMessage({ message })
|
|
33137
|
-
};
|
|
33138
|
-
}
|
|
33139
|
-
if (!isRecord3(source) || typeof source.signMessage !== "function") {
|
|
33140
|
-
throw new WriteRequestError(
|
|
33141
|
-
"signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
|
|
33142
|
-
);
|
|
33143
|
-
}
|
|
33144
|
-
return source;
|
|
33145
|
-
}
|
|
33146
|
-
|
|
33147
34084
|
// src/protocol/lineage.ts
|
|
33148
34085
|
var DATA_POINT_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;
|
|
33149
34086
|
function isDataPointId(value) {
|
|
33150
34087
|
return typeof value === "string" && DATA_POINT_ID_PATTERN.test(value);
|
|
33151
34088
|
}
|
|
33152
34089
|
function deriveDataPointId(ownerAddress, scope) {
|
|
33153
|
-
if (!
|
|
34090
|
+
if (!isAddress6(ownerAddress, { strict: false })) {
|
|
33154
34091
|
throw new Error(
|
|
33155
34092
|
`ownerAddress is not an EVM address: ${String(ownerAddress)}`
|
|
33156
34093
|
);
|
|
33157
34094
|
}
|
|
33158
|
-
return
|
|
34095
|
+
return keccak2562(
|
|
33159
34096
|
encodeAbiParameters(
|
|
33160
34097
|
[
|
|
33161
34098
|
{ name: "ownerAddress", type: "address" },
|
|
@@ -33245,7 +34182,7 @@ function gatewayLineagePath(dataPointId, version) {
|
|
|
33245
34182
|
function normalizeBaseUrl(url) {
|
|
33246
34183
|
return url.replace(/\/+$/, "");
|
|
33247
34184
|
}
|
|
33248
|
-
function
|
|
34185
|
+
function resolveFetch2(fetchFn) {
|
|
33249
34186
|
const resolved = fetchFn ?? globalThis.fetch;
|
|
33250
34187
|
if (resolved === void 0) {
|
|
33251
34188
|
throw new LineageReadError("No fetch implementation available");
|
|
@@ -33286,7 +34223,7 @@ async function parseLineageGraph(source, response) {
|
|
|
33286
34223
|
{ cause: err instanceof Error ? err.message : String(err) }
|
|
33287
34224
|
);
|
|
33288
34225
|
}
|
|
33289
|
-
const envelope =
|
|
34226
|
+
const envelope = isRecord4(body) && isRecord4(body.data) ? body : void 0;
|
|
33290
34227
|
const parsed = LineageGraphSchema.safeParse(envelope?.data ?? body);
|
|
33291
34228
|
if (!parsed.success) {
|
|
33292
34229
|
throw new LineageReadError(
|
|
@@ -33296,7 +34233,7 @@ async function parseLineageGraph(source, response) {
|
|
|
33296
34233
|
{ issues: parsed.error.issues }
|
|
33297
34234
|
);
|
|
33298
34235
|
}
|
|
33299
|
-
const proof =
|
|
34236
|
+
const proof = isRecord4(envelope?.proof) ? envelope.proof : void 0;
|
|
33300
34237
|
return proof === void 0 ? parsed.data : { ...parsed.data, proof };
|
|
33301
34238
|
}
|
|
33302
34239
|
async function sendLineageRead(source, fetchFn, url, headers) {
|
|
@@ -33317,7 +34254,7 @@ async function sendLineageRead(source, fetchFn, url, headers) {
|
|
|
33317
34254
|
return parseLineageGraph(source, response);
|
|
33318
34255
|
}
|
|
33319
34256
|
async function getPersonalServerLineage(params) {
|
|
33320
|
-
const fetchFn =
|
|
34257
|
+
const fetchFn = resolveFetch2(params.fetch);
|
|
33321
34258
|
const baseUrl = normalizeBaseUrl(params.personalServerUrl);
|
|
33322
34259
|
const audience = params.audience ?? baseUrl;
|
|
33323
34260
|
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
@@ -33352,7 +34289,7 @@ async function getGatewayLineage(params) {
|
|
|
33352
34289
|
{ dataPointId: params.dataPointId }
|
|
33353
34290
|
);
|
|
33354
34291
|
}
|
|
33355
|
-
const fetchFn =
|
|
34292
|
+
const fetchFn = resolveFetch2(params.fetch);
|
|
33356
34293
|
const baseUrl = normalizeBaseUrl(params.gatewayUrl);
|
|
33357
34294
|
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
33358
34295
|
const uri = gatewayLineagePath(
|
|
@@ -33382,7 +34319,7 @@ var TOMBSTONE_METADATA_HASH_PREIMAGE = "vana.data-point.tombstone.metadata.v1";
|
|
|
33382
34319
|
var TOMBSTONE_DATA_HASH = "0x30c45ee72fe56d1927701316925ab7ceacd3b6f9267061735d59396f075c6222";
|
|
33383
34320
|
var TOMBSTONE_METADATA_HASH = "0xc5255a141acd6a2ae55971b62c0a85977c2511989dc114ad2abc2b7644f57d90";
|
|
33384
34321
|
function computeTombstoneHash(preimage) {
|
|
33385
|
-
return
|
|
34322
|
+
return keccak2563(stringToBytes3(preimage));
|
|
33386
34323
|
}
|
|
33387
34324
|
function isTombstoneHashes(dataHash, metadataHash) {
|
|
33388
34325
|
return typeof dataHash === "string" && typeof metadataHash === "string" && dataHash.toLowerCase() === TOMBSTONE_DATA_HASH && metadataHash.toLowerCase() === TOMBSTONE_METADATA_HASH;
|
|
@@ -33401,7 +34338,7 @@ function tombstoneDeletedAt(value) {
|
|
|
33401
34338
|
return typeof deletedAt === "string" ? deletedAt : null;
|
|
33402
34339
|
}
|
|
33403
34340
|
function assertAddress4(value, name) {
|
|
33404
|
-
if (!
|
|
34341
|
+
if (!isAddress7(value)) {
|
|
33405
34342
|
throw new Error(`${name} must be a valid EVM address`);
|
|
33406
34343
|
}
|
|
33407
34344
|
}
|
|
@@ -33816,17 +34753,17 @@ function tryGrantPermissions(scopes) {
|
|
|
33816
34753
|
}
|
|
33817
34754
|
|
|
33818
34755
|
// src/protocol/personal-server-write.ts
|
|
33819
|
-
import { sha256 as
|
|
33820
|
-
import { bytesToHex as
|
|
34756
|
+
import { sha256 as sha2567 } from "@noble/hashes/sha2";
|
|
34757
|
+
import { bytesToHex as bytesToHex4, isAddress as isAddress8 } from "viem";
|
|
33821
34758
|
import { z as z4 } from "zod";
|
|
33822
34759
|
|
|
33823
34760
|
// src/protocol/write-request.ts
|
|
33824
|
-
import { sha256 as
|
|
33825
|
-
import { bytesToHex as
|
|
34761
|
+
import { sha256 as sha2566 } from "@noble/hashes/sha2";
|
|
34762
|
+
import { bytesToHex as bytesToHex3 } from "viem";
|
|
33826
34763
|
function normalizeBaseUrl2(url) {
|
|
33827
34764
|
return url.replace(/\/+$/, "");
|
|
33828
34765
|
}
|
|
33829
|
-
function
|
|
34766
|
+
function resolveFetch3(fetchFn) {
|
|
33830
34767
|
const resolved = fetchFn ?? globalThis.fetch;
|
|
33831
34768
|
if (resolved === void 0) {
|
|
33832
34769
|
throw new WriteRequestError("No fetch implementation available");
|
|
@@ -33839,7 +34776,7 @@ function errorMessage(err) {
|
|
|
33839
34776
|
function finiteOr(value, fallback) {
|
|
33840
34777
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
33841
34778
|
}
|
|
33842
|
-
function
|
|
34779
|
+
function sleep3(ms) {
|
|
33843
34780
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
33844
34781
|
}
|
|
33845
34782
|
var issuedProofIats = /* @__PURE__ */ new Map();
|
|
@@ -33881,7 +34818,7 @@ function nextProofIat(proofKey) {
|
|
|
33881
34818
|
setIssuedProofIat(proofKey, iat, last);
|
|
33882
34819
|
const waitSec = iat - nowSec - PROOF_IAT_MAX_AHEAD_SECONDS;
|
|
33883
34820
|
if (waitSec <= 0) return Promise.resolve(iat);
|
|
33884
|
-
return
|
|
34821
|
+
return sleep3(waitSec * 1e3).then(() => iat);
|
|
33885
34822
|
}
|
|
33886
34823
|
function freshProofNonce() {
|
|
33887
34824
|
const webCrypto = globalThis.crypto;
|
|
@@ -33889,22 +34826,22 @@ function freshProofNonce() {
|
|
|
33889
34826
|
return webCrypto.randomUUID();
|
|
33890
34827
|
}
|
|
33891
34828
|
if (typeof webCrypto?.getRandomValues === "function") {
|
|
33892
|
-
return
|
|
34829
|
+
return bytesToHex3(webCrypto.getRandomValues(new Uint8Array(16)));
|
|
33893
34830
|
}
|
|
33894
34831
|
throw new WriteRequestError(
|
|
33895
34832
|
"No secure random source available to build a proof nonce; provide a crypto global"
|
|
33896
34833
|
);
|
|
33897
34834
|
}
|
|
33898
34835
|
function proofKeyFor(parts) {
|
|
33899
|
-
return
|
|
33900
|
-
|
|
34836
|
+
return bytesToHex3(
|
|
34837
|
+
sha2566(
|
|
33901
34838
|
new TextEncoder().encode(
|
|
33902
34839
|
JSON.stringify([
|
|
33903
34840
|
parts.aud,
|
|
33904
34841
|
parts.method,
|
|
33905
34842
|
parts.uri,
|
|
33906
34843
|
parts.grantId,
|
|
33907
|
-
parts.signedBytes ?
|
|
34844
|
+
parts.signedBytes ? bytesToHex3(sha2566(parts.signedBytes)) : ""
|
|
33908
34845
|
])
|
|
33909
34846
|
)
|
|
33910
34847
|
)
|
|
@@ -33922,7 +34859,7 @@ async function sendWithFreshProof(label, fetchFn, options, proofKey, build) {
|
|
|
33922
34859
|
lastError = err;
|
|
33923
34860
|
}
|
|
33924
34861
|
if (attempt < attempts - 1) {
|
|
33925
|
-
await
|
|
34862
|
+
await sleep3(delayMs);
|
|
33926
34863
|
delayMs *= 2;
|
|
33927
34864
|
}
|
|
33928
34865
|
}
|
|
@@ -33961,7 +34898,7 @@ function dataPath(scope) {
|
|
|
33961
34898
|
return `/v1/data/${encodeURIComponent(scope)}`;
|
|
33962
34899
|
}
|
|
33963
34900
|
async function openWriteSession(params) {
|
|
33964
|
-
const fetchFn =
|
|
34901
|
+
const fetchFn = resolveFetch3(params.fetch);
|
|
33965
34902
|
const personalServerUrl = normalizeBaseUrl2(params.personalServerUrl);
|
|
33966
34903
|
const audience = params.audience ?? personalServerUrl;
|
|
33967
34904
|
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
@@ -34041,12 +34978,12 @@ async function openWriteSession(params) {
|
|
|
34041
34978
|
};
|
|
34042
34979
|
}
|
|
34043
34980
|
function isWriteSession(value) {
|
|
34044
|
-
if (!
|
|
34981
|
+
if (!isRecord4(value)) return false;
|
|
34045
34982
|
const signer = value.signer;
|
|
34046
|
-
return typeof value.personalServerUrl === "string" && typeof value.audience === "string" && typeof value.grantId === "string" && typeof value.accessToken === "string" && value.accessToken.length > 0 && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt) && Array.isArray(value.writeScopes) && value.writeScopes.every((scope) => typeof scope === "string") &&
|
|
34983
|
+
return typeof value.personalServerUrl === "string" && typeof value.audience === "string" && typeof value.grantId === "string" && typeof value.accessToken === "string" && value.accessToken.length > 0 && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt) && Array.isArray(value.writeScopes) && value.writeScopes.every((scope) => typeof scope === "string") && isRecord4(signer) && typeof signer.signMessage === "function";
|
|
34047
34984
|
}
|
|
34048
34985
|
function sessionCoversScope(session, scope) {
|
|
34049
|
-
if (!
|
|
34986
|
+
if (!isRecord4(session) || !Array.isArray(session.writeScopes) || !session.writeScopes.every((pattern) => typeof pattern === "string")) {
|
|
34050
34987
|
throw new WriteRequestError("session must come from openWriteSession");
|
|
34051
34988
|
}
|
|
34052
34989
|
return session.writeScopes.some(
|
|
@@ -34091,7 +35028,7 @@ function binaryWriteSignedBytes(input) {
|
|
|
34091
35028
|
mimeType: normalizeBinaryMimeType(input.contentType),
|
|
34092
35029
|
...input.filename ? { filename: input.filename } : {},
|
|
34093
35030
|
sizeBytes: input.bytes.length,
|
|
34094
|
-
contentHash:
|
|
35031
|
+
contentHash: bytesToHex4(sha2567(input.bytes)),
|
|
34095
35032
|
encoding: "base64",
|
|
34096
35033
|
content: toBase64(input.bytes),
|
|
34097
35034
|
...metadata !== void 0 ? { metadata } : {}
|
|
@@ -34120,7 +35057,7 @@ function assertNoReservedKeys(value, where) {
|
|
|
34120
35057
|
}
|
|
34121
35058
|
}
|
|
34122
35059
|
function isLineagePair(value) {
|
|
34123
|
-
return
|
|
35060
|
+
return isRecord4(value) && typeof value.ownerAddress === "string" && typeof value.scope === "string";
|
|
34124
35061
|
}
|
|
34125
35062
|
function normalizeLineage(lineage, derivedScope) {
|
|
34126
35063
|
if (!Array.isArray(lineage)) {
|
|
@@ -34139,7 +35076,7 @@ function normalizeLineage(lineage, derivedScope) {
|
|
|
34139
35076
|
for (const entry of lineage) {
|
|
34140
35077
|
let id;
|
|
34141
35078
|
if (isLineagePair(entry)) {
|
|
34142
|
-
if (!
|
|
35079
|
+
if (!isAddress8(entry.ownerAddress, { strict: false })) {
|
|
34143
35080
|
throw new WriteRequestError(
|
|
34144
35081
|
"lineage source ownerAddress must be an EVM address",
|
|
34145
35082
|
{ ownerAddress: entry.ownerAddress }
|
|
@@ -34188,7 +35125,7 @@ function assertNoLineageField(value, where) {
|
|
|
34188
35125
|
}
|
|
34189
35126
|
function buildMetadataHeader(metadata, sources) {
|
|
34190
35127
|
if (metadata !== void 0) {
|
|
34191
|
-
if (!
|
|
35128
|
+
if (!isRecord4(metadata)) {
|
|
34192
35129
|
throw new WriteRequestError("metadata must be a plain object");
|
|
34193
35130
|
}
|
|
34194
35131
|
assertNoReservedKeys(metadata, "metadata");
|
|
@@ -34241,7 +35178,7 @@ function prepareWrite(params) {
|
|
|
34241
35178
|
if (params.data === void 0) {
|
|
34242
35179
|
throw new WriteRequestError("Pass data (a JSON object) or binary");
|
|
34243
35180
|
}
|
|
34244
|
-
if (!
|
|
35181
|
+
if (!isRecord4(params.data)) {
|
|
34245
35182
|
throw new WriteRequestError("data must be a plain JSON object");
|
|
34246
35183
|
}
|
|
34247
35184
|
if (params.metadata !== void 0) {
|
|
@@ -34292,7 +35229,7 @@ async function writeData(params) {
|
|
|
34292
35229
|
if (!isWriteSession(session)) {
|
|
34293
35230
|
throw new WriteRequestError("session must come from openWriteSession");
|
|
34294
35231
|
}
|
|
34295
|
-
const fetchFn =
|
|
35232
|
+
const fetchFn = resolveFetch3(params.fetch);
|
|
34296
35233
|
if (typeof params.scope !== "string" || params.scope.length === 0) {
|
|
34297
35234
|
throw new WriteRequestError("scope is required");
|
|
34298
35235
|
}
|
|
@@ -34404,6 +35341,13 @@ var QUESTION_STATUSES = [
|
|
|
34404
35341
|
"failed",
|
|
34405
35342
|
"stale"
|
|
34406
35343
|
];
|
|
35344
|
+
var DERIVATIVE_ERROR_CODES = [
|
|
35345
|
+
"inference_unavailable",
|
|
35346
|
+
"source_missing",
|
|
35347
|
+
"grant_invalid",
|
|
35348
|
+
"internal"
|
|
35349
|
+
];
|
|
35350
|
+
var DerivativeErrorCodeSchema = z5.enum(DERIVATIVE_ERROR_CODES);
|
|
34407
35351
|
var QuestionStatusSchema = z5.enum(QUESTION_STATUSES);
|
|
34408
35352
|
var QuestionRegisteredBySchema = z5.union([
|
|
34409
35353
|
z5.object({ kind: z5.literal("owner") }),
|
|
@@ -34425,6 +35369,14 @@ var DerivativeQuestionSchema = z5.object({
|
|
|
34425
35369
|
status: QuestionStatusSchema,
|
|
34426
35370
|
/** A short reason, set only while `status` is `failed`. */
|
|
34427
35371
|
error: nullableString,
|
|
35372
|
+
/**
|
|
35373
|
+
* The coarse failure class behind `error`, set only while `status` is
|
|
35374
|
+
* `failed`. `null` from a Personal Server that predates the class
|
|
35375
|
+
* (`personal-server-ts` before the status route).
|
|
35376
|
+
*/
|
|
35377
|
+
errorCode: DerivativeErrorCodeSchema.nullish().transform(
|
|
35378
|
+
(value) => value ?? null
|
|
35379
|
+
),
|
|
34428
35380
|
createdAt: z5.string(),
|
|
34429
35381
|
updatedAt: nullableString,
|
|
34430
35382
|
/** When the last compute finished, or `null` while `pending`. */
|
|
@@ -34469,7 +35421,7 @@ function resolveRequest(params) {
|
|
|
34469
35421
|
"signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
|
|
34470
35422
|
);
|
|
34471
35423
|
}
|
|
34472
|
-
const fetchFn =
|
|
35424
|
+
const fetchFn = resolveFetch3(params.fetch);
|
|
34473
35425
|
const baseUrl = normalizeBaseUrl2(params.personalServerUrl);
|
|
34474
35426
|
const audience = params.audience ?? baseUrl;
|
|
34475
35427
|
return {
|
|
@@ -34557,6 +35509,7 @@ async function questionErrorFromResponse(response, body) {
|
|
|
34557
35509
|
);
|
|
34558
35510
|
}
|
|
34559
35511
|
}
|
|
35512
|
+
var personalServerErrorFromQuestionResponse = questionErrorFromResponse;
|
|
34560
35513
|
async function sendOnce(params, resolved, session, spec, bodyBytes) {
|
|
34561
35514
|
return sendWithFreshProof(
|
|
34562
35515
|
spec.label,
|
|
@@ -34801,7 +35754,7 @@ async function waitForQuestion(params) {
|
|
|
34801
35754
|
}
|
|
34802
35755
|
);
|
|
34803
35756
|
}
|
|
34804
|
-
await
|
|
35757
|
+
await sleep3(Math.min(pollIntervalMs, remaining));
|
|
34805
35758
|
}
|
|
34806
35759
|
}
|
|
34807
35760
|
async function askPersonalServer(params) {
|
|
@@ -34836,6 +35789,166 @@ async function askPersonalServer(params) {
|
|
|
34836
35789
|
return { registration, record };
|
|
34837
35790
|
}
|
|
34838
35791
|
|
|
35792
|
+
// src/protocol/derivative-status.ts
|
|
35793
|
+
import { z as z6 } from "zod";
|
|
35794
|
+
var DERIVATIVE_STATUS_PATH = "/v1/derivatives/status";
|
|
35795
|
+
var DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS = 12e4;
|
|
35796
|
+
var DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS = 2e3;
|
|
35797
|
+
var nullable = (schema) => schema.nullish().transform((value) => value ?? null);
|
|
35798
|
+
var DerivativeStatusSchema = z6.object({
|
|
35799
|
+
derivedScope: z6.string().min(1),
|
|
35800
|
+
status: QuestionStatusSchema,
|
|
35801
|
+
/** When the last compute finished, or `null` if none ever has. */
|
|
35802
|
+
lastComputedAt: nullable(z6.string()),
|
|
35803
|
+
/** Local version of the derived record the last compute wrote. */
|
|
35804
|
+
derivedVersion: nullable(z6.number()),
|
|
35805
|
+
derivedCollectedAt: nullable(z6.string()),
|
|
35806
|
+
/** The failure class; `null` unless `status` is `failed`. */
|
|
35807
|
+
errorCode: nullable(DerivativeErrorCodeSchema),
|
|
35808
|
+
/**
|
|
35809
|
+
* Seconds until the Personal Server's next automatic retry, or `null` when
|
|
35810
|
+
* none is pending or running — the terminal signature. Poll on this cadence
|
|
35811
|
+
* rather than guessing one.
|
|
35812
|
+
*/
|
|
35813
|
+
retryAfterSeconds: nullable(z6.number())
|
|
35814
|
+
});
|
|
35815
|
+
function derivativeStatusTarget(derivedScope) {
|
|
35816
|
+
return `${DERIVATIVE_STATUS_PATH}?derivedScope=${encodeURIComponent(derivedScope)}`;
|
|
35817
|
+
}
|
|
35818
|
+
function normalizeBaseUrl3(url) {
|
|
35819
|
+
return url.replace(/\/+$/, "");
|
|
35820
|
+
}
|
|
35821
|
+
function resolveFetch4(fetchFn) {
|
|
35822
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
35823
|
+
if (resolved === void 0) {
|
|
35824
|
+
throw new WriteRequestError("No fetch implementation available");
|
|
35825
|
+
}
|
|
35826
|
+
return resolved;
|
|
35827
|
+
}
|
|
35828
|
+
function requireDerivedScope(derivedScope) {
|
|
35829
|
+
if (typeof derivedScope !== "string" || derivedScope.length === 0) {
|
|
35830
|
+
throw new WriteRequestError("derivedScope is required");
|
|
35831
|
+
}
|
|
35832
|
+
return derivedScope;
|
|
35833
|
+
}
|
|
35834
|
+
function sleep4(ms, signal) {
|
|
35835
|
+
if (ms <= 0) return Promise.resolve();
|
|
35836
|
+
return new Promise((resolve, reject) => {
|
|
35837
|
+
const timer = setTimeout(() => {
|
|
35838
|
+
signal?.removeEventListener("abort", onAbort);
|
|
35839
|
+
resolve();
|
|
35840
|
+
}, ms);
|
|
35841
|
+
const onAbort = () => {
|
|
35842
|
+
clearTimeout(timer);
|
|
35843
|
+
reject(abortError2(signal));
|
|
35844
|
+
};
|
|
35845
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
35846
|
+
});
|
|
35847
|
+
}
|
|
35848
|
+
function timeoutError(latest, timeoutMs) {
|
|
35849
|
+
return new DerivativeQuestionTimeoutError(
|
|
35850
|
+
`Derived scope ${latest.derivedScope} was still ${latest.status} after ${timeoutMs}ms`,
|
|
35851
|
+
{
|
|
35852
|
+
derivedScope: latest.derivedScope,
|
|
35853
|
+
status: latest.status,
|
|
35854
|
+
errorCode: latest.errorCode,
|
|
35855
|
+
retryAfterSeconds: latest.retryAfterSeconds,
|
|
35856
|
+
timeoutMs
|
|
35857
|
+
}
|
|
35858
|
+
);
|
|
35859
|
+
}
|
|
35860
|
+
function abortError2(signal) {
|
|
35861
|
+
const reason = signal?.reason;
|
|
35862
|
+
return reason instanceof Error ? reason : new WriteRequestError("Derivative status wait was aborted");
|
|
35863
|
+
}
|
|
35864
|
+
function isDerivativeStatusSettled(status) {
|
|
35865
|
+
if (status.status === "ready") return true;
|
|
35866
|
+
return status.status === "failed" && status.retryAfterSeconds === null;
|
|
35867
|
+
}
|
|
35868
|
+
async function getDerivativeStatus(params) {
|
|
35869
|
+
const derivedScope = requireDerivedScope(params.derivedScope);
|
|
35870
|
+
const fetchFn = resolveFetch4(params.fetch);
|
|
35871
|
+
const baseUrl = normalizeBaseUrl3(params.personalServerUrl);
|
|
35872
|
+
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
35873
|
+
const headers = new Headers(params.headers);
|
|
35874
|
+
headers.set(
|
|
35875
|
+
"Authorization",
|
|
35876
|
+
await buildWeb3SignedHeader({
|
|
35877
|
+
signMessage: signer.signMessage,
|
|
35878
|
+
aud: params.audience ?? baseUrl,
|
|
35879
|
+
method: "GET",
|
|
35880
|
+
uri: DERIVATIVE_STATUS_PATH,
|
|
35881
|
+
grantId: params.grantId
|
|
35882
|
+
})
|
|
35883
|
+
);
|
|
35884
|
+
let response;
|
|
35885
|
+
try {
|
|
35886
|
+
response = await fetchFn(
|
|
35887
|
+
`${baseUrl}${derivativeStatusTarget(derivedScope)}`,
|
|
35888
|
+
{
|
|
35889
|
+
method: "GET",
|
|
35890
|
+
headers,
|
|
35891
|
+
...params.signal ? { signal: params.signal } : {}
|
|
35892
|
+
}
|
|
35893
|
+
);
|
|
35894
|
+
} catch (err) {
|
|
35895
|
+
throw new WriteTransportError(
|
|
35896
|
+
`Derivative status read failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
35897
|
+
1,
|
|
35898
|
+
err
|
|
35899
|
+
);
|
|
35900
|
+
}
|
|
35901
|
+
if (!response.ok) {
|
|
35902
|
+
throw await personalServerErrorFromQuestionResponse(
|
|
35903
|
+
response
|
|
35904
|
+
);
|
|
35905
|
+
}
|
|
35906
|
+
let body;
|
|
35907
|
+
try {
|
|
35908
|
+
body = await response.json();
|
|
35909
|
+
} catch (err) {
|
|
35910
|
+
throw new DerivativeQuestionRejectedError(
|
|
35911
|
+
"Derivative status response is not JSON",
|
|
35912
|
+
response.status,
|
|
35913
|
+
null,
|
|
35914
|
+
{ cause: err instanceof Error ? err.message : String(err) }
|
|
35915
|
+
);
|
|
35916
|
+
}
|
|
35917
|
+
const parsed = DerivativeStatusSchema.safeParse(body);
|
|
35918
|
+
if (!parsed.success) {
|
|
35919
|
+
throw new DerivativeQuestionRejectedError(
|
|
35920
|
+
"Derivative status response is not a status view",
|
|
35921
|
+
response.status,
|
|
35922
|
+
null,
|
|
35923
|
+
{ issues: parsed.error.issues }
|
|
35924
|
+
);
|
|
35925
|
+
}
|
|
35926
|
+
return parsed.data;
|
|
35927
|
+
}
|
|
35928
|
+
async function waitForDerivativeStatus(params) {
|
|
35929
|
+
const timeoutMs = Math.max(
|
|
35930
|
+
0,
|
|
35931
|
+
params.timeoutMs ?? DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS
|
|
35932
|
+
);
|
|
35933
|
+
const pollIntervalMs = Math.max(
|
|
35934
|
+
0,
|
|
35935
|
+
params.pollIntervalMs ?? DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS
|
|
35936
|
+
);
|
|
35937
|
+
const deadline = Date.now() + timeoutMs;
|
|
35938
|
+
for (; ; ) {
|
|
35939
|
+
if (params.signal?.aborted) throw abortError2(params.signal);
|
|
35940
|
+
const latest = await getDerivativeStatus(params);
|
|
35941
|
+
if (isDerivativeStatusSettled(latest)) return latest;
|
|
35942
|
+
const remaining = deadline - Date.now();
|
|
35943
|
+
if (remaining <= 0) throw timeoutError(latest, timeoutMs);
|
|
35944
|
+
const waitMs = latest.retryAfterSeconds === null ? pollIntervalMs : latest.retryAfterSeconds * 1e3;
|
|
35945
|
+
if (waitMs > remaining) {
|
|
35946
|
+
throw timeoutError(latest, timeoutMs);
|
|
35947
|
+
}
|
|
35948
|
+
await sleep4(waitMs, params.signal);
|
|
35949
|
+
}
|
|
35950
|
+
}
|
|
35951
|
+
|
|
34839
35952
|
// src/protocol/gateway.ts
|
|
34840
35953
|
function withGrantPermissions(grant) {
|
|
34841
35954
|
const stripped = { ...grant };
|
|
@@ -35865,7 +36978,7 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
|
|
|
35865
36978
|
"server_not_configured",
|
|
35866
36979
|
"content_too_large"
|
|
35867
36980
|
]);
|
|
35868
|
-
function
|
|
36981
|
+
function isRecord5(value) {
|
|
35869
36982
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
35870
36983
|
}
|
|
35871
36984
|
function normalizeCode(value) {
|
|
@@ -35876,10 +36989,10 @@ function normalizeCode(value) {
|
|
|
35876
36989
|
return KNOWN_CODES.has(code) ? code : null;
|
|
35877
36990
|
}
|
|
35878
36991
|
function extractPSErrorBody(body) {
|
|
35879
|
-
if (!
|
|
36992
|
+
if (!isRecord5(body)) {
|
|
35880
36993
|
return null;
|
|
35881
36994
|
}
|
|
35882
|
-
const nested =
|
|
36995
|
+
const nested = isRecord5(body.error) ? body.error : null;
|
|
35883
36996
|
const code = normalizeCode(
|
|
35884
36997
|
nested?.errorCode ?? nested?.code ?? body.errorCode ?? body.code
|
|
35885
36998
|
);
|
|
@@ -35910,15 +37023,23 @@ export {
|
|
|
35910
37023
|
BUILDER_REGISTRATION_TYPES,
|
|
35911
37024
|
BlockchainError,
|
|
35912
37025
|
BrowserPlatformAdapter,
|
|
37026
|
+
BuilderUnknownError,
|
|
37027
|
+
CLAIM_POLL_FLOOR_MS,
|
|
35913
37028
|
CONTRACTS,
|
|
35914
37029
|
CallbackStorage,
|
|
35915
37030
|
ContractFactory,
|
|
35916
37031
|
ContractNotFoundError,
|
|
35917
37032
|
DATA_ACCESS_OP_TYPE,
|
|
35918
37033
|
DATA_REGISTRY_STATUS_ABI,
|
|
37034
|
+
DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS,
|
|
37035
|
+
DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS,
|
|
37036
|
+
DEFAULT_JOB_DEADLINE_SECONDS,
|
|
37037
|
+
DEFAULT_LEASE_SECONDS,
|
|
35919
37038
|
DEFAULT_QUESTION_POLL_INTERVAL_MS,
|
|
35920
37039
|
DEFAULT_QUESTION_TIMEOUT_MS,
|
|
37040
|
+
DERIVATIVE_ERROR_CODES,
|
|
35921
37041
|
DERIVATIVE_QUESTIONS_PATH,
|
|
37042
|
+
DERIVATIVE_STATUS_PATH,
|
|
35922
37043
|
DataFileEnvelopeSchema,
|
|
35923
37044
|
DataPointDeletedError,
|
|
35924
37045
|
DataPointNotFoundError,
|
|
@@ -35927,6 +37048,7 @@ export {
|
|
|
35927
37048
|
DerivativeComputeUnavailableError,
|
|
35928
37049
|
DerivativeCycleError,
|
|
35929
37050
|
DerivativeDerivedScopeRequiredError,
|
|
37051
|
+
DerivativeErrorCodeSchema,
|
|
35930
37052
|
DerivativeQuestionFailedError,
|
|
35931
37053
|
DerivativeQuestionInvalidError,
|
|
35932
37054
|
DerivativeQuestionNotFoundError,
|
|
@@ -35934,8 +37056,12 @@ export {
|
|
|
35934
37056
|
DerivativeQuestionSchema,
|
|
35935
37057
|
DerivativeQuestionTimeoutError,
|
|
35936
37058
|
DerivativeSourceNotGrantedError,
|
|
37059
|
+
DerivativeStatusSchema,
|
|
35937
37060
|
DropboxStorage,
|
|
35938
37061
|
ECIESError,
|
|
37062
|
+
ENCLAVE_IDENTITY_EVIDENCE_VERSION,
|
|
37063
|
+
ENCLAVE_TRUST_ANCHORS,
|
|
37064
|
+
ENCLAVE_WALLET_PURPOSE,
|
|
35939
37065
|
ESCROW_DEPOSIT_ABI2 as ESCROW_DEPOSIT_ABI,
|
|
35940
37066
|
ExpiredTokenError,
|
|
35941
37067
|
FEE_REGISTRY_ABI,
|
|
@@ -35944,12 +37070,24 @@ export {
|
|
|
35944
37070
|
GRANT_REGISTRATION_TYPES,
|
|
35945
37071
|
GRANT_REVOCATION_TYPES,
|
|
35946
37072
|
GoogleDriveStorage,
|
|
37073
|
+
GrantInvalidError,
|
|
35947
37074
|
InMemoryTokenStore,
|
|
35948
37075
|
IngestResponseSchema,
|
|
35949
37076
|
InvalidConfigurationError,
|
|
35950
37077
|
InvalidScopeEntryError,
|
|
35951
37078
|
InvalidSignatureError,
|
|
35952
37079
|
IpfsStorage,
|
|
37080
|
+
JOB_OPERATIONS,
|
|
37081
|
+
JOB_PROTOCOL_VERSION,
|
|
37082
|
+
JOB_STATES,
|
|
37083
|
+
JobEnvelopeError,
|
|
37084
|
+
JobIdTakenError,
|
|
37085
|
+
JobNotFoundError,
|
|
37086
|
+
JobRejectedError,
|
|
37087
|
+
JobRequestTooLargeError,
|
|
37088
|
+
JobTimeoutError,
|
|
37089
|
+
JobTransportError,
|
|
37090
|
+
JobsClientError,
|
|
35953
37091
|
LINEAGE_FIELD,
|
|
35954
37092
|
LINEAGE_KEY,
|
|
35955
37093
|
LineageEntrySchema,
|
|
@@ -35957,10 +37095,17 @@ export {
|
|
|
35957
37095
|
LineageNodeSchema,
|
|
35958
37096
|
LineageReadError,
|
|
35959
37097
|
MASTER_KEY_MESSAGE,
|
|
37098
|
+
MASTER_SIGNATURE_DELIVERY_MAX_AGE_SECONDS,
|
|
37099
|
+
MASTER_SIGNATURE_DELIVERY_VERSION,
|
|
37100
|
+
MAX_ATTEMPTS,
|
|
37101
|
+
MAX_INLINE_RESULT_BYTES,
|
|
37102
|
+
MAX_JOB_DEADLINE_SECONDS,
|
|
37103
|
+
MAX_LEASE_SECONDS,
|
|
35960
37104
|
MAX_LINEAGE_SOURCES,
|
|
35961
37105
|
MAX_QUESTION_CHARS,
|
|
35962
37106
|
MAX_QUESTION_MODEL_CHARS,
|
|
35963
37107
|
MAX_QUESTION_SOURCE_SCOPES,
|
|
37108
|
+
MAX_WAIT_SECONDS,
|
|
35964
37109
|
MissingAuthError,
|
|
35965
37110
|
NATIVE_ASSET_ADDRESS,
|
|
35966
37111
|
NATIVE_VANA_ASSET,
|
|
@@ -35969,6 +37114,7 @@ export {
|
|
|
35969
37114
|
NodePlatformAdapter,
|
|
35970
37115
|
NonceError,
|
|
35971
37116
|
OAuthClient,
|
|
37117
|
+
OwnerNotReadyError,
|
|
35972
37118
|
PERSONAL_SERVER_LITE_OWNER_BINDING_PREFIX,
|
|
35973
37119
|
PERSONAL_SERVER_LITE_OWNER_BINDING_PURPOSE,
|
|
35974
37120
|
PERSONAL_SERVER_LITE_OWNER_BINDING_VERSION,
|
|
@@ -35994,6 +37140,7 @@ export {
|
|
|
35994
37140
|
RedactedLineageNodeSchema,
|
|
35995
37141
|
RelayerError,
|
|
35996
37142
|
SCOPE_ACTIONS,
|
|
37143
|
+
SEALED_ENVELOPE_VERSION,
|
|
35997
37144
|
SERVER_REGISTRATION_TYPES,
|
|
35998
37145
|
ScopeSchema,
|
|
35999
37146
|
SerializationError,
|
|
@@ -36006,6 +37153,7 @@ export {
|
|
|
36006
37153
|
TOMBSTONE_METADATA_HASH,
|
|
36007
37154
|
TOMBSTONE_METADATA_HASH_PREIMAGE,
|
|
36008
37155
|
TransactionPendingError,
|
|
37156
|
+
USER_PS_ID_DOMAIN,
|
|
36009
37157
|
UserRejectedRequestError,
|
|
36010
37158
|
VanaError,
|
|
36011
37159
|
VanaStorage,
|
|
@@ -36024,6 +37172,7 @@ export {
|
|
|
36024
37172
|
WriteSessionExpiredError,
|
|
36025
37173
|
WriteTransportError,
|
|
36026
37174
|
WriteUnauthorizedError,
|
|
37175
|
+
appRootPreimage,
|
|
36027
37176
|
askPersonalServer,
|
|
36028
37177
|
assertDerivedScopeNaming,
|
|
36029
37178
|
assertValidPkceVerifier,
|
|
@@ -36037,6 +37186,7 @@ export {
|
|
|
36037
37186
|
buildEscrowPaymentHeader,
|
|
36038
37187
|
buildGrantPaymentHeader,
|
|
36039
37188
|
buildMarkDataPointUnavailableRequest,
|
|
37189
|
+
buildMasterSignatureDelivery,
|
|
36040
37190
|
buildPersonalServerDataReadRequest,
|
|
36041
37191
|
buildPersonalServerLiteOwnerBindingMessage,
|
|
36042
37192
|
buildPersonalServerLiteOwnerBindingSignature,
|
|
@@ -36045,6 +37195,7 @@ export {
|
|
|
36045
37195
|
buildSetDataPointStatusRequest,
|
|
36046
37196
|
buildWeb3SignedHeader,
|
|
36047
37197
|
builderRegistrationDomain,
|
|
37198
|
+
canonicalJobRequestBytes,
|
|
36048
37199
|
chains,
|
|
36049
37200
|
clearContractCache,
|
|
36050
37201
|
computeBodyHash,
|
|
@@ -36056,6 +37207,7 @@ export {
|
|
|
36056
37207
|
createDefaultNonceSource,
|
|
36057
37208
|
createEscrowGatewayClient,
|
|
36058
37209
|
createGatewayClient,
|
|
37210
|
+
createJobsClient,
|
|
36059
37211
|
createNodePlatformAdapter,
|
|
36060
37212
|
createPlatformAdapter,
|
|
36061
37213
|
createPlatformAdapterFor,
|
|
@@ -36069,6 +37221,7 @@ export {
|
|
|
36069
37221
|
decryptWithPassword,
|
|
36070
37222
|
deleteDataPoint,
|
|
36071
37223
|
deleteQuestion,
|
|
37224
|
+
derivativeStatusTarget,
|
|
36072
37225
|
deriveDataPointId,
|
|
36073
37226
|
deriveMasterKey,
|
|
36074
37227
|
deriveScopeKey,
|
|
@@ -36079,6 +37232,7 @@ export {
|
|
|
36079
37232
|
encodeDepositTokenData,
|
|
36080
37233
|
encodeSetDataPointStatusData,
|
|
36081
37234
|
encodeWriteMetadataHeader,
|
|
37235
|
+
encryptMasterSignatureDelivery,
|
|
36082
37236
|
encryptWithPassword,
|
|
36083
37237
|
escrowContractAddress,
|
|
36084
37238
|
escrowPaymentDomain,
|
|
@@ -36092,6 +37246,7 @@ export {
|
|
|
36092
37246
|
getContractAddress,
|
|
36093
37247
|
getContractController,
|
|
36094
37248
|
getContractInfo,
|
|
37249
|
+
getDerivativeStatus,
|
|
36095
37250
|
getFee,
|
|
36096
37251
|
getGatewayLineage,
|
|
36097
37252
|
getLineage,
|
|
@@ -36107,16 +37262,20 @@ export {
|
|
|
36107
37262
|
isDataPointId,
|
|
36108
37263
|
isDataPointTombstone,
|
|
36109
37264
|
isDataPortabilityGatewayConfig,
|
|
37265
|
+
isDerivativeStatusSettled,
|
|
36110
37266
|
isECIESEncrypted,
|
|
36111
37267
|
isPlatformSupported,
|
|
36112
37268
|
isRedactedLineageNode,
|
|
36113
37269
|
isTombstoneHashes,
|
|
37270
|
+
kmsIssuedPreimage,
|
|
36114
37271
|
listQuestions,
|
|
36115
37272
|
mainnetServices,
|
|
36116
37273
|
moksha,
|
|
36117
37274
|
mokshaServices,
|
|
36118
37275
|
mokshaTestnet2 as mokshaTestnet,
|
|
36119
37276
|
normalizeBinaryMimeType,
|
|
37277
|
+
openJobRequest,
|
|
37278
|
+
openJobResult,
|
|
36120
37279
|
openWriteSession,
|
|
36121
37280
|
parsePSError,
|
|
36122
37281
|
parsePersonalServerPaymentRequired,
|
|
@@ -36140,6 +37299,8 @@ export {
|
|
|
36140
37299
|
scopeMatchesPattern,
|
|
36141
37300
|
scopeNamespace,
|
|
36142
37301
|
scopeToPathSegments,
|
|
37302
|
+
sealJobRequest,
|
|
37303
|
+
sealJobResult,
|
|
36143
37304
|
serializeECIES,
|
|
36144
37305
|
serverRegistrationDomain,
|
|
36145
37306
|
sessionCoversScope,
|
|
@@ -36150,10 +37311,13 @@ export {
|
|
|
36150
37311
|
toDirectPaymentReceipt,
|
|
36151
37312
|
tombstoneDeletedAt,
|
|
36152
37313
|
tryGrantPermissions,
|
|
37314
|
+
userPsId,
|
|
36153
37315
|
vanaMainnet2 as vanaMainnet,
|
|
37316
|
+
verifyEnclaveIdentityEvidence,
|
|
36154
37317
|
verifyGrantRegistration,
|
|
36155
37318
|
verifyPkceChallenge,
|
|
36156
37319
|
verifyWeb3Signed,
|
|
37320
|
+
waitForDerivativeStatus,
|
|
36157
37321
|
waitForQuestion,
|
|
36158
37322
|
writeData,
|
|
36159
37323
|
writePersonalServerData
|