@opendatalabs/vana-sdk 3.18.1 → 3.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +141 -0
  2. package/dist/auth/web3-signed-builder.cjs +3 -0
  3. package/dist/auth/web3-signed-builder.cjs.map +1 -1
  4. package/dist/auth/web3-signed-builder.d.ts +14 -0
  5. package/dist/auth/web3-signed-builder.js +3 -0
  6. package/dist/auth/web3-signed-builder.js.map +1 -1
  7. package/dist/errors.cjs +69 -0
  8. package/dist/errors.cjs.map +1 -1
  9. package/dist/errors.d.ts +117 -2
  10. package/dist/errors.js +60 -0
  11. package/dist/errors.js.map +1 -1
  12. package/dist/index.browser.d.ts +1 -0
  13. package/dist/index.browser.js +577 -29
  14. package/dist/index.browser.js.map +4 -4
  15. package/dist/index.node.cjs +605 -29
  16. package/dist/index.node.cjs.map +4 -4
  17. package/dist/index.node.d.ts +1 -0
  18. package/dist/index.node.js +577 -29
  19. package/dist/index.node.js.map +4 -4
  20. package/dist/protocol/derivative-questions.cjs +518 -0
  21. package/dist/protocol/derivative-questions.cjs.map +1 -0
  22. package/dist/protocol/derivative-questions.d.ts +396 -0
  23. package/dist/protocol/derivative-questions.js +507 -0
  24. package/dist/protocol/derivative-questions.js.map +1 -0
  25. package/dist/protocol/derivative-questions.test.d.ts +1 -0
  26. package/dist/protocol/personal-server-write.cjs +12 -108
  27. package/dist/protocol/personal-server-write.cjs.map +1 -1
  28. package/dist/protocol/personal-server-write.d.ts +2 -17
  29. package/dist/protocol/personal-server-write.js +7 -98
  30. package/dist/protocol/personal-server-write.js.map +1 -1
  31. package/dist/protocol/write-request.cjs +156 -0
  32. package/dist/protocol/write-request.cjs.map +1 -0
  33. package/dist/protocol/write-request.d.ts +75 -0
  34. package/dist/protocol/write-request.js +124 -0
  35. package/dist/protocol/write-request.js.map +1 -0
  36. package/dist/tests/mock-personal-server.d.ts +54 -0
  37. package/package.json +1 -1
@@ -1358,6 +1358,57 @@ var LineageReadError = class extends VanaError {
1358
1358
  errorCode;
1359
1359
  details;
1360
1360
  };
1361
+ var DerivativeQuestionRejectedError = class extends PersonalServerWriteError {
1362
+ constructor(message, status, errorCode = null, details) {
1363
+ super(message, "DERIVATIVE_QUESTION_REJECTED", status, errorCode, details);
1364
+ }
1365
+ };
1366
+ var DerivativeQuestionInvalidError = class extends PersonalServerWriteError {
1367
+ constructor(message, status = 400, errorCode = null, details) {
1368
+ super(message, "DERIVATIVE_QUESTION_INVALID", status, errorCode, details);
1369
+ }
1370
+ };
1371
+ var DerivativeQuestionNotFoundError = class extends PersonalServerWriteError {
1372
+ constructor(message, errorCode = null, details) {
1373
+ super(message, "DERIVATIVE_QUESTION_NOT_FOUND", 404, errorCode, details);
1374
+ }
1375
+ };
1376
+ var DerivativeDerivedScopeRequiredError = class extends PersonalServerWriteError {
1377
+ constructor(message, errorCode = null, details) {
1378
+ super(
1379
+ message,
1380
+ "DERIVATIVE_DERIVED_SCOPE_REQUIRED",
1381
+ 400,
1382
+ errorCode,
1383
+ details
1384
+ );
1385
+ }
1386
+ };
1387
+ var DerivativeSourceNotGrantedError = class extends PersonalServerWriteError {
1388
+ constructor(message, errorCode = null, details) {
1389
+ super(message, "DERIVATIVE_SOURCE_NOT_GRANTED", 403, errorCode, details);
1390
+ }
1391
+ };
1392
+ var DerivativeCycleError = class extends PersonalServerWriteError {
1393
+ constructor(message, errorCode = null, details) {
1394
+ super(message, "DERIVATIVE_CYCLE", 409, errorCode, details);
1395
+ }
1396
+ };
1397
+ var DerivativeComputeUnavailableError = class extends PersonalServerWriteError {
1398
+ constructor(message, errorCode = null, details) {
1399
+ super(message, "DERIVATIVE_COMPUTE_UNAVAILABLE", 503, errorCode, details);
1400
+ }
1401
+ };
1402
+ var DerivativeQuestionTimeoutError = class extends PersonalServerWriteError {
1403
+ constructor(message, details) {
1404
+ super(message, "DERIVATIVE_QUESTION_TIMEOUT", void 0, null, details);
1405
+ }
1406
+ };
1407
+ var DerivativeQuestionFailedError = class extends PersonalServerWriteError {
1408
+ constructor(message, details) {
1409
+ super(message, "DERIVATIVE_QUESTION_FAILED", void 0, null, details);
1410
+ }
1411
+ };
1361
1412
  var DataPointDeletedError = class extends VanaError {
1362
1413
  constructor(message, details = {}) {
1363
1414
  super(message, "DATA_POINT_DELETED");
@@ -29115,6 +29166,9 @@ async function buildWeb3SignedHeader(params) {
29115
29166
  if (params.grantId !== void 0) {
29116
29167
  payload["grantId"] = params.grantId;
29117
29168
  }
29169
+ if (params.nonce !== void 0) {
29170
+ payload["nonce"] = params.nonce;
29171
+ }
29118
29172
  const sortedPayload = Object.keys(payload).sort().reduce((acc, key) => {
29119
29173
  acc[key] = payload[key];
29120
29174
  return acc;
@@ -34391,32 +34445,13 @@ function tryGrantPermissions(scopes) {
34391
34445
  }
34392
34446
 
34393
34447
  // src/protocol/personal-server-write.ts
34394
- import { sha256 as sha2565 } from "@noble/hashes/sha2";
34395
- import { bytesToHex as bytesToHex2, isAddress as isAddress6 } from "viem";
34448
+ import { sha256 as sha2566 } from "@noble/hashes/sha2";
34449
+ import { bytesToHex as bytesToHex3, isAddress as isAddress6 } from "viem";
34396
34450
  import { z as z4 } from "zod";
34397
- var WRITE_SESSION_PATH = "/v1/write/session";
34398
- var WRITE_SIGNATURE_HEADER = "X-Vana-Write-Signature";
34399
- var WRITE_METADATA_HEADER = "X-Vana-Metadata";
34400
- var LINEAGE_FIELD = "lineage";
34401
- var MAX_LINEAGE_SOURCES = 256;
34402
- var WRITE_FILENAME_HEADER = "X-Filename";
34403
- var WRITE_CONTENT_DISPOSITION_HEADER = "Content-Disposition";
34404
- var WRITER_ATTRIBUTION_KEY = "$writtenBy";
34405
- var LINEAGE_KEY = "$lineage";
34406
- var RESERVED_WRITE_KEYS = [
34407
- WRITER_ATTRIBUTION_KEY,
34408
- LINEAGE_KEY
34409
- ];
34410
- var WriteDataResultSchema = IngestResponseSchema.extend({
34411
- // Present when the write carried lineage: the validated, lowercased ids.
34412
- lineage: z4.object({ sources: z4.array(z4.string()) }).optional()
34413
- });
34414
- var WriteSessionResponseSchema = z4.object({
34415
- access_token: z4.string().min(1),
34416
- token_type: z4.string(),
34417
- expires_in: z4.number().nonnegative(),
34418
- scope: z4.string()
34419
- });
34451
+
34452
+ // src/protocol/write-request.ts
34453
+ import { sha256 as sha2565 } from "@noble/hashes/sha2";
34454
+ import { bytesToHex as bytesToHex2 } from "viem";
34420
34455
  function normalizeBaseUrl2(url) {
34421
34456
  return url.replace(/\/+$/, "");
34422
34457
  }
@@ -34427,9 +34462,6 @@ function resolveFetch2(fetchFn) {
34427
34462
  }
34428
34463
  return resolved;
34429
34464
  }
34430
- function dataPath(scope) {
34431
- return `/v1/data/${encodeURIComponent(scope)}`;
34432
- }
34433
34465
  function errorMessage(err) {
34434
34466
  return err instanceof Error ? err.message : String(err);
34435
34467
  }
@@ -34480,6 +34512,18 @@ function nextProofIat(proofKey) {
34480
34512
  if (waitSec <= 0) return Promise.resolve(iat);
34481
34513
  return sleep2(waitSec * 1e3).then(() => iat);
34482
34514
  }
34515
+ function freshProofNonce() {
34516
+ const webCrypto = globalThis.crypto;
34517
+ if (typeof webCrypto?.randomUUID === "function") {
34518
+ return webCrypto.randomUUID();
34519
+ }
34520
+ if (typeof webCrypto?.getRandomValues === "function") {
34521
+ return bytesToHex2(webCrypto.getRandomValues(new Uint8Array(16)));
34522
+ }
34523
+ throw new WriteRequestError(
34524
+ "No secure random source available to build a proof nonce; provide a crypto global"
34525
+ );
34526
+ }
34483
34527
  function proofKeyFor(parts) {
34484
34528
  return bytesToHex2(
34485
34529
  sha2565(
@@ -34517,6 +34561,34 @@ async function sendWithFreshProof(label, fetchFn, options, proofKey, build) {
34517
34561
  lastError
34518
34562
  );
34519
34563
  }
34564
+
34565
+ // src/protocol/personal-server-write.ts
34566
+ var WRITE_SESSION_PATH = "/v1/write/session";
34567
+ var WRITE_SIGNATURE_HEADER = "X-Vana-Write-Signature";
34568
+ var WRITE_METADATA_HEADER = "X-Vana-Metadata";
34569
+ var LINEAGE_FIELD = "lineage";
34570
+ var MAX_LINEAGE_SOURCES = 256;
34571
+ var WRITE_FILENAME_HEADER = "X-Filename";
34572
+ var WRITE_CONTENT_DISPOSITION_HEADER = "Content-Disposition";
34573
+ var WRITER_ATTRIBUTION_KEY = "$writtenBy";
34574
+ var LINEAGE_KEY = "$lineage";
34575
+ var RESERVED_WRITE_KEYS = [
34576
+ WRITER_ATTRIBUTION_KEY,
34577
+ LINEAGE_KEY
34578
+ ];
34579
+ var WriteDataResultSchema = IngestResponseSchema.extend({
34580
+ // Present when the write carried lineage: the validated, lowercased ids.
34581
+ lineage: z4.object({ sources: z4.array(z4.string()) }).optional()
34582
+ });
34583
+ var WriteSessionResponseSchema = z4.object({
34584
+ access_token: z4.string().min(1),
34585
+ token_type: z4.string(),
34586
+ expires_in: z4.number().nonnegative(),
34587
+ scope: z4.string()
34588
+ });
34589
+ function dataPath(scope) {
34590
+ return `/v1/data/${encodeURIComponent(scope)}`;
34591
+ }
34520
34592
  async function openWriteSession(params) {
34521
34593
  const fetchFn = resolveFetch2(params.fetch);
34522
34594
  const personalServerUrl = normalizeBaseUrl2(params.personalServerUrl);
@@ -34648,7 +34720,7 @@ function binaryWriteSignedBytes(input) {
34648
34720
  mimeType: normalizeBinaryMimeType(input.contentType),
34649
34721
  ...input.filename ? { filename: input.filename } : {},
34650
34722
  sizeBytes: input.bytes.length,
34651
- contentHash: bytesToHex2(sha2565(input.bytes)),
34723
+ contentHash: bytesToHex3(sha2566(input.bytes)),
34652
34724
  encoding: "base64",
34653
34725
  content: toBase64(input.bytes),
34654
34726
  ...metadata !== void 0 ? { metadata } : {}
@@ -34945,6 +35017,454 @@ async function writePersonalServerData(params) {
34945
35017
  return { ...result, session };
34946
35018
  }
34947
35019
 
35020
+ // src/protocol/derivative-questions.ts
35021
+ import { z as z5 } from "zod";
35022
+ var DERIVATIVE_QUESTIONS_PATH = "/v1/derivatives/questions";
35023
+ var MAX_QUESTION_SOURCE_SCOPES = 16;
35024
+ var MAX_QUESTION_CHARS = 8e3;
35025
+ var MAX_QUESTION_MODEL_CHARS = 128;
35026
+ var MODEL_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
35027
+ var DEFAULT_QUESTION_TIMEOUT_MS = 12e4;
35028
+ var DEFAULT_QUESTION_POLL_INTERVAL_MS = 2e3;
35029
+ var SESSION_REFRESH_SKEW_MS = 3e4;
35030
+ var QUESTION_STATUSES = [
35031
+ "pending",
35032
+ "ready",
35033
+ "failed",
35034
+ "stale"
35035
+ ];
35036
+ var QuestionStatusSchema = z5.enum(QUESTION_STATUSES);
35037
+ var QuestionRegisteredBySchema = z5.union([
35038
+ z5.object({ kind: z5.literal("owner") }),
35039
+ z5.object({
35040
+ kind: z5.literal("builder"),
35041
+ builder: z5.string(),
35042
+ grantId: z5.string()
35043
+ })
35044
+ ]);
35045
+ var nullableString = z5.string().nullish().transform((value) => value ?? null);
35046
+ var DerivativeQuestionSchema = z5.object({
35047
+ questionId: z5.string().min(1),
35048
+ derivedScope: z5.string().min(1),
35049
+ sourceScopes: z5.array(z5.string()),
35050
+ question: z5.string(),
35051
+ /** The model override, or `null` for the server's default. */
35052
+ model: nullableString,
35053
+ registeredBy: QuestionRegisteredBySchema,
35054
+ status: QuestionStatusSchema,
35055
+ /** A short reason, set only while `status` is `failed`. */
35056
+ error: nullableString,
35057
+ createdAt: z5.string(),
35058
+ updatedAt: nullableString,
35059
+ /** When the last compute finished, or `null` while `pending`. */
35060
+ lastComputedAt: nullableString,
35061
+ /** Local version of the derived record the last compute wrote. */
35062
+ derivedVersion: z5.number().nullish().transform((value) => value ?? null),
35063
+ derivedCollectedAt: nullableString
35064
+ });
35065
+ var QuestionListSchema = z5.object({
35066
+ questions: z5.array(DerivativeQuestionSchema)
35067
+ });
35068
+ var QuestionRecomputeResultSchema = DerivativeQuestionSchema;
35069
+ var QuestionDeleteResultSchema = z5.object({
35070
+ questionId: z5.string().min(1),
35071
+ deleted: z5.literal(true)
35072
+ });
35073
+ var sessionsBySigner = /* @__PURE__ */ new WeakMap();
35074
+ function sessionCacheKey(personalServerUrl, audience, grantId, fetchFn) {
35075
+ return JSON.stringify([personalServerUrl, audience, grantId]) + fetchIdOf(fetchFn);
35076
+ }
35077
+ var fetchIds = /* @__PURE__ */ new WeakMap();
35078
+ var nextFetchId = 0;
35079
+ function fetchIdOf(fetchFn) {
35080
+ let id = fetchIds.get(fetchFn);
35081
+ if (id === void 0) {
35082
+ id = ++nextFetchId;
35083
+ fetchIds.set(fetchFn, id);
35084
+ }
35085
+ return `#${id}`;
35086
+ }
35087
+ function resolveRequest(params) {
35088
+ if (typeof params.personalServerUrl !== "string" || params.personalServerUrl.length === 0) {
35089
+ throw new WriteRequestError("personalServerUrl is required");
35090
+ }
35091
+ if (typeof params.grantId !== "string" || params.grantId.length === 0) {
35092
+ throw new WriteRequestError(
35093
+ "grantId is required; a question call runs under the grant carrying write:<derivedScope>"
35094
+ );
35095
+ }
35096
+ if (params.signer === null || typeof params.signer !== "object") {
35097
+ throw new WriteRequestError(
35098
+ "signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
35099
+ );
35100
+ }
35101
+ const fetchFn = resolveFetch2(params.fetch);
35102
+ const baseUrl = normalizeBaseUrl2(params.personalServerUrl);
35103
+ const audience = params.audience ?? baseUrl;
35104
+ return {
35105
+ baseUrl,
35106
+ audience,
35107
+ fetchFn,
35108
+ cacheKey: sessionCacheKey(baseUrl, audience, params.grantId, fetchFn),
35109
+ signerKey: params.signer
35110
+ };
35111
+ }
35112
+ async function resolveSession(params, resolved, force) {
35113
+ let cache = sessionsBySigner.get(resolved.signerKey);
35114
+ if (cache === void 0) {
35115
+ cache = /* @__PURE__ */ new Map();
35116
+ sessionsBySigner.set(resolved.signerKey, cache);
35117
+ }
35118
+ const cached = cache.get(resolved.cacheKey);
35119
+ if (!force && cached !== void 0 && cached.expiresAt > Date.now() + SESSION_REFRESH_SKEW_MS) {
35120
+ return cached;
35121
+ }
35122
+ if (force) cache.delete(resolved.cacheKey);
35123
+ const session = await openWriteSession({
35124
+ personalServerUrl: resolved.baseUrl,
35125
+ signer: params.signer,
35126
+ grantId: params.grantId,
35127
+ account: params.account,
35128
+ audience: resolved.audience,
35129
+ fetch: resolved.fetchFn,
35130
+ headers: params.headers,
35131
+ retry: params.retry
35132
+ });
35133
+ cache.set(resolved.cacheKey, session);
35134
+ return session;
35135
+ }
35136
+ var PROOF_FAILURE_CODES = /* @__PURE__ */ new Set([
35137
+ "WRITE_ATTRIBUTION_REQUIRED",
35138
+ "WRITE_ATTRIBUTION_INVALID",
35139
+ "WRITE_ATTRIBUTION_SIGNER_MISMATCH",
35140
+ "WRITE_ATTRIBUTION_GRANT_MISMATCH",
35141
+ "WRITE_ATTRIBUTION_REPLAY"
35142
+ ]);
35143
+ function isStaleSession(errorCode) {
35144
+ return errorCode === null || !PROOF_FAILURE_CODES.has(errorCode);
35145
+ }
35146
+ async function questionErrorFromResponse(response, body) {
35147
+ const { errorCode, message, details } = body ?? await readPersonalServerErrorBody(response);
35148
+ const text = message ?? `Derivative question request failed: ${response.status} ${response.statusText}`;
35149
+ switch (errorCode) {
35150
+ case "DERIVATIVE_SOURCE_NOT_GRANTED":
35151
+ return new DerivativeSourceNotGrantedError(text, errorCode, details);
35152
+ case "DERIVATIVE_CYCLE":
35153
+ return new DerivativeCycleError(text, errorCode, details);
35154
+ case "DERIVATIVE_COMPUTE_UNAVAILABLE":
35155
+ return new DerivativeComputeUnavailableError(text, errorCode, details);
35156
+ case "DERIVATIVE_QUESTION_INVALID":
35157
+ case "LINEAGE_SCOPE_UNDER_SOURCE_PREFIX":
35158
+ return new DerivativeQuestionInvalidError(
35159
+ text,
35160
+ response.status,
35161
+ errorCode,
35162
+ details
35163
+ );
35164
+ case "DERIVATIVE_QUESTION_NOT_FOUND":
35165
+ return new DerivativeQuestionNotFoundError(text, errorCode, details);
35166
+ case "DERIVATIVE_DERIVED_SCOPE_REQUIRED":
35167
+ return new DerivativeDerivedScopeRequiredError(text, errorCode, details);
35168
+ default:
35169
+ break;
35170
+ }
35171
+ switch (response.status) {
35172
+ case 401:
35173
+ return new WriteUnauthorizedError(text, errorCode, details);
35174
+ case 403:
35175
+ return new WriteForbiddenError(text, errorCode, details);
35176
+ case 404:
35177
+ return new DerivativeQuestionNotFoundError(text, errorCode, details);
35178
+ case 409:
35179
+ return new WriteConflictError(text, errorCode, details);
35180
+ default:
35181
+ return new DerivativeQuestionRejectedError(
35182
+ text,
35183
+ response.status,
35184
+ errorCode,
35185
+ details
35186
+ );
35187
+ }
35188
+ }
35189
+ async function sendOnce(params, resolved, session, spec, bodyBytes) {
35190
+ return sendWithFreshProof(
35191
+ spec.label,
35192
+ resolved.fetchFn,
35193
+ params.retry,
35194
+ proofKeyFor({
35195
+ aud: session.audience,
35196
+ method: spec.method,
35197
+ uri: spec.target,
35198
+ grantId: session.grantId,
35199
+ signedBytes: bodyBytes
35200
+ }),
35201
+ async (iat) => {
35202
+ const headers = new Headers(params.headers);
35203
+ headers.set("Accept", "application/json");
35204
+ headers.set("Authorization", `Bearer ${session.accessToken}`);
35205
+ if (bodyBytes !== void 0) {
35206
+ headers.set("Content-Type", "application/json");
35207
+ }
35208
+ headers.set(
35209
+ WRITE_SIGNATURE_HEADER,
35210
+ await buildWeb3SignedHeader({
35211
+ signMessage: session.signer.signMessage,
35212
+ aud: session.audience,
35213
+ // The proof commits to the whole request target, query included:
35214
+ // `?derivedScope=` is what the list route authorizes against, and a
35215
+ // proof that did not cover it would authorize any other scope.
35216
+ uri: spec.target,
35217
+ method: spec.method,
35218
+ body: bodyBytes,
35219
+ grantId: session.grantId,
35220
+ // Fresh per attempt, so a retry after a thrown `fetch` is never the
35221
+ // proof the server may already have consumed, and so two identical
35222
+ // polls inside one second stay distinct.
35223
+ nonce: freshProofNonce(),
35224
+ iat
35225
+ })
35226
+ );
35227
+ return {
35228
+ url: `${resolved.baseUrl}${spec.target}`,
35229
+ init: {
35230
+ method: spec.method,
35231
+ headers,
35232
+ ...bodyBytes === void 0 ? {} : { body: bodyBytes },
35233
+ ...params.signal ? { signal: params.signal } : {}
35234
+ }
35235
+ };
35236
+ }
35237
+ );
35238
+ }
35239
+ async function sendQuestionRequest(params, spec, schema) {
35240
+ const resolved = resolveRequest(params);
35241
+ const bodyBytes = spec.body === void 0 ? void 0 : new TextEncoder().encode(JSON.stringify(spec.body));
35242
+ let session = await resolveSession(params, resolved, false);
35243
+ let response = await sendOnce(params, resolved, session, spec, bodyBytes);
35244
+ let errorBody;
35245
+ if (response.status === 401) {
35246
+ errorBody = await readPersonalServerErrorBody(response);
35247
+ if (isStaleSession(errorBody.errorCode)) {
35248
+ session = await resolveSession(params, resolved, true);
35249
+ response = await sendOnce(params, resolved, session, spec, bodyBytes);
35250
+ errorBody = void 0;
35251
+ }
35252
+ }
35253
+ if (!response.ok) {
35254
+ throw await questionErrorFromResponse(response, errorBody);
35255
+ }
35256
+ let body;
35257
+ try {
35258
+ body = await response.json();
35259
+ } catch (err) {
35260
+ throw new DerivativeQuestionRejectedError(
35261
+ `${spec.label} response is not JSON`,
35262
+ response.status,
35263
+ null,
35264
+ { cause: errorMessage(err) }
35265
+ );
35266
+ }
35267
+ const parsed = schema.safeParse(body);
35268
+ if (!parsed.success) {
35269
+ throw new DerivativeQuestionRejectedError(
35270
+ `${spec.label} response is not a derivative question answer`,
35271
+ response.status,
35272
+ null,
35273
+ { issues: parsed.error.issues }
35274
+ );
35275
+ }
35276
+ return parsed.data;
35277
+ }
35278
+ function assertQuestionId(questionId) {
35279
+ if (typeof questionId !== "string" || questionId.length === 0) {
35280
+ throw new WriteRequestError("questionId is required");
35281
+ }
35282
+ return `${DERIVATIVE_QUESTIONS_PATH}/${encodeURIComponent(questionId)}`;
35283
+ }
35284
+ function registrationBody(params) {
35285
+ const { derivedScope, question } = params;
35286
+ if (typeof derivedScope !== "string" || derivedScope.length === 0) {
35287
+ throw new WriteRequestError("derivedScope is required");
35288
+ }
35289
+ if (!Array.isArray(params.sourceScopes) || params.sourceScopes.length === 0) {
35290
+ throw new WriteRequestError(
35291
+ "sourceScopes must be a non-empty array of scopes"
35292
+ );
35293
+ }
35294
+ if (params.sourceScopes.length > MAX_QUESTION_SOURCE_SCOPES) {
35295
+ throw new WriteRequestError(
35296
+ `sourceScopes lists ${params.sourceScopes.length} scopes; the maximum is ${MAX_QUESTION_SOURCE_SCOPES}`,
35297
+ { max: MAX_QUESTION_SOURCE_SCOPES, count: params.sourceScopes.length }
35298
+ );
35299
+ }
35300
+ const sourceScopes = [];
35301
+ for (const scope of params.sourceScopes) {
35302
+ if (typeof scope !== "string" || scope.length === 0) {
35303
+ throw new WriteRequestError("sourceScopes entries must be scope strings");
35304
+ }
35305
+ if (sourceScopes.includes(scope)) {
35306
+ throw new WriteRequestError("sourceScopes must not repeat a scope", {
35307
+ duplicate: scope
35308
+ });
35309
+ }
35310
+ if (scope === derivedScope) {
35311
+ throw new WriteRequestError(
35312
+ "derivedScope cannot be one of its own sources",
35313
+ { scope }
35314
+ );
35315
+ }
35316
+ sourceScopes.push(scope);
35317
+ }
35318
+ if (typeof question !== "string" || question.trim() === "") {
35319
+ throw new WriteRequestError("question must be a non-empty string");
35320
+ }
35321
+ if (question.length > MAX_QUESTION_CHARS) {
35322
+ throw new WriteRequestError(
35323
+ `question is ${question.length} characters; the maximum is ${MAX_QUESTION_CHARS}`,
35324
+ { max: MAX_QUESTION_CHARS, length: question.length }
35325
+ );
35326
+ }
35327
+ if (params.model !== void 0) {
35328
+ if (typeof params.model !== "string" || params.model.length > MAX_QUESTION_MODEL_CHARS || !MODEL_ID_PATTERN.test(params.model)) {
35329
+ throw new WriteRequestError("model must be a provider model id", {
35330
+ model: params.model
35331
+ });
35332
+ }
35333
+ }
35334
+ assertDerivedScopeNaming(derivedScope, sourceScopes);
35335
+ return {
35336
+ derivedScope,
35337
+ sourceScopes,
35338
+ question,
35339
+ ...params.model === void 0 ? {} : { model: params.model }
35340
+ };
35341
+ }
35342
+ async function registerQuestion(params) {
35343
+ const body = registrationBody(params);
35344
+ return sendQuestionRequest(
35345
+ params,
35346
+ {
35347
+ method: "POST",
35348
+ target: DERIVATIVE_QUESTIONS_PATH,
35349
+ body,
35350
+ label: "Register derivative question"
35351
+ },
35352
+ DerivativeQuestionSchema
35353
+ );
35354
+ }
35355
+ async function getQuestion(params) {
35356
+ const target = assertQuestionId(params.questionId);
35357
+ return sendQuestionRequest(
35358
+ params,
35359
+ { method: "GET", target, label: "Read derivative question" },
35360
+ DerivativeQuestionSchema
35361
+ );
35362
+ }
35363
+ async function listQuestions(params) {
35364
+ if (typeof params.derivedScope !== "string" || params.derivedScope.length === 0) {
35365
+ throw new WriteRequestError(
35366
+ "derivedScope is required; a builder may only list its own questions on a scope it may write"
35367
+ );
35368
+ }
35369
+ const target = `${DERIVATIVE_QUESTIONS_PATH}?derivedScope=${encodeURIComponent(params.derivedScope)}`;
35370
+ const { questions } = await sendQuestionRequest(
35371
+ params,
35372
+ {
35373
+ method: "GET",
35374
+ target,
35375
+ label: "List derivative questions"
35376
+ },
35377
+ QuestionListSchema
35378
+ );
35379
+ return questions;
35380
+ }
35381
+ async function recomputeQuestion(params) {
35382
+ const target = `${assertQuestionId(params.questionId)}/recompute`;
35383
+ return sendQuestionRequest(
35384
+ params,
35385
+ { method: "POST", target, label: "Recompute derivative question" },
35386
+ QuestionRecomputeResultSchema
35387
+ );
35388
+ }
35389
+ async function deleteQuestion(params) {
35390
+ const target = assertQuestionId(params.questionId);
35391
+ return sendQuestionRequest(
35392
+ params,
35393
+ { method: "DELETE", target, label: "Delete derivative question" },
35394
+ QuestionDeleteResultSchema
35395
+ );
35396
+ }
35397
+ function isSettled(status) {
35398
+ return status === "ready" || status === "failed";
35399
+ }
35400
+ function abortError(signal) {
35401
+ const reason = signal.reason;
35402
+ if (reason instanceof Error) return reason;
35403
+ const error = new Error("The operation was aborted");
35404
+ error.name = "AbortError";
35405
+ return error;
35406
+ }
35407
+ async function waitForQuestion(params) {
35408
+ const timeoutMs = Math.max(
35409
+ 0,
35410
+ params.timeoutMs ?? DEFAULT_QUESTION_TIMEOUT_MS
35411
+ );
35412
+ const pollIntervalMs = Math.max(
35413
+ 0,
35414
+ params.pollIntervalMs ?? DEFAULT_QUESTION_POLL_INTERVAL_MS
35415
+ );
35416
+ const deadline = Date.now() + timeoutMs;
35417
+ for (; ; ) {
35418
+ if (params.signal?.aborted) throw abortError(params.signal);
35419
+ const latest = await getQuestion(params);
35420
+ if (isSettled(latest.status)) return latest;
35421
+ const remaining = deadline - Date.now();
35422
+ if (remaining <= 0) {
35423
+ throw new DerivativeQuestionTimeoutError(
35424
+ `Derivative question ${latest.questionId} was still ${latest.status} after ${timeoutMs}ms`,
35425
+ {
35426
+ questionId: latest.questionId,
35427
+ derivedScope: latest.derivedScope,
35428
+ status: latest.status,
35429
+ timeoutMs
35430
+ }
35431
+ );
35432
+ }
35433
+ await sleep2(Math.min(pollIntervalMs, remaining));
35434
+ }
35435
+ }
35436
+ async function askPersonalServer(params) {
35437
+ const registered = await registerQuestion(params);
35438
+ const registration = await waitForQuestion({
35439
+ ...params,
35440
+ questionId: registered.questionId
35441
+ });
35442
+ if (registration.status !== "ready") {
35443
+ throw new DerivativeQuestionFailedError(
35444
+ `Derivative question ${registration.questionId} failed: ${registration.error ?? "no reason given"}`,
35445
+ {
35446
+ questionId: registration.questionId,
35447
+ derivedScope: registration.derivedScope,
35448
+ error: registration.error
35449
+ }
35450
+ );
35451
+ }
35452
+ const signer = resolveWriteSigner(params.signer, {
35453
+ account: params.account
35454
+ });
35455
+ const readParams = {
35456
+ personalServerUrl: normalizeBaseUrl2(params.personalServerUrl),
35457
+ scope: params.derivedScope,
35458
+ grantId: params.grantId,
35459
+ signMessage: signer.signMessage,
35460
+ ...params.audience === void 0 ? {} : { audience: params.audience },
35461
+ ...params.headers === void 0 ? {} : { headers: params.headers },
35462
+ ...params.fetch === void 0 ? {} : { fetch: params.fetch }
35463
+ };
35464
+ const record = await readPersonalServerData(readParams);
35465
+ return { registration, record };
35466
+ }
35467
+
34948
35468
  // src/protocol/gateway.ts
34949
35469
  function withGrantPermissions(grant) {
34950
35470
  const stripped = { ...grant };
@@ -36025,11 +36545,24 @@ export {
36025
36545
  ContractNotFoundError,
36026
36546
  DATA_ACCESS_OP_TYPE,
36027
36547
  DATA_REGISTRY_STATUS_ABI,
36548
+ DEFAULT_QUESTION_POLL_INTERVAL_MS,
36549
+ DEFAULT_QUESTION_TIMEOUT_MS,
36550
+ DERIVATIVE_QUESTIONS_PATH,
36028
36551
  DataFileEnvelopeSchema,
36029
36552
  DataPointDeletedError,
36030
36553
  DataPointNotFoundError,
36031
36554
  DataPointStatus,
36032
36555
  DataPointVersionConflictError,
36556
+ DerivativeComputeUnavailableError,
36557
+ DerivativeCycleError,
36558
+ DerivativeDerivedScopeRequiredError,
36559
+ DerivativeQuestionFailedError,
36560
+ DerivativeQuestionInvalidError,
36561
+ DerivativeQuestionNotFoundError,
36562
+ DerivativeQuestionRejectedError,
36563
+ DerivativeQuestionSchema,
36564
+ DerivativeQuestionTimeoutError,
36565
+ DerivativeSourceNotGrantedError,
36033
36566
  DropboxStorage,
36034
36567
  ECIESError,
36035
36568
  ESCROW_DEPOSIT_ABI2 as ESCROW_DEPOSIT_ABI,
@@ -36054,6 +36587,9 @@ export {
36054
36587
  LineageReadError,
36055
36588
  MASTER_KEY_MESSAGE,
36056
36589
  MAX_LINEAGE_SOURCES,
36590
+ MAX_QUESTION_CHARS,
36591
+ MAX_QUESTION_MODEL_CHARS,
36592
+ MAX_QUESTION_SOURCE_SCOPES,
36057
36593
  MissingAuthError,
36058
36594
  NATIVE_ASSET_ADDRESS,
36059
36595
  NATIVE_VANA_ASSET,
@@ -36074,6 +36610,11 @@ export {
36074
36610
  PersonalServerError,
36075
36611
  PersonalServerWriteError,
36076
36612
  PinataStorage,
36613
+ QUESTION_STATUSES,
36614
+ QuestionDeleteResultSchema,
36615
+ QuestionRecomputeResultSchema,
36616
+ QuestionRegisteredBySchema,
36617
+ QuestionStatusSchema,
36077
36618
  R2Storage,
36078
36619
  RECORD_DATA_ACCESS_TYPES,
36079
36620
  REGISTRATION_KIND_FOR_OP,
@@ -36112,6 +36653,7 @@ export {
36112
36653
  WriteSessionExpiredError,
36113
36654
  WriteTransportError,
36114
36655
  WriteUnauthorizedError,
36656
+ askPersonalServer,
36115
36657
  assertDerivedScopeNaming,
36116
36658
  assertValidPkceVerifier,
36117
36659
  authorizeEscrowPayment,
@@ -36155,6 +36697,7 @@ export {
36155
36697
  dataRegistryDomain,
36156
36698
  decryptWithPassword,
36157
36699
  deleteDataPoint,
36700
+ deleteQuestion,
36158
36701
  deriveDataPointId,
36159
36702
  deriveMasterKey,
36160
36703
  deriveScopeKey,
@@ -36184,6 +36727,7 @@ export {
36184
36727
  getOpFee,
36185
36728
  getPersonalServerLineage,
36186
36729
  getPlatformCapabilities,
36730
+ getQuestion,
36187
36731
  getServiceEndpoints,
36188
36732
  grantPermissions,
36189
36733
  grantRegistrationDomain,
@@ -36196,6 +36740,7 @@ export {
36196
36740
  isPlatformSupported,
36197
36741
  isRedactedLineageNode,
36198
36742
  isTombstoneHashes,
36743
+ listQuestions,
36199
36744
  mainnetServices,
36200
36745
  moksha,
36201
36746
  mokshaServices,
@@ -36215,8 +36760,10 @@ export {
36215
36760
  personalServerLineagePath,
36216
36761
  personalServerRegistrationDomain,
36217
36762
  readPersonalServerData,
36763
+ recomputeQuestion,
36218
36764
  recoverServerOwner,
36219
36765
  registerPersonalServerSignature,
36766
+ registerQuestion,
36220
36767
  resolveWriteSigner,
36221
36768
  scopeCoveredByGrant,
36222
36769
  scopeMatchesPattern,
@@ -36236,6 +36783,7 @@ export {
36236
36783
  verifyGrantRegistration,
36237
36784
  verifyPkceChallenge,
36238
36785
  verifyWeb3Signed,
36786
+ waitForQuestion,
36239
36787
  writeData,
36240
36788
  writePersonalServerData
36241
36789
  };