@opendatalabs/vana-sdk 3.21.0 → 3.22.0

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 CHANGED
@@ -621,6 +621,70 @@ These helpers require `personal-server-ts` main `d91124d` or later, which is
621
621
  where the query-in-the-signed-uri rule, the `nonce` claim, the 404 for an
622
622
  unknown id and the full-view `recompute` answer landed.
623
623
 
624
+ ### Watching a derived scope as the reader
625
+
626
+ The helpers above are the builder's: every one of them needs a write session,
627
+ which an app holding only a bare read entry on the derived scope cannot open.
628
+ That reader sees `GET /v1/data/<derivedScope>` answer 404 whether the compute
629
+ is running, retrying, or finished failing.
630
+
631
+ `getDerivativeStatus` is the reader's view of the same question. It
632
+ authenticates like a data read — a live grant covering the derived scope, or
633
+ the owner — and nothing is charged, so a priced grant raises no 402 here.
634
+
635
+ ```typescript
636
+ import {
637
+ getDerivativeStatus,
638
+ waitForDerivativeStatus,
639
+ } from "@opendatalabs/vana-sdk";
640
+
641
+ const status = await getDerivativeStatus({
642
+ personalServerUrl: "https://ps.example.com",
643
+ derivedScope: "coach.weekly",
644
+ grantId,
645
+ signer,
646
+ });
647
+ // { derivedScope, status, lastComputedAt, derivedVersion,
648
+ // derivedCollectedAt, errorCode, retryAfterSeconds }
649
+
650
+ const settled = await waitForDerivativeStatus({
651
+ personalServerUrl: "https://ps.example.com",
652
+ derivedScope: "coach.weekly",
653
+ grantId,
654
+ signer,
655
+ timeoutMs: 60_000,
656
+ });
657
+ ```
658
+
659
+ The view is lifecycle only: the question text, the source scopes, the question
660
+ id, the registrar and the server's raw `error` string stay owner-only.
661
+ `errorCode` is a closed vocabulary — `inference_unavailable`,
662
+ `source_missing`, `grant_invalid`, `internal` — and is `null` unless `status`
663
+ is `failed`.
664
+
665
+ `retryAfterSeconds` is what separates a failure that is still being worked on
666
+ from one that is over: `inference_unavailable` is the one transient class, and
667
+ the Personal Server retries it on its own schedule. `waitForDerivativeStatus`
668
+ returns as soon as the scope is `ready` or has failed with no retry pending,
669
+ keeps waiting through a retrying failure, and takes the server's
670
+ `retryAfterSeconds` as the cadence in place of `pollIntervalMs`, longer or
671
+ shorter — it is when the next compute actually happens, so asking sooner sees
672
+ nothing new and asking later sits on an answer that already exists. Once the
673
+ remaining budget cannot cover the next cadence it raises the timeout rather
674
+ than spending one more request that cannot carry new data. `signal` aborts
675
+ the wait and the request in flight with it. A failed status is returned, not thrown; branch
676
+ on `errorCode`. `isDerivativeStatusSettled` is the same predicate, exported
677
+ for callers that poll on their own.
678
+
679
+ When several questions write the same derived scope, the most optimistic true
680
+ state answers (`ready`, then `stale`, then `pending`, then `failed`), because
681
+ serving data is registration-agnostic: a duplicate that never wrote anything
682
+ must not report away an answer the scope has.
683
+
684
+ The status route needs a Personal Server that ships it; an older one answers
685
+ 404 for the route itself, which arrives as `DerivativeQuestionNotFoundError`
686
+ — the same error as a covered scope with no question behind it.
687
+
624
688
  ## Networks
625
689
 
626
690
  | Network | Chain ID | RPC URL |
@@ -51,7 +51,8 @@ export { ScopeSchema, parseScope, scopeToPathSegments, scopeMatchesPattern, scop
51
51
  export { SCOPE_ACTIONS, InvalidScopeEntryError, parseScopeEntry, formatScopeEntry, grantPermissions, permissionsToScopes, tryGrantPermissions, hasAction, type ScopeAction, type ParsedScopeEntry, type GrantPermission, } from "./protocol/scope-actions.js";
52
52
  export { WRITE_SESSION_PATH, WRITE_SIGNATURE_HEADER, WRITE_METADATA_HEADER, WRITE_FILENAME_HEADER, WRITE_CONTENT_DISPOSITION_HEADER, WRITER_ATTRIBUTION_KEY, LINEAGE_KEY, LINEAGE_FIELD, MAX_LINEAGE_SOURCES, RESERVED_WRITE_KEYS, openWriteSession, writeData, writePersonalServerData, sessionCoversScope, binaryWriteSignedBytes, normalizeBinaryMimeType, parseWriteMetadataHeader, encodeWriteMetadataHeader, type WriteTransportRetryOptions, type WriteSession, type OpenWriteSessionParams, type WriteBinaryPayload, type LineageSource, type WriteJsonDataParams, type WriteBinaryDataParams, type WriteDataParams, type WriteDataResult, type WritePersonalServerDataParams, type WritePersonalServerDataResult, type BinaryWriteSignedBytesInput, } from "./protocol/personal-server-write.js";
53
53
  export { resolveWriteSigner, type WriteSigner, type WriteSignerSource, type ViemWriteAccount, type ViemWriteWalletClient, type ResolveWriteSignerOptions, } from "./protocol/write-signer.js";
54
- export { DERIVATIVE_QUESTIONS_PATH, MAX_QUESTION_SOURCE_SCOPES, MAX_QUESTION_CHARS, MAX_QUESTION_MODEL_CHARS, DEFAULT_QUESTION_TIMEOUT_MS, DEFAULT_QUESTION_POLL_INTERVAL_MS, QUESTION_STATUSES, registerQuestion, getQuestion, listQuestions, recomputeQuestion, deleteQuestion, waitForQuestion, askPersonalServer, QuestionStatusSchema, QuestionRegisteredBySchema, DerivativeQuestionSchema, QuestionRecomputeResultSchema, QuestionDeleteResultSchema, type QuestionStatus, type QuestionRegisteredBy, type DerivativeQuestion, type QuestionRecomputeResult, type QuestionDeleteResult, type DerivativeQuestionAuthParams, type RegisterQuestionParams, type GetQuestionParams, type ListQuestionsParams, type RecomputeQuestionParams, type DeleteQuestionParams, type WaitForQuestionParams, type AskPersonalServerParams, type AskPersonalServerResult, } from "./protocol/derivative-questions.js";
54
+ export { DERIVATIVE_QUESTIONS_PATH, MAX_QUESTION_SOURCE_SCOPES, MAX_QUESTION_CHARS, MAX_QUESTION_MODEL_CHARS, DEFAULT_QUESTION_TIMEOUT_MS, DEFAULT_QUESTION_POLL_INTERVAL_MS, QUESTION_STATUSES, DERIVATIVE_ERROR_CODES, DerivativeErrorCodeSchema, type DerivativeErrorCode, registerQuestion, getQuestion, listQuestions, recomputeQuestion, deleteQuestion, waitForQuestion, askPersonalServer, QuestionStatusSchema, QuestionRegisteredBySchema, DerivativeQuestionSchema, QuestionRecomputeResultSchema, QuestionDeleteResultSchema, type QuestionStatus, type QuestionRegisteredBy, type DerivativeQuestion, type QuestionRecomputeResult, type QuestionDeleteResult, type DerivativeQuestionAuthParams, type RegisterQuestionParams, type GetQuestionParams, type ListQuestionsParams, type RecomputeQuestionParams, type DeleteQuestionParams, type WaitForQuestionParams, type AskPersonalServerParams, type AskPersonalServerResult, } from "./protocol/derivative-questions.js";
55
+ export { DERIVATIVE_STATUS_PATH, DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS, DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS, derivativeStatusTarget, getDerivativeStatus, waitForDerivativeStatus, isDerivativeStatusSettled, DerivativeStatusSchema, type DerivativeStatus, type GetDerivativeStatusParams, type WaitForDerivativeStatusParams, } from "./protocol/derivative-status.js";
55
56
  export { deriveDataPointId, isDataPointId, scopeNamespace, derivedScopeViolatesNaming, assertDerivedScopeNaming, isRedactedLineageNode, personalServerLineagePath, gatewayLineagePath, getLineage, getPersonalServerLineage, getGatewayLineage, LineageNodeSchema, RedactedLineageNodeSchema, LineageEntrySchema, LineageGraphSchema, type LineageNode, type RedactedLineageNode, type LineageEntry, type LineageGraph, type LineageReadResult, type PersonalServerLineageParams, type GatewayLineageParams, type GetLineageParams, } from "./protocol/lineage.js";
56
57
  export { DataFileEnvelopeSchema, createDataFileEnvelope, IngestResponseSchema, type DataFileEnvelope, type IngestResponse, } from "./protocol/data-file.js";
57
58
  export { createGatewayClient, type GatewayEnvelope, type GatewayProof, type Builder, type Schema, type ServerInfo, type OwnerServerRecord, type OwnerServersResult, type GatewayGrantFee, type GatewayGrantStatus, type GatewayGrantResponse, type GrantListItem, type DataPointRecord, type DataPointListResult, type ListDataPointsOptions, type RegisterServerParams, type RegisterServerResult, type RegisterBuilderParams, type RegisterBuilderResult, type RegisterDataPointParams, type RegisterDataPointResult, type GetDataPointOptions, type DeleteDataPointParams, type DeleteDataPointResult, type CreateGrantParams, type RevokeGrantParams, type AccessRecord, type PayForOperationParams, type PayForOperationResult, type SettleOpType, type SettleItem, type SettlePromoteResult, type SettleReconcileItem, type SettleParams, type SettleResult, type GatewayClient, } from "./protocol/gateway.js";
@@ -33777,6 +33777,13 @@ var QUESTION_STATUSES = [
33777
33777
  "failed",
33778
33778
  "stale"
33779
33779
  ];
33780
+ var DERIVATIVE_ERROR_CODES = [
33781
+ "inference_unavailable",
33782
+ "source_missing",
33783
+ "grant_invalid",
33784
+ "internal"
33785
+ ];
33786
+ var DerivativeErrorCodeSchema = z5.enum(DERIVATIVE_ERROR_CODES);
33780
33787
  var QuestionStatusSchema = z5.enum(QUESTION_STATUSES);
33781
33788
  var QuestionRegisteredBySchema = z5.union([
33782
33789
  z5.object({ kind: z5.literal("owner") }),
@@ -33798,6 +33805,14 @@ var DerivativeQuestionSchema = z5.object({
33798
33805
  status: QuestionStatusSchema,
33799
33806
  /** A short reason, set only while `status` is `failed`. */
33800
33807
  error: nullableString,
33808
+ /**
33809
+ * The coarse failure class behind `error`, set only while `status` is
33810
+ * `failed`. `null` from a Personal Server that predates the class
33811
+ * (`personal-server-ts` before the status route).
33812
+ */
33813
+ errorCode: DerivativeErrorCodeSchema.nullish().transform(
33814
+ (value) => value ?? null
33815
+ ),
33801
33816
  createdAt: z5.string(),
33802
33817
  updatedAt: nullableString,
33803
33818
  /** When the last compute finished, or `null` while `pending`. */
@@ -33930,6 +33945,7 @@ async function questionErrorFromResponse(response, body) {
33930
33945
  );
33931
33946
  }
33932
33947
  }
33948
+ var personalServerErrorFromQuestionResponse = questionErrorFromResponse;
33933
33949
  async function sendOnce(params, resolved, session, spec, bodyBytes) {
33934
33950
  return sendWithFreshProof(
33935
33951
  spec.label,
@@ -34209,6 +34225,166 @@ async function askPersonalServer(params) {
34209
34225
  return { registration, record };
34210
34226
  }
34211
34227
 
34228
+ // src/protocol/derivative-status.ts
34229
+ import { z as z6 } from "zod";
34230
+ var DERIVATIVE_STATUS_PATH = "/v1/derivatives/status";
34231
+ var DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS = 12e4;
34232
+ var DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS = 2e3;
34233
+ var nullable = (schema) => schema.nullish().transform((value) => value ?? null);
34234
+ var DerivativeStatusSchema = z6.object({
34235
+ derivedScope: z6.string().min(1),
34236
+ status: QuestionStatusSchema,
34237
+ /** When the last compute finished, or `null` if none ever has. */
34238
+ lastComputedAt: nullable(z6.string()),
34239
+ /** Local version of the derived record the last compute wrote. */
34240
+ derivedVersion: nullable(z6.number()),
34241
+ derivedCollectedAt: nullable(z6.string()),
34242
+ /** The failure class; `null` unless `status` is `failed`. */
34243
+ errorCode: nullable(DerivativeErrorCodeSchema),
34244
+ /**
34245
+ * Seconds until the Personal Server's next automatic retry, or `null` when
34246
+ * none is pending or running — the terminal signature. Poll on this cadence
34247
+ * rather than guessing one.
34248
+ */
34249
+ retryAfterSeconds: nullable(z6.number())
34250
+ });
34251
+ function derivativeStatusTarget(derivedScope) {
34252
+ return `${DERIVATIVE_STATUS_PATH}?derivedScope=${encodeURIComponent(derivedScope)}`;
34253
+ }
34254
+ function normalizeBaseUrl3(url) {
34255
+ return url.replace(/\/+$/, "");
34256
+ }
34257
+ function resolveFetch3(fetchFn) {
34258
+ const resolved = fetchFn ?? globalThis.fetch;
34259
+ if (resolved === void 0) {
34260
+ throw new WriteRequestError("No fetch implementation available");
34261
+ }
34262
+ return resolved;
34263
+ }
34264
+ function requireDerivedScope(derivedScope) {
34265
+ if (typeof derivedScope !== "string" || derivedScope.length === 0) {
34266
+ throw new WriteRequestError("derivedScope is required");
34267
+ }
34268
+ return derivedScope;
34269
+ }
34270
+ function sleep3(ms, signal) {
34271
+ if (ms <= 0) return Promise.resolve();
34272
+ return new Promise((resolve, reject) => {
34273
+ const timer = setTimeout(() => {
34274
+ signal?.removeEventListener("abort", onAbort);
34275
+ resolve();
34276
+ }, ms);
34277
+ const onAbort = () => {
34278
+ clearTimeout(timer);
34279
+ reject(abortError2(signal));
34280
+ };
34281
+ signal?.addEventListener("abort", onAbort, { once: true });
34282
+ });
34283
+ }
34284
+ function timeoutError(latest, timeoutMs) {
34285
+ return new DerivativeQuestionTimeoutError(
34286
+ `Derived scope ${latest.derivedScope} was still ${latest.status} after ${timeoutMs}ms`,
34287
+ {
34288
+ derivedScope: latest.derivedScope,
34289
+ status: latest.status,
34290
+ errorCode: latest.errorCode,
34291
+ retryAfterSeconds: latest.retryAfterSeconds,
34292
+ timeoutMs
34293
+ }
34294
+ );
34295
+ }
34296
+ function abortError2(signal) {
34297
+ const reason = signal?.reason;
34298
+ return reason instanceof Error ? reason : new WriteRequestError("Derivative status wait was aborted");
34299
+ }
34300
+ function isDerivativeStatusSettled(status) {
34301
+ if (status.status === "ready") return true;
34302
+ return status.status === "failed" && status.retryAfterSeconds === null;
34303
+ }
34304
+ async function getDerivativeStatus(params) {
34305
+ const derivedScope = requireDerivedScope(params.derivedScope);
34306
+ const fetchFn = resolveFetch3(params.fetch);
34307
+ const baseUrl = normalizeBaseUrl3(params.personalServerUrl);
34308
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
34309
+ const headers = new Headers(params.headers);
34310
+ headers.set(
34311
+ "Authorization",
34312
+ await buildWeb3SignedHeader({
34313
+ signMessage: signer.signMessage,
34314
+ aud: params.audience ?? baseUrl,
34315
+ method: "GET",
34316
+ uri: DERIVATIVE_STATUS_PATH,
34317
+ grantId: params.grantId
34318
+ })
34319
+ );
34320
+ let response;
34321
+ try {
34322
+ response = await fetchFn(
34323
+ `${baseUrl}${derivativeStatusTarget(derivedScope)}`,
34324
+ {
34325
+ method: "GET",
34326
+ headers,
34327
+ ...params.signal ? { signal: params.signal } : {}
34328
+ }
34329
+ );
34330
+ } catch (err) {
34331
+ throw new WriteTransportError(
34332
+ `Derivative status read failed: ${err instanceof Error ? err.message : String(err)}`,
34333
+ 1,
34334
+ err
34335
+ );
34336
+ }
34337
+ if (!response.ok) {
34338
+ throw await personalServerErrorFromQuestionResponse(
34339
+ response
34340
+ );
34341
+ }
34342
+ let body;
34343
+ try {
34344
+ body = await response.json();
34345
+ } catch (err) {
34346
+ throw new DerivativeQuestionRejectedError(
34347
+ "Derivative status response is not JSON",
34348
+ response.status,
34349
+ null,
34350
+ { cause: err instanceof Error ? err.message : String(err) }
34351
+ );
34352
+ }
34353
+ const parsed = DerivativeStatusSchema.safeParse(body);
34354
+ if (!parsed.success) {
34355
+ throw new DerivativeQuestionRejectedError(
34356
+ "Derivative status response is not a status view",
34357
+ response.status,
34358
+ null,
34359
+ { issues: parsed.error.issues }
34360
+ );
34361
+ }
34362
+ return parsed.data;
34363
+ }
34364
+ async function waitForDerivativeStatus(params) {
34365
+ const timeoutMs = Math.max(
34366
+ 0,
34367
+ params.timeoutMs ?? DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS
34368
+ );
34369
+ const pollIntervalMs = Math.max(
34370
+ 0,
34371
+ params.pollIntervalMs ?? DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS
34372
+ );
34373
+ const deadline = Date.now() + timeoutMs;
34374
+ for (; ; ) {
34375
+ if (params.signal?.aborted) throw abortError2(params.signal);
34376
+ const latest = await getDerivativeStatus(params);
34377
+ if (isDerivativeStatusSettled(latest)) return latest;
34378
+ const remaining = deadline - Date.now();
34379
+ if (remaining <= 0) throw timeoutError(latest, timeoutMs);
34380
+ const waitMs = latest.retryAfterSeconds === null ? pollIntervalMs : latest.retryAfterSeconds * 1e3;
34381
+ if (waitMs > remaining) {
34382
+ throw timeoutError(latest, timeoutMs);
34383
+ }
34384
+ await sleep3(waitMs, params.signal);
34385
+ }
34386
+ }
34387
+
34212
34388
  // src/protocol/gateway.ts
34213
34389
  function withGrantPermissions(grant) {
34214
34390
  const stripped = { ...grant };
@@ -34821,9 +34997,13 @@ export {
34821
34997
  ContractFactory,
34822
34998
  ContractNotFoundError,
34823
34999
  DATA_REGISTRY_STATUS_ABI,
35000
+ DEFAULT_DERIVATIVE_STATUS_POLL_INTERVAL_MS,
35001
+ DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS,
34824
35002
  DEFAULT_QUESTION_POLL_INTERVAL_MS,
34825
35003
  DEFAULT_QUESTION_TIMEOUT_MS,
35004
+ DERIVATIVE_ERROR_CODES,
34826
35005
  DERIVATIVE_QUESTIONS_PATH,
35006
+ DERIVATIVE_STATUS_PATH,
34827
35007
  DataFileEnvelopeSchema,
34828
35008
  DataPointDeletedError,
34829
35009
  DataPointNotFoundError,
@@ -34832,6 +35012,7 @@ export {
34832
35012
  DerivativeComputeUnavailableError,
34833
35013
  DerivativeCycleError,
34834
35014
  DerivativeDerivedScopeRequiredError,
35015
+ DerivativeErrorCodeSchema,
34835
35016
  DerivativeQuestionFailedError,
34836
35017
  DerivativeQuestionInvalidError,
34837
35018
  DerivativeQuestionNotFoundError,
@@ -34839,6 +35020,7 @@ export {
34839
35020
  DerivativeQuestionSchema,
34840
35021
  DerivativeQuestionTimeoutError,
34841
35022
  DerivativeSourceNotGrantedError,
35023
+ DerivativeStatusSchema,
34842
35024
  DropboxStorage,
34843
35025
  ECIESError,
34844
35026
  ESCROW_DEPOSIT_ABI2 as ESCROW_DEPOSIT_ABI,
@@ -34963,6 +35145,7 @@ export {
34963
35145
  decryptWithPassword,
34964
35146
  deleteDataPoint,
34965
35147
  deleteQuestion,
35148
+ derivativeStatusTarget,
34966
35149
  deriveDataPointId,
34967
35150
  deriveMasterKey,
34968
35151
  deriveScopeKey,
@@ -34986,6 +35169,7 @@ export {
34986
35169
  getContractAddress,
34987
35170
  getContractController,
34988
35171
  getContractInfo,
35172
+ getDerivativeStatus,
34989
35173
  getFee,
34990
35174
  getGatewayLineage,
34991
35175
  getLineage,
@@ -35001,6 +35185,7 @@ export {
35001
35185
  isDataPointId,
35002
35186
  isDataPointTombstone,
35003
35187
  isDataPortabilityGatewayConfig,
35188
+ isDerivativeStatusSettled,
35004
35189
  isECIESEncrypted,
35005
35190
  isPlatformSupported,
35006
35191
  isRedactedLineageNode,
@@ -35043,6 +35228,7 @@ export {
35043
35228
  verifyGrantRegistration,
35044
35229
  verifyPkceChallenge,
35045
35230
  verifyWeb3Signed,
35231
+ waitForDerivativeStatus,
35046
35232
  waitForQuestion,
35047
35233
  writeData,
35048
35234
  writePersonalServerData