@opendatalabs/personal-server-ts-server 1.8.0 → 1.10.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.
@@ -4404,7 +4404,7 @@ function weierstrass(curveDef) {
4404
4404
  function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
4405
4405
  if (["recovered", "canonical"].some((k10) => k10 in opts))
4406
4406
  throw new Error("sign() legacy options not supported");
4407
- const { hash: hash2, randomBytes: randomBytes4 } = CURVE4;
4407
+ const { hash: hash2, randomBytes: randomBytes5 } = CURVE4;
4408
4408
  let { lowS, prehash, extraEntropy: ent } = opts;
4409
4409
  if (lowS == null)
4410
4410
  lowS = true;
@@ -4416,7 +4416,7 @@ function weierstrass(curveDef) {
4416
4416
  const d10 = normPrivateKeyToScalar(privateKey);
4417
4417
  const seedArgs = [int2octets(d10), int2octets(h1int)];
4418
4418
  if (ent != null && ent !== false) {
4419
- const e10 = ent === true ? randomBytes4(Fp2.BYTES) : ent;
4419
+ const e10 = ent === true ? randomBytes5(Fp2.BYTES) : ent;
4420
4420
  seedArgs.push(ensureBytes("extraEntropy", e10));
4421
4421
  }
4422
4422
  const seed = concatBytes3(...seedArgs);
@@ -105697,6 +105697,11 @@ var ServerNotConfiguredError = class extends ProtocolError {
105697
105697
  super(500, "SERVER_NOT_CONFIGURED", "Server is not configured", details);
105698
105698
  }
105699
105699
  };
105700
+ var ContentTooLargeError = class extends ProtocolError {
105701
+ constructor(details) {
105702
+ super(413, "CONTENT_TOO_LARGE", "Content too large", details);
105703
+ }
105704
+ };
105700
105705
  var LineageInvalidError = class extends ProtocolError {
105701
105706
  constructor(message, details) {
105702
105707
  super(400, "LINEAGE_INVALID", message, details);
@@ -105747,6 +105752,31 @@ var DataDeletedError = class extends ProtocolError {
105747
105752
  super(410, "DATA_DELETED", "Data point has been deleted", details);
105748
105753
  }
105749
105754
  };
105755
+ var DerivativeQuestionInvalidError = class extends ProtocolError {
105756
+ constructor(message, details) {
105757
+ super(400, "DERIVATIVE_QUESTION_INVALID", message, details);
105758
+ }
105759
+ };
105760
+ var DerivativeQuestionNotFoundError = class extends ProtocolError {
105761
+ constructor(details) {
105762
+ super(404, "DERIVATIVE_QUESTION_NOT_FOUND", "Question not found", details);
105763
+ }
105764
+ };
105765
+ var DerivativeCycleError = class extends ProtocolError {
105766
+ constructor(details) {
105767
+ super(409, "DERIVATIVE_CYCLE", `Registering this question would make "${details.derivedScope}" a transitive source of itself; recompute would never settle`, details);
105768
+ }
105769
+ };
105770
+ var DerivativeSourceNotGrantedError = class extends ProtocolError {
105771
+ constructor(details) {
105772
+ super(403, "DERIVATIVE_SOURCE_NOT_GRANTED", "The builder's grant does not cover reading every source scope of this question", details);
105773
+ }
105774
+ };
105775
+ var DerivativeComputeUnavailableError = class extends ProtocolError {
105776
+ constructor(details) {
105777
+ super(503, "DERIVATIVE_COMPUTE_UNAVAILABLE", "This server has no derivative compute configured", details);
105778
+ }
105779
+ };
105750
105780
 
105751
105781
  // ../core/dist/sync/data-point-id.js
105752
105782
  function computeDataPointId(ownerAddress, scope) {
@@ -109719,6 +109749,21 @@ var DEFAULTS = {
109719
109749
  enabled: true,
109720
109750
  serverAddr: "frpc.server.vana.org",
109721
109751
  serverPort: 7e3
109752
+ },
109753
+ inference: {
109754
+ // OpenAI-compatible chat completions endpoint the derivative compute
109755
+ // layer calls. Point it at the Vana inference relay (which holds the
109756
+ // provider key) or straight at a provider for local development.
109757
+ baseUrl: "https://inference.phala.com/v1",
109758
+ model: "z-ai/glm-5.2",
109759
+ // End to end encryption of prompt and answer to the Phala gateway
109760
+ // (E2EE v2): the relay only sees ciphertext. Set false only for local
109761
+ // development against a provider without ACI attestation.
109762
+ e2ee: true,
109763
+ // Newest-first items kept per source scope when a prompt is assembled.
109764
+ maxSourceItems: 50,
109765
+ // Quiet period after a source scope changes before a recompute starts.
109766
+ recomputeDebounceMs: 5e3
109722
109767
  }
109723
109768
  };
109724
109769
  var StorageBackend = external_exports.enum([
@@ -109772,7 +109817,14 @@ var ServerConfigSchema = external_exports.object({
109772
109817
  enabled: external_exports.boolean().default(DEFAULTS.tunnel.enabled),
109773
109818
  serverAddr: external_exports.string().default(DEFAULTS.tunnel.serverAddr),
109774
109819
  serverPort: external_exports.number().int().min(1).max(65535).default(DEFAULTS.tunnel.serverPort)
109775
- }).default(DEFAULTS.tunnel)
109820
+ }).default(DEFAULTS.tunnel),
109821
+ inference: external_exports.object({
109822
+ baseUrl: external_exports.url().default(DEFAULTS.inference.baseUrl),
109823
+ model: external_exports.string().min(1).default(DEFAULTS.inference.model),
109824
+ e2ee: external_exports.boolean().default(DEFAULTS.inference.e2ee),
109825
+ maxSourceItems: external_exports.number().int().min(1).max(1e4).default(DEFAULTS.inference.maxSourceItems),
109826
+ recomputeDebounceMs: external_exports.number().int().min(0).max(36e5).default(DEFAULTS.inference.recomputeDebounceMs)
109827
+ }).default(DEFAULTS.inference)
109776
109828
  });
109777
109829
 
109778
109830
  // ../lite/dist/state.js
@@ -112676,6 +112728,18 @@ function apiLoggerAsLogger(logger) {
112676
112728
  error: (payload, message) => (logger?.error ?? noop)(payload, message ?? "")
112677
112729
  };
112678
112730
  }
112731
+ function notifyDataWritten(deps, event) {
112732
+ if (!deps.onDataWritten)
112733
+ return;
112734
+ try {
112735
+ deps.onDataWritten(event);
112736
+ } catch (err2) {
112737
+ deps.logger?.warn?.({
112738
+ scope: event.scope,
112739
+ error: err2 instanceof Error ? err2.message : String(err2)
112740
+ }, "onDataWritten hook failed; record already stored");
112741
+ }
112742
+ }
112679
112743
  function notifyNewData(syncManager) {
112680
112744
  if (!syncManager)
112681
112745
  return;
@@ -113040,6 +113104,11 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
113040
113104
  }, "Binary data file ingested");
113041
113105
  await logBuilderWrite();
113042
113106
  notifyNewData(deps.syncManager);
113107
+ notifyDataWritten(deps, {
113108
+ scope: scopeResult.scope,
113109
+ collectedAt: collectedAtValue,
113110
+ lineageSources: lineage2?.sources
113111
+ });
113043
113112
  return jsonResponse(result2.response, { status: 201 });
113044
113113
  }
113045
113114
  const parsed = await parseJsonObjectBody(request2, "Request body must be valid JSON");
@@ -113067,6 +113136,11 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
113067
113136
  }, "Data file ingested");
113068
113137
  await logBuilderWrite();
113069
113138
  notifyNewData(deps.syncManager);
113139
+ notifyDataWritten(deps, {
113140
+ scope: scopeResult.scope,
113141
+ collectedAt: collectedAtValue,
113142
+ lineageSources: lineage?.sources
113143
+ });
113070
113144
  return jsonResponse(result.response, { status: 201 });
113071
113145
  } catch (err2) {
113072
113146
  if (err2 instanceof IngestPersistedError) {
@@ -113293,6 +113367,93 @@ async function handlePersonalServerOauthTokenRequest(request2, deps) {
113293
113367
  });
113294
113368
  }
113295
113369
 
113370
+ // ../core/dist/derivatives/types.js
113371
+ function questionRegistrationView(registration) {
113372
+ return {
113373
+ questionId: registration.questionId,
113374
+ derivedScope: registration.derivedScope,
113375
+ sourceScopes: [...registration.sourceScopes],
113376
+ question: registration.question,
113377
+ model: registration.model,
113378
+ registeredBy: registration.registeredBy,
113379
+ status: registration.status,
113380
+ error: registration.error,
113381
+ createdAt: registration.createdAt,
113382
+ updatedAt: registration.updatedAt,
113383
+ lastComputedAt: registration.lastComputedAt,
113384
+ derivedVersion: registration.derivedVersion,
113385
+ derivedCollectedAt: registration.derivedCollectedAt
113386
+ };
113387
+ }
113388
+
113389
+ // ../core/dist/derivatives/store.js
113390
+ function clone2(registration) {
113391
+ return {
113392
+ ...registration,
113393
+ sourceScopes: [...registration.sourceScopes],
113394
+ registeredBy: { ...registration.registeredBy }
113395
+ };
113396
+ }
113397
+ function matchesQuestionFilter(registration, filter) {
113398
+ if (!filter)
113399
+ return true;
113400
+ if (filter.derivedScope && registration.derivedScope !== filter.derivedScope)
113401
+ return false;
113402
+ if (filter.sourceScope && !registration.sourceScopes.includes(filter.sourceScope))
113403
+ return false;
113404
+ if (filter.builder) {
113405
+ const by2 = registration.registeredBy;
113406
+ if (by2.kind !== "builder" || by2.builder.toLowerCase() !== filter.builder.toLowerCase())
113407
+ return false;
113408
+ }
113409
+ return true;
113410
+ }
113411
+ function sortQuestions(registrations) {
113412
+ return [...registrations].sort((a10, b10) => a10.createdAt.localeCompare(b10.createdAt) || a10.questionId.localeCompare(b10.questionId));
113413
+ }
113414
+ function createInMemoryQuestionStore(options = {}) {
113415
+ const byId = /* @__PURE__ */ new Map();
113416
+ for (const registration of options.initial ?? []) {
113417
+ byId.set(registration.questionId, clone2(registration));
113418
+ }
113419
+ async function changed() {
113420
+ if (!options.onChange)
113421
+ return;
113422
+ await options.onChange(sortQuestions([...byId.values()]).map(clone2));
113423
+ }
113424
+ return {
113425
+ async list(filter) {
113426
+ return sortQuestions([...byId.values()].filter((registration) => matchesQuestionFilter(registration, filter))).map(clone2);
113427
+ },
113428
+ async get(questionId) {
113429
+ const registration = byId.get(questionId);
113430
+ return registration ? clone2(registration) : null;
113431
+ },
113432
+ async insert(registration) {
113433
+ if (byId.has(registration.questionId)) {
113434
+ throw new Error(`Question ${registration.questionId} is already registered`);
113435
+ }
113436
+ byId.set(registration.questionId, clone2(registration));
113437
+ await changed();
113438
+ },
113439
+ async update(questionId, patch) {
113440
+ const current = byId.get(questionId);
113441
+ if (!current)
113442
+ return null;
113443
+ const next = { ...current, ...patch };
113444
+ byId.set(questionId, next);
113445
+ await changed();
113446
+ return clone2(next);
113447
+ },
113448
+ async delete(questionId) {
113449
+ const existed = byId.delete(questionId);
113450
+ if (existed)
113451
+ await changed();
113452
+ return existed;
113453
+ }
113454
+ };
113455
+ }
113456
+
113296
113457
  // ../core/dist/policy/data-read.js
113297
113458
  function parseGrantExpiresAtSeconds(value) {
113298
113459
  if (value === null || value === void 0 || value === "0")
@@ -113382,6 +113543,1635 @@ async function verifyDataReadPolicy(input, ports) {
113382
113543
  return grant;
113383
113544
  }
113384
113545
 
113546
+ // ../core/dist/policy/data-write.js
113547
+ var WRITE_SCOPE_PREFIX = "write:";
113548
+ function isWriteScopeEntry(entry) {
113549
+ return entry.startsWith(WRITE_SCOPE_PREFIX);
113550
+ }
113551
+ function writeScopePatterns(grantScopes) {
113552
+ return grantScopes.filter(isWriteScopeEntry).map((entry) => entry.slice(WRITE_SCOPE_PREFIX.length)).filter((pattern) => pattern.length > 0);
113553
+ }
113554
+ function scopeCoveredByWriteGrant(requestedScope, grantScopes) {
113555
+ return writeScopePatterns(grantScopes).some((pattern) => scopeMatchesPattern(requestedScope, pattern));
113556
+ }
113557
+ async function verifyDataWritePolicy(input, ports) {
113558
+ const available = await ports.runtimeAvailability?.isAvailable();
113559
+ if (available === false) {
113560
+ throw new PsUnavailableError();
113561
+ }
113562
+ const builder = await ports.authSessionVerifier.getBuilder(input.signer);
113563
+ if (!builder) {
113564
+ throw new UnregisteredBuilderError();
113565
+ }
113566
+ if (!input.grantId) {
113567
+ throw new GrantRequiredError({
113568
+ reason: "No grantId bound to the write session"
113569
+ });
113570
+ }
113571
+ const grant = await ports.grantVerifier.getGrant(input.grantId);
113572
+ if (!grant) {
113573
+ throw new GrantRequiredError({
113574
+ reason: "Grant not found",
113575
+ grantId: input.grantId
113576
+ });
113577
+ }
113578
+ if (grant.revokedAt !== null) {
113579
+ throw new GrantRevokedError({ grantId: grant.id });
113580
+ }
113581
+ if (!grant.scopes || writeScopePatterns(grant.scopes).length === 0) {
113582
+ throw new ScopeMismatchError({
113583
+ requestedScope: input.requestedScope,
113584
+ reason: "Grant has no write scopes"
113585
+ });
113586
+ }
113587
+ if (grant.expiresAt !== null && grant.expiresAt !== void 0) {
113588
+ const expiresAtSec = parseGrantExpiresAtSeconds(grant.expiresAt);
113589
+ if (expiresAtSec === null) {
113590
+ throw new ScopeMismatchError({
113591
+ requestedScope: input.requestedScope,
113592
+ reason: "Grant expiry is invalid"
113593
+ });
113594
+ }
113595
+ if (expiresAtSec > 0) {
113596
+ const nowSec = Math.floor(Date.now() / 1e3);
113597
+ if (expiresAtSec < nowSec) {
113598
+ throw new GrantExpiredError({
113599
+ expiresAt: expiresAtSec
113600
+ });
113601
+ }
113602
+ }
113603
+ }
113604
+ if (!scopeCoveredByWriteGrant(input.requestedScope, grant.scopes)) {
113605
+ throw new ScopeMismatchError({
113606
+ requestedScope: input.requestedScope,
113607
+ grantedScopes: grant.scopes,
113608
+ reason: "Grant does not authorize writing to this scope"
113609
+ });
113610
+ }
113611
+ if (builder.id.toLowerCase() !== grant.granteeId.toLowerCase()) {
113612
+ throw new InvalidSignatureError3({
113613
+ reason: "Write signer is not the grant builder",
113614
+ expected: grant.granteeId,
113615
+ actual: input.signer
113616
+ });
113617
+ }
113618
+ if (!input.serverOwner) {
113619
+ throw new ServerNotConfiguredError({
113620
+ reason: "serverOwner is required to verify grant ownership"
113621
+ });
113622
+ }
113623
+ if (!grant.grantorAddress || grant.grantorAddress.toLowerCase() !== input.serverOwner.toLowerCase()) {
113624
+ throw new GrantOwnerMismatchError({
113625
+ grantId: grant.id,
113626
+ expected: input.serverOwner,
113627
+ actual: grant.grantorAddress ?? null
113628
+ });
113629
+ }
113630
+ await ports.writeFeeVerifier?.assertWriteAllowed({
113631
+ builder: input.signer,
113632
+ grant,
113633
+ scope: input.requestedScope
113634
+ });
113635
+ return grant;
113636
+ }
113637
+
113638
+ // ../core/dist/derivatives/registration.js
113639
+ var MAX_QUESTION_SOURCE_SCOPES = 16;
113640
+ var MAX_QUESTION_CHARS = 8e3;
113641
+ var MAX_MODEL_CHARS = 128;
113642
+ var MAX_ECHOED_SCOPE_CHARS = 128;
113643
+ var MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
113644
+ function isRecord4(value) {
113645
+ return value !== null && typeof value === "object" && !Array.isArray(value);
113646
+ }
113647
+ function parseScope(value, field) {
113648
+ if (typeof value !== "string") {
113649
+ throw new DerivativeQuestionInvalidError(`${field} must be a scope string`, {
113650
+ field
113651
+ });
113652
+ }
113653
+ const parsed = parseDataScopeContract(value);
113654
+ if (!parsed.ok) {
113655
+ throw new DerivativeQuestionInvalidError(`${field} is not a valid scope: ${parsed.body.message}`, { field, scope: value.slice(0, MAX_ECHOED_SCOPE_CHARS) });
113656
+ }
113657
+ return parsed.scope;
113658
+ }
113659
+ function parseQuestionInput(body) {
113660
+ if (!isRecord4(body)) {
113661
+ throw new DerivativeQuestionInvalidError("Body must be a JSON object");
113662
+ }
113663
+ const derivedScope = parseScope(body.derivedScope, "derivedScope");
113664
+ if (!Array.isArray(body.sourceScopes) || body.sourceScopes.length === 0) {
113665
+ throw new DerivativeQuestionInvalidError("sourceScopes must be a non-empty array of scopes", { field: "sourceScopes" });
113666
+ }
113667
+ if (body.sourceScopes.length > MAX_QUESTION_SOURCE_SCOPES) {
113668
+ throw new DerivativeQuestionInvalidError(`sourceScopes lists ${body.sourceScopes.length} scopes; the maximum is ${MAX_QUESTION_SOURCE_SCOPES}`, { field: "sourceScopes", max: MAX_QUESTION_SOURCE_SCOPES });
113669
+ }
113670
+ const sourceScopes = [];
113671
+ for (const entry of body.sourceScopes) {
113672
+ const scope = parseScope(entry, "sourceScopes[]");
113673
+ if (sourceScopes.includes(scope)) {
113674
+ throw new DerivativeQuestionInvalidError("sourceScopes lists the same scope twice", { field: "sourceScopes", duplicate: scope });
113675
+ }
113676
+ if (scope === derivedScope) {
113677
+ throw new DerivativeQuestionInvalidError("derivedScope cannot be one of its own sources", { field: "sourceScopes", scope });
113678
+ }
113679
+ sourceScopes.push(scope);
113680
+ }
113681
+ if (typeof body.question !== "string" || body.question.trim() === "") {
113682
+ throw new DerivativeQuestionInvalidError("question must be a non-empty string", { field: "question" });
113683
+ }
113684
+ if (body.question.length > MAX_QUESTION_CHARS) {
113685
+ throw new DerivativeQuestionInvalidError(`question is ${body.question.length} characters; the maximum is ${MAX_QUESTION_CHARS}`, { field: "question", max: MAX_QUESTION_CHARS });
113686
+ }
113687
+ let model = null;
113688
+ if (body.model !== void 0 && body.model !== null) {
113689
+ if (typeof body.model !== "string" || body.model.length > MAX_MODEL_CHARS || !MODEL_ID.test(body.model)) {
113690
+ throw new DerivativeQuestionInvalidError("model must be a provider model id", { field: "model" });
113691
+ }
113692
+ model = body.model;
113693
+ }
113694
+ assertDerivedScopeNaming(derivedScope, sourceScopes);
113695
+ return { derivedScope, sourceScopes, question: body.question, model };
113696
+ }
113697
+ function findDerivationCycle(candidate, existing) {
113698
+ const sourcesOf = /* @__PURE__ */ new Map();
113699
+ const add2 = (derived, sources) => {
113700
+ const set2 = sourcesOf.get(derived) ?? /* @__PURE__ */ new Set();
113701
+ for (const source of sources)
113702
+ set2.add(source);
113703
+ sourcesOf.set(derived, set2);
113704
+ };
113705
+ for (const registration of existing) {
113706
+ add2(registration.derivedScope, registration.sourceScopes);
113707
+ }
113708
+ add2(candidate.derivedScope, candidate.sourceScopes);
113709
+ const target = candidate.derivedScope;
113710
+ const visited = /* @__PURE__ */ new Set();
113711
+ const stack = [
113712
+ { scope: target, path: [target] }
113713
+ ];
113714
+ while (stack.length > 0) {
113715
+ const { scope, path } = stack.pop();
113716
+ for (const source of sourcesOf.get(scope) ?? []) {
113717
+ if (source === target)
113718
+ return [...path, source];
113719
+ if (visited.has(source))
113720
+ continue;
113721
+ visited.add(source);
113722
+ stack.push({ scope: source, path: [...path, source] });
113723
+ }
113724
+ }
113725
+ return null;
113726
+ }
113727
+ async function createQuestionRegistration(input) {
113728
+ const parsed = parseQuestionInput(input.body);
113729
+ const cycle = findDerivationCycle(parsed, await input.store.list());
113730
+ if (cycle) {
113731
+ throw new DerivativeCycleError({
113732
+ derivedScope: parsed.derivedScope,
113733
+ path: cycle
113734
+ });
113735
+ }
113736
+ const at3 = input.now().toISOString();
113737
+ const registration = {
113738
+ questionId: input.questionId,
113739
+ derivedScope: parsed.derivedScope,
113740
+ sourceScopes: parsed.sourceScopes,
113741
+ question: parsed.question,
113742
+ model: parsed.model,
113743
+ registeredBy: input.registeredBy,
113744
+ status: "pending",
113745
+ error: null,
113746
+ createdAt: at3,
113747
+ updatedAt: at3,
113748
+ lastComputedAt: null,
113749
+ derivedVersion: null,
113750
+ derivedCollectedAt: null
113751
+ };
113752
+ await input.store.insert(registration);
113753
+ return registration;
113754
+ }
113755
+ function uncoveredSourceScopes(sourceScopes, grantScopes) {
113756
+ const readEntries = (grantScopes ?? []).filter((entry) => !isWriteScopeEntry(entry));
113757
+ return sourceScopes.filter((scope) => !scopeCoveredByGrant(scope, readEntries));
113758
+ }
113759
+
113760
+ // ../core/dist/derivatives/prompt.js
113761
+ var DEFAULT_MAX_SOURCE_ITEMS = 50;
113762
+ var DEFAULT_MAX_SOURCE_CHARS = 2e5;
113763
+ var TIMESTAMP_KEYS = [
113764
+ "collectedAt",
113765
+ "updatedAt",
113766
+ "updated_at",
113767
+ "update_time",
113768
+ "createdAt",
113769
+ "created_at",
113770
+ "create_time",
113771
+ "timestamp",
113772
+ "time",
113773
+ "date",
113774
+ "publishedAt",
113775
+ "published_at"
113776
+ ];
113777
+ var RESERVED_KEYS = /* @__PURE__ */ new Set(["$lineage", "$writtenBy", "$binary"]);
113778
+ function isRecord5(value) {
113779
+ return value !== null && typeof value === "object" && !Array.isArray(value);
113780
+ }
113781
+ function timestampOf(item) {
113782
+ if (!isRecord5(item))
113783
+ return null;
113784
+ for (const key of TIMESTAMP_KEYS) {
113785
+ const value = item[key];
113786
+ if (typeof value === "number" && Number.isFinite(value)) {
113787
+ return value < 1e12 ? value * 1e3 : value;
113788
+ }
113789
+ if (typeof value === "string") {
113790
+ const parsed = Date.parse(value);
113791
+ if (!Number.isNaN(parsed))
113792
+ return parsed;
113793
+ }
113794
+ }
113795
+ return null;
113796
+ }
113797
+ function sortNewestFirst(items) {
113798
+ const indexed = items.map((item, index) => ({
113799
+ item,
113800
+ index,
113801
+ at: timestampOf(item)
113802
+ }));
113803
+ const dated = indexed.filter((entry) => entry.at !== null).sort((a10, b10) => b10.at - a10.at || b10.index - a10.index);
113804
+ const undated = indexed.filter((entry) => entry.at === null).reverse();
113805
+ return [...dated, ...undated].map((entry) => entry.item);
113806
+ }
113807
+ function trimSourceData(data, options = {}) {
113808
+ const maxItems = Math.max(1, options.maxItems ?? DEFAULT_MAX_SOURCE_ITEMS);
113809
+ const maxChars = Math.max(1, options.maxChars ?? DEFAULT_MAX_SOURCE_CHARS);
113810
+ let kept = 0;
113811
+ let total = 0;
113812
+ const trimArray = (items, limit2) => {
113813
+ total += items.length;
113814
+ const sorted = sortNewestFirst(items).slice(0, limit2);
113815
+ kept += sorted.length;
113816
+ return sorted;
113817
+ };
113818
+ const build = (limit2) => {
113819
+ kept = 0;
113820
+ total = 0;
113821
+ if (Array.isArray(data))
113822
+ return trimArray(data, limit2);
113823
+ if (isRecord5(data)) {
113824
+ const out = {};
113825
+ for (const [key, value] of Object.entries(data)) {
113826
+ if (RESERVED_KEYS.has(key))
113827
+ continue;
113828
+ out[key] = Array.isArray(value) ? trimArray(value, limit2) : value;
113829
+ }
113830
+ return out;
113831
+ }
113832
+ return data;
113833
+ };
113834
+ let limit = maxItems;
113835
+ let result = build(limit);
113836
+ let text = JSON.stringify(result) ?? "null";
113837
+ while (text.length > maxChars && limit > 1) {
113838
+ limit = Math.max(1, Math.floor(limit / 2));
113839
+ result = build(limit);
113840
+ text = JSON.stringify(result) ?? "null";
113841
+ }
113842
+ if (text.length > maxChars) {
113843
+ return {
113844
+ data: `${text.slice(0, maxChars)}...[truncated]`,
113845
+ kept,
113846
+ total,
113847
+ truncated: true
113848
+ };
113849
+ }
113850
+ return { data: result, kept, total, truncated: false };
113851
+ }
113852
+ var SYSTEM_PROMPT = [
113853
+ "You answer a question about a person using ONLY the user data provided in the message.",
113854
+ "Do not use outside knowledge and do not guess; if the data does not support an answer, say so in the answer.",
113855
+ "Respond with a single JSON object and nothing else, with exactly these fields:",
113856
+ ' "answer": string, the answer to the question, written for the person the data belongs to;',
113857
+ ' "evidence": string, a short summary of which parts of the data support the answer.'
113858
+ ].join("\n");
113859
+ function buildQuestionMessages(input) {
113860
+ const sections = input.sources.map((source) => {
113861
+ const note = source.total > source.kept ? ` (newest ${source.kept} of ${source.total} items)` : "";
113862
+ const cut = source.truncated ? " (truncated)" : "";
113863
+ return [
113864
+ `### Scope: ${source.scope}${note}${cut}`,
113865
+ `Collected at: ${source.collectedAt}`,
113866
+ JSON.stringify(source.data)
113867
+ ].join("\n");
113868
+ });
113869
+ const user = [
113870
+ "## Question",
113871
+ input.question,
113872
+ "",
113873
+ "## User data",
113874
+ ...sections,
113875
+ "",
113876
+ "Answer the question as a JSON object with the fields answer and evidence."
113877
+ ].join("\n");
113878
+ return [
113879
+ { role: "system", content: SYSTEM_PROMPT },
113880
+ { role: "user", content: user }
113881
+ ];
113882
+ }
113883
+ function parseAnswer(content) {
113884
+ const candidates = [content.trim()];
113885
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(content);
113886
+ if (fenced?.[1])
113887
+ candidates.unshift(fenced[1].trim());
113888
+ const first = content.indexOf("{");
113889
+ const last2 = content.lastIndexOf("}");
113890
+ if (first !== -1 && last2 > first) {
113891
+ candidates.push(content.slice(first, last2 + 1));
113892
+ }
113893
+ for (const candidate of candidates) {
113894
+ try {
113895
+ const parsed = JSON.parse(candidate);
113896
+ if (isRecord5(parsed) && typeof parsed.answer === "string") {
113897
+ return {
113898
+ answer: parsed.answer,
113899
+ evidence: typeof parsed.evidence === "string" ? parsed.evidence : null
113900
+ };
113901
+ }
113902
+ } catch {
113903
+ }
113904
+ }
113905
+ return { answer: content.trim(), evidence: null };
113906
+ }
113907
+
113908
+ // ../core/dist/derivatives/inference.js
113909
+ var DEFAULT_INFERENCE_BASE_URL = "https://inference.phala.com/v1";
113910
+ var DEFAULT_INFERENCE_MODEL = "z-ai/glm-5.2";
113911
+ var DEFAULT_INFERENCE_TIMEOUT_MS = 12e4;
113912
+ var DEFAULT_INFERENCE_MAX_TOKENS = 2048;
113913
+ var DEFAULT_INFERENCE_REQUEST_FIELDS = {
113914
+ provider: { aci_verified: true, zdr: true }
113915
+ };
113916
+ var InferenceRequestError = class extends Error {
113917
+ status;
113918
+ /** OpenAI-style `error.type` of the rejection, when the body had one. */
113919
+ errorType;
113920
+ /**
113921
+ * Explicit retry hint. When undefined the compute layer falls back to the
113922
+ * status: no response, 429 or 5xx are retried.
113923
+ */
113924
+ retryable;
113925
+ constructor(message, status2, options = {}) {
113926
+ super(message);
113927
+ this.status = status2;
113928
+ this.name = "InferenceRequestError";
113929
+ this.errorType = options.errorType ?? null;
113930
+ this.retryable = options.retryable;
113931
+ }
113932
+ };
113933
+ function isRecord6(value) {
113934
+ return value !== null && typeof value === "object" && !Array.isArray(value);
113935
+ }
113936
+ function readUsage(value) {
113937
+ if (!isRecord6(value))
113938
+ return void 0;
113939
+ const num2 = (v10) => typeof v10 === "number" ? v10 : void 0;
113940
+ const usage = {
113941
+ promptTokens: num2(value.prompt_tokens),
113942
+ completionTokens: num2(value.completion_tokens),
113943
+ totalTokens: num2(value.total_tokens)
113944
+ };
113945
+ return usage;
113946
+ }
113947
+ function readContent(body) {
113948
+ if (!isRecord6(body) || !Array.isArray(body.choices))
113949
+ return null;
113950
+ const first = body.choices[0];
113951
+ if (!isRecord6(first) || !isRecord6(first.message))
113952
+ return null;
113953
+ const index = typeof first.index === "number" ? first.index : 0;
113954
+ const field = `choices.${index}.message.content`;
113955
+ const id2 = typeof body.id === "string" ? body.id : "";
113956
+ const content = first.message.content;
113957
+ if (typeof content === "string")
113958
+ return { content, field, id: id2 };
113959
+ if (Array.isArray(content)) {
113960
+ const text = content.map((part) => isRecord6(part) && typeof part.text === "string" ? part.text : "").join("");
113961
+ return { content: text, field, id: id2 };
113962
+ }
113963
+ return null;
113964
+ }
113965
+ async function readErrorType(response) {
113966
+ try {
113967
+ const body = await response.json();
113968
+ if (isRecord6(body) && isRecord6(body.error)) {
113969
+ return typeof body.error.type === "string" ? body.error.type : null;
113970
+ }
113971
+ } catch {
113972
+ }
113973
+ return null;
113974
+ }
113975
+ function createOpenAiCompatibleInferenceProvider(options = {}) {
113976
+ const base = (options.baseUrl ?? DEFAULT_INFERENCE_BASE_URL).replace(/\/+$/, "");
113977
+ const defaultModel = options.model ?? DEFAULT_INFERENCE_MODEL;
113978
+ const timeoutMs = options.timeoutMs ?? DEFAULT_INFERENCE_TIMEOUT_MS;
113979
+ const doFetch = options.fetch ?? fetch;
113980
+ const requestFields = options.requestFields ?? DEFAULT_INFERENCE_REQUEST_FIELDS;
113981
+ const encryption = options.encryption;
113982
+ async function send(input) {
113983
+ const headers = new Headers({ "Content-Type": "application/json" });
113984
+ if (options.apiKey) {
113985
+ headers.set("Authorization", `Bearer ${options.apiKey}`);
113986
+ }
113987
+ const model = input.model || defaultModel;
113988
+ let messages = input.messages;
113989
+ let encrypted = null;
113990
+ if (encryption) {
113991
+ encrypted = await encryption.encryptRequest({
113992
+ model,
113993
+ messages,
113994
+ headers
113995
+ });
113996
+ messages = encrypted.messages;
113997
+ }
113998
+ const body = {
113999
+ ...requestFields,
114000
+ model,
114001
+ messages,
114002
+ max_tokens: input.maxTokens ?? DEFAULT_INFERENCE_MAX_TOKENS
114003
+ };
114004
+ let response;
114005
+ try {
114006
+ response = await doFetch(`${base}/chat/completions`, {
114007
+ method: "POST",
114008
+ headers,
114009
+ body: JSON.stringify(body),
114010
+ signal: AbortSignal.timeout(timeoutMs)
114011
+ });
114012
+ } catch (err2) {
114013
+ const name = err2 instanceof Error ? err2.name : "Error";
114014
+ throw new InferenceRequestError(`inference request failed before a response (${name})`, null);
114015
+ }
114016
+ if (!response.ok) {
114017
+ const errorType = await readErrorType(response);
114018
+ const retry = await encryption?.onRejected?.({
114019
+ status: response.status,
114020
+ errorType,
114021
+ headers: response.headers
114022
+ }) === true;
114023
+ return {
114024
+ ok: false,
114025
+ retry,
114026
+ error: new InferenceRequestError(`inference request failed with status ${response.status}${errorType ? ` (${errorType})` : ""}`, response.status, { errorType })
114027
+ };
114028
+ }
114029
+ let parsed;
114030
+ try {
114031
+ parsed = await response.json();
114032
+ } catch {
114033
+ throw new InferenceRequestError("inference response was not JSON", response.status);
114034
+ }
114035
+ const choice = readContent(parsed);
114036
+ if (choice === null) {
114037
+ throw new InferenceRequestError("inference response carried no assistant content", response.status);
114038
+ }
114039
+ let content = choice.content;
114040
+ if (encrypted) {
114041
+ content = await encrypted.decryptResponse({
114042
+ content,
114043
+ field: choice.field,
114044
+ id: choice.id,
114045
+ headers: response.headers
114046
+ });
114047
+ }
114048
+ if (content.trim() === "") {
114049
+ throw new InferenceRequestError("inference response carried no assistant content", response.status);
114050
+ }
114051
+ const receiptId = response.headers.get("x-receipt-id") ?? void 0;
114052
+ const aciIdentity = response.headers.get("x-aci-identity") ?? void 0;
114053
+ return {
114054
+ ok: true,
114055
+ result: {
114056
+ content,
114057
+ usage: readUsage(isRecord6(parsed) ? parsed.usage : void 0),
114058
+ ...receiptId ? { receiptId } : {},
114059
+ ...aciIdentity ? { aciIdentity } : {}
114060
+ }
114061
+ };
114062
+ }
114063
+ return {
114064
+ defaultModel,
114065
+ async chat(input) {
114066
+ const first = await send(input);
114067
+ if (first.ok)
114068
+ return first.result;
114069
+ if (!first.retry)
114070
+ throw first.error;
114071
+ const second = await send(input);
114072
+ if (second.ok)
114073
+ return second.result;
114074
+ throw second.error;
114075
+ }
114076
+ };
114077
+ }
114078
+
114079
+ // ../core/dist/derivatives/compute.js
114080
+ var DEFAULT_RETRY_DELAYS_MS = [1e3, 4e3];
114081
+ function isRetryableInferenceError(err2) {
114082
+ if (!(err2 instanceof InferenceRequestError))
114083
+ return false;
114084
+ if (err2.retryable !== void 0)
114085
+ return err2.retryable;
114086
+ return err2.status === null || err2.status === 429 || err2.status >= 500;
114087
+ }
114088
+ async function withRetries(deps, attempt, retryable) {
114089
+ const delays = deps.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
114090
+ const sleep2 = deps.sleep ?? ((ms3) => new Promise((r10) => setTimeout(r10, ms3)));
114091
+ for (let index = 0; ; index += 1) {
114092
+ try {
114093
+ return await attempt();
114094
+ } catch (err2) {
114095
+ if (index >= delays.length || !retryable(err2))
114096
+ throw err2;
114097
+ await sleep2(delays[index]);
114098
+ }
114099
+ }
114100
+ }
114101
+ var ComputeFailure = class extends Error {
114102
+ constructor(message) {
114103
+ super(message);
114104
+ this.name = "ComputeFailure";
114105
+ }
114106
+ };
114107
+ function shortError(err2) {
114108
+ if (err2 instanceof ComputeFailure)
114109
+ return err2.message;
114110
+ if (err2 instanceof InferenceRequestError)
114111
+ return err2.message;
114112
+ if (err2 instanceof ProtocolError)
114113
+ return `${err2.errorCode}: ${err2.message}`;
114114
+ return `compute failed (${err2 instanceof Error ? err2.name : "Error"})`;
114115
+ }
114116
+ function collectedAtStamp(now, isTaken) {
114117
+ const base = now();
114118
+ base.setUTCMilliseconds(0);
114119
+ for (let bump = 0; bump < 60; bump += 1) {
114120
+ const candidate = new Date(base.getTime() + bump * 1e3).toISOString().replace(/\.\d{3}Z$/, "Z");
114121
+ if (!isTaken(candidate))
114122
+ return candidate;
114123
+ }
114124
+ throw new ComputeFailure("could not allocate a version stamp");
114125
+ }
114126
+ async function tombstoneMarker(scopeDeletions, scope) {
114127
+ if (!scopeDeletions)
114128
+ return null;
114129
+ const verdict = await scopeDeletions.resolve(scope);
114130
+ if (!verdict.deleted || verdict.version === null)
114131
+ return null;
114132
+ const version4 = Number(verdict.version);
114133
+ return Number.isSafeInteger(version4) ? version4 : null;
114134
+ }
114135
+ function localScopesById2(storage, serverOwner) {
114136
+ const byId = /* @__PURE__ */ new Map();
114137
+ for (let offset = 0; ; offset += LOCAL_SCOPE_SCAN_PAGE) {
114138
+ const { scopes, total } = storage.listScopes({
114139
+ limit: LOCAL_SCOPE_SCAN_PAGE,
114140
+ offset
114141
+ });
114142
+ for (const summary of scopes) {
114143
+ byId.set(computeDataPointId(serverOwner, summary.scope), summary.scope);
114144
+ }
114145
+ if (scopes.length === 0 || offset + scopes.length >= total)
114146
+ break;
114147
+ }
114148
+ return byId;
114149
+ }
114150
+ async function assertNoLineageCycle(deps, registration, serverOwner, sourceLineage) {
114151
+ const derivedId = computeDataPointId(serverOwner, registration.derivedScope);
114152
+ let byId = null;
114153
+ const visited = /* @__PURE__ */ new Set();
114154
+ const stack = [];
114155
+ for (const [scope, sources] of sourceLineage) {
114156
+ for (const id2 of sources)
114157
+ stack.push({ id: id2, path: [scope] });
114158
+ }
114159
+ while (stack.length > 0) {
114160
+ const { id: id2, path } = stack.pop();
114161
+ if (id2 === derivedId) {
114162
+ throw new DerivativeCycleError({
114163
+ derivedScope: registration.derivedScope,
114164
+ path: [registration.derivedScope, ...path, registration.derivedScope]
114165
+ });
114166
+ }
114167
+ if (visited.has(id2))
114168
+ continue;
114169
+ visited.add(id2);
114170
+ byId ??= localScopesById2(deps.storage, serverOwner);
114171
+ const scope = byId.get(id2);
114172
+ if (!scope)
114173
+ continue;
114174
+ const entry = deps.storage.findEntry({ scope });
114175
+ if (!entry)
114176
+ continue;
114177
+ let sources = [];
114178
+ try {
114179
+ const envelope = await deps.storage.readEnvelope(scope, entry.collectedAt);
114180
+ sources = readStoredLineage(envelope.data)?.sources ?? [];
114181
+ } catch {
114182
+ }
114183
+ for (const next of sources)
114184
+ stack.push({ id: next, path: [...path, scope] });
114185
+ }
114186
+ }
114187
+ async function loadSource(deps, scope) {
114188
+ const entry = deps.storage.findEntry({ scope });
114189
+ const deletion = await resolveReadDeletion({ scopeDeletions: deps.scopeDeletions, serverOwner: deps.serverOwner }, scope, entry);
114190
+ if (deletion) {
114191
+ throw new ComputeFailure(`source scope ${scope} is deleted`);
114192
+ }
114193
+ if (!entry) {
114194
+ throw new ComputeFailure(`source scope ${scope} has no local data`);
114195
+ }
114196
+ let envelope;
114197
+ try {
114198
+ envelope = await deps.storage.readEnvelope(scope, entry.collectedAt);
114199
+ } catch {
114200
+ throw new ComputeFailure(`source scope ${scope} could not be read`);
114201
+ }
114202
+ let lineageSources = [];
114203
+ try {
114204
+ lineageSources = readStoredLineage(envelope.data)?.sources ?? [];
114205
+ } catch {
114206
+ }
114207
+ const raw = isBinaryEnvelope(envelope) ? {
114208
+ binary: true,
114209
+ note: "binary record; its content is not included in the prompt"
114210
+ } : envelope.data;
114211
+ const trimmed = trimSourceData(raw, {
114212
+ maxItems: deps.maxSourceItems,
114213
+ maxChars: deps.maxSourceChars
114214
+ });
114215
+ return {
114216
+ source: {
114217
+ scope,
114218
+ collectedAt: entry.collectedAt,
114219
+ version: entry.version,
114220
+ data: trimmed.data,
114221
+ kept: trimmed.kept,
114222
+ total: trimmed.total,
114223
+ truncated: trimmed.truncated
114224
+ },
114225
+ lineageSources
114226
+ };
114227
+ }
114228
+ async function assertGrantStillValid(deps, registration) {
114229
+ if (registration.registeredBy.kind !== "builder")
114230
+ return;
114231
+ if (!deps.writePolicyPorts) {
114232
+ throw new ComputeFailure("builder grant verification is not configured");
114233
+ }
114234
+ if (!deps.serverOwner) {
114235
+ throw new ComputeFailure("server owner is not configured");
114236
+ }
114237
+ const { builder, grantId } = registration.registeredBy;
114238
+ const ports = deps.writePolicyPorts;
114239
+ const serverOwner = deps.serverOwner;
114240
+ const grant = await withRetries(deps, () => verifyDataWritePolicy({
114241
+ signer: builder,
114242
+ grantId,
114243
+ requestedScope: registration.derivedScope,
114244
+ serverOwner
114245
+ }, ports), (err2) => !(err2 instanceof ProtocolError));
114246
+ const uncovered = uncoveredSourceScopes(registration.sourceScopes, grant.scopes ?? []);
114247
+ if (uncovered.length > 0) {
114248
+ throw new DerivativeSourceNotGrantedError({ scopes: uncovered });
114249
+ }
114250
+ }
114251
+ async function computeQuestion(questionId, deps) {
114252
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
114253
+ if (await deps.runtimeAvailability?.isAvailable() === false) {
114254
+ return { status: "skipped", reason: "runtime-unavailable" };
114255
+ }
114256
+ const registration = await deps.store.get(questionId);
114257
+ if (!registration)
114258
+ return { status: "skipped", reason: "unknown-question" };
114259
+ try {
114260
+ if (!deps.serverOwner) {
114261
+ throw new ComputeFailure("server owner is not configured");
114262
+ }
114263
+ const serverOwner = deps.serverOwner;
114264
+ await assertGrantStillValid(deps, registration);
114265
+ assertDerivedScopeNaming(registration.derivedScope, registration.sourceScopes);
114266
+ const sources = [];
114267
+ const sourceLineage = /* @__PURE__ */ new Map();
114268
+ for (const scope of registration.sourceScopes) {
114269
+ const loaded = await loadSource(deps, scope);
114270
+ sources.push(loaded.source);
114271
+ sourceLineage.set(scope, loaded.lineageSources);
114272
+ }
114273
+ await assertNoLineageCycle(deps, registration, serverOwner, sourceLineage);
114274
+ const messages = buildQuestionMessages({
114275
+ question: registration.question,
114276
+ sources
114277
+ });
114278
+ const model = registration.model ?? deps.provider.defaultModel;
114279
+ const reply = await withRetries(deps, () => deps.provider.chat({ model, messages, maxTokens: deps.maxTokens }), isRetryableInferenceError);
114280
+ const parsed = parseAnswer(reply.content);
114281
+ const computedAt = now().toISOString();
114282
+ const lineageIds = registration.sourceScopes.map((scope) => computeDataPointId(serverOwner, scope));
114283
+ const record2 = {
114284
+ questionId: registration.questionId,
114285
+ question: registration.question,
114286
+ answer: parsed.answer,
114287
+ evidence: parsed.evidence,
114288
+ model,
114289
+ computedAt,
114290
+ sources: sources.map((source) => ({
114291
+ scope: source.scope,
114292
+ version: source.version,
114293
+ collectedAt: source.collectedAt
114294
+ })),
114295
+ lineage: lineageIds,
114296
+ ...reply.receiptId || reply.aciIdentity ? {
114297
+ inference: {
114298
+ ...reply.receiptId ? { receiptId: reply.receiptId } : {},
114299
+ ...reply.aciIdentity ? { aciIdentity: reply.aciIdentity } : {}
114300
+ }
114301
+ } : {}
114302
+ };
114303
+ const lineage = {
114304
+ sources: lineageIds,
114305
+ writtenAt: computedAt
114306
+ };
114307
+ const collectedAt2 = collectedAtStamp(now, (candidate) => deps.storage.findEntry({
114308
+ scope: registration.derivedScope,
114309
+ at: candidate
114310
+ })?.collectedAt === candidate);
114311
+ const written = await ingestDataContract({
114312
+ storage: deps.storage,
114313
+ scopeParam: registration.derivedScope,
114314
+ body: record2,
114315
+ collectedAt: collectedAt2,
114316
+ status: deps.syncManager ? "syncing" : "stored",
114317
+ lineage,
114318
+ afterTombstoneVersion: await tombstoneMarker(deps.scopeDeletions, registration.derivedScope)
114319
+ });
114320
+ if (!written.ok) {
114321
+ throw new ComputeFailure(`derived record rejected: ${written.body.error}`);
114322
+ }
114323
+ const entry = deps.storage.findEntry({
114324
+ scope: registration.derivedScope,
114325
+ at: collectedAt2
114326
+ });
114327
+ const updated = await deps.store.update(questionId, {
114328
+ status: "ready",
114329
+ error: null,
114330
+ updatedAt: computedAt,
114331
+ lastComputedAt: computedAt,
114332
+ derivedVersion: entry?.version ?? null,
114333
+ derivedCollectedAt: collectedAt2
114334
+ });
114335
+ if (deps.syncManager?.notifyNewData) {
114336
+ deps.syncManager.notifyNewData();
114337
+ } else if (deps.syncManager?.trigger) {
114338
+ void deps.syncManager.trigger().catch(() => void 0);
114339
+ }
114340
+ try {
114341
+ deps.onDerivedWritten?.({
114342
+ scope: registration.derivedScope,
114343
+ collectedAt: collectedAt2,
114344
+ lineageSources: lineageIds
114345
+ });
114346
+ } catch (err2) {
114347
+ deps.logger?.warn?.({
114348
+ questionId,
114349
+ derivedScope: registration.derivedScope,
114350
+ error: err2 instanceof Error ? err2.name : String(err2)
114351
+ }, "onDerivedWritten hook failed; derivative already written");
114352
+ }
114353
+ deps.logger?.info?.({
114354
+ questionId,
114355
+ derivedScope: registration.derivedScope,
114356
+ sourceScopes: registration.sourceScopes,
114357
+ model,
114358
+ version: entry?.version ?? null,
114359
+ receiptId: reply.receiptId ?? null
114360
+ }, "Derivative question computed");
114361
+ return {
114362
+ status: "ready",
114363
+ registration: updated ?? { ...registration, status: "ready" }
114364
+ };
114365
+ } catch (err2) {
114366
+ const error51 = shortError(err2);
114367
+ const at3 = now().toISOString();
114368
+ const updated = await deps.store.update(questionId, {
114369
+ status: "failed",
114370
+ error: error51,
114371
+ updatedAt: at3
114372
+ });
114373
+ deps.logger?.warn?.({ questionId, derivedScope: registration.derivedScope, error: error51 }, "Derivative question compute failed");
114374
+ return {
114375
+ status: "failed",
114376
+ registration: updated ?? { ...registration, status: "failed", error: error51 },
114377
+ error: error51
114378
+ };
114379
+ }
114380
+ }
114381
+
114382
+ // ../core/dist/derivatives/scheduler.js
114383
+ var defaultTimers = {
114384
+ setTimeout: (callback, ms3) => setTimeout(callback, ms3),
114385
+ clearTimeout: (handle) => clearTimeout(handle)
114386
+ };
114387
+ function createRecomputeScheduler(options) {
114388
+ const debounceMs = options.debounceMs ?? 5e3;
114389
+ const timers = options.timers ?? defaultTimers;
114390
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
114391
+ const states = /* @__PURE__ */ new Map();
114392
+ const pending = /* @__PURE__ */ new Set();
114393
+ let stopped = false;
114394
+ function track(promise2) {
114395
+ pending.add(promise2);
114396
+ const done = () => pending.delete(promise2);
114397
+ promise2.then(done, done);
114398
+ return promise2;
114399
+ }
114400
+ function warn(payload, message) {
114401
+ options.logger?.warn?.(payload, message);
114402
+ }
114403
+ function stateFor(questionId) {
114404
+ let state = states.get(questionId);
114405
+ if (!state) {
114406
+ state = { timer: null, running: null, rerun: false };
114407
+ states.set(questionId, state);
114408
+ }
114409
+ return state;
114410
+ }
114411
+ function run(questionId) {
114412
+ if (stopped)
114413
+ return;
114414
+ const state = stateFor(questionId);
114415
+ if (state.running) {
114416
+ state.rerun = true;
114417
+ return;
114418
+ }
114419
+ state.running = track(Promise.resolve().then(() => options.compute(questionId)).then(() => void 0, (err2) => warn({
114420
+ questionId,
114421
+ error: err2 instanceof Error ? err2.name : String(err2)
114422
+ }, "Derivative compute threw")).then(async () => {
114423
+ state.running = null;
114424
+ if (state.rerun) {
114425
+ state.rerun = false;
114426
+ await markStale(questionId);
114427
+ schedule(questionId, 0);
114428
+ } else if (!states.get(questionId)?.timer) {
114429
+ states.delete(questionId);
114430
+ }
114431
+ }));
114432
+ }
114433
+ function schedule(questionId, delayMs) {
114434
+ if (stopped)
114435
+ return;
114436
+ const state = stateFor(questionId);
114437
+ if (state.timer !== null)
114438
+ timers.clearTimeout(state.timer);
114439
+ state.timer = timers.setTimeout(() => {
114440
+ state.timer = null;
114441
+ run(questionId);
114442
+ }, delayMs);
114443
+ }
114444
+ async function markStale(questionId) {
114445
+ const registration = await options.store.get(questionId);
114446
+ if (!registration)
114447
+ return;
114448
+ if (registration.status === "ready" || registration.status === "failed") {
114449
+ await options.store.update(questionId, {
114450
+ status: "stale",
114451
+ updatedAt: now().toISOString()
114452
+ });
114453
+ }
114454
+ }
114455
+ return {
114456
+ markSourceChanged(scope, opts) {
114457
+ if (stopped)
114458
+ return;
114459
+ const lineage = new Set((opts?.lineageSources ?? []).map((id2) => id2.toLowerCase()));
114460
+ void track((async () => {
114461
+ const affected = await options.store.list({ sourceScope: scope });
114462
+ for (const registration of affected) {
114463
+ if (options.serverOwner && lineage.has(computeDataPointId(options.serverOwner, registration.derivedScope))) {
114464
+ continue;
114465
+ }
114466
+ await markStale(registration.questionId);
114467
+ schedule(registration.questionId, debounceMs);
114468
+ }
114469
+ })().catch((err2) => warn({ scope, error: err2 instanceof Error ? err2.name : String(err2) }, "Could not mark derivative questions stale")));
114470
+ },
114471
+ requestRecompute(questionId, opts) {
114472
+ if (stopped)
114473
+ return;
114474
+ void track(markStale(questionId).catch((err2) => warn({
114475
+ questionId,
114476
+ error: err2 instanceof Error ? err2.name : String(err2)
114477
+ }, "Could not mark derivative question stale")).then(() => schedule(questionId, opts?.immediate ? 0 : debounceMs)));
114478
+ },
114479
+ async whenIdle() {
114480
+ const waitForTimers = !options.timers;
114481
+ for (; ; ) {
114482
+ while (pending.size > 0) {
114483
+ await Promise.allSettled([...pending]);
114484
+ }
114485
+ const busy = [...states.values()].some((state) => state.running !== null || waitForTimers && state.timer !== null);
114486
+ if (!busy)
114487
+ return;
114488
+ await new Promise((resolve) => setTimeout(resolve, 5));
114489
+ }
114490
+ },
114491
+ stop() {
114492
+ stopped = true;
114493
+ for (const state of states.values()) {
114494
+ if (state.timer !== null)
114495
+ timers.clearTimeout(state.timer);
114496
+ state.timer = null;
114497
+ }
114498
+ },
114499
+ start() {
114500
+ if (!stopped)
114501
+ return;
114502
+ stopped = false;
114503
+ void track((async () => {
114504
+ for (const registration of await options.store.list()) {
114505
+ if (registration.status === "pending" || registration.status === "stale") {
114506
+ schedule(registration.questionId, 0);
114507
+ }
114508
+ }
114509
+ })().catch((err2) => warn({ error: err2 instanceof Error ? err2.name : String(err2) }, "Could not reschedule derivative questions")));
114510
+ }
114511
+ };
114512
+ }
114513
+
114514
+ // ../core/dist/derivatives/api.js
114515
+ var MAX_QUESTION_BODY_BYTES = 16 * 1024;
114516
+ function jsonResponse2(body, init) {
114517
+ const headers = new Headers(init?.headers);
114518
+ headers.set("Content-Type", "application/json");
114519
+ return new Response(JSON.stringify(body), { ...init, headers });
114520
+ }
114521
+ function errorResponse2(status2, errorCode, message) {
114522
+ return jsonResponse2({ error: { code: status2, errorCode, message } }, { status: status2 });
114523
+ }
114524
+ function stripBasePath2(pathname, basePath) {
114525
+ if (!basePath || basePath === "/")
114526
+ return pathname;
114527
+ if (pathname === basePath)
114528
+ return "/";
114529
+ if (pathname.startsWith(`${basePath}/`))
114530
+ return pathname.slice(basePath.length);
114531
+ return pathname;
114532
+ }
114533
+ async function authorizeOwnerOrWriter(deps, request2, scope) {
114534
+ if (deps.auth.authorizeWrite) {
114535
+ return await deps.auth.authorizeWrite({ request: request2, scope }) ?? void 0;
114536
+ }
114537
+ await deps.auth.authorizeOwner(request2);
114538
+ return void 0;
114539
+ }
114540
+ function sameBuilder(a10, b10) {
114541
+ return a10.toLowerCase() === b10.toLowerCase();
114542
+ }
114543
+ async function loadForCaller(deps, request2, store, questionId) {
114544
+ const registration = await store.get(questionId);
114545
+ if (!registration) {
114546
+ await deps.auth.authorizeOwner(request2);
114547
+ throw new DerivativeQuestionNotFoundError({ questionId });
114548
+ }
114549
+ const writer = await authorizeOwnerOrWriter(deps, request2, registration.derivedScope);
114550
+ if (writer) {
114551
+ const by2 = registration.registeredBy;
114552
+ if (by2.kind !== "builder" || !sameBuilder(by2.builder, writer.builder)) {
114553
+ await writer.releaseProof?.();
114554
+ throw new DerivativeQuestionNotFoundError({ questionId });
114555
+ }
114556
+ }
114557
+ return { registration, writer };
114558
+ }
114559
+ async function handlePersonalServerDerivativesRequest(request2, deps, options = {}) {
114560
+ try {
114561
+ const url2 = new URL(request2.url);
114562
+ const pathname = stripBasePath2(url2.pathname, options.basePath);
114563
+ const parts = pathname.split("/").filter(Boolean);
114564
+ if (parts[0] !== "questions" || parts.length > 3) {
114565
+ return errorResponse2(404, "NOT_FOUND", "Not found");
114566
+ }
114567
+ const compute = deps.compute;
114568
+ if (!compute)
114569
+ throw new DerivativeComputeUnavailableError();
114570
+ const { store, scheduler } = compute;
114571
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
114572
+ if (parts.length === 1) {
114573
+ if (request2.method === "GET") {
114574
+ const derivedScope = url2.searchParams.get("derivedScope") ?? void 0;
114575
+ if (derivedScope) {
114576
+ const writer = await authorizeOwnerOrWriter(deps, request2, derivedScope);
114577
+ const registrations2 = await store.list({
114578
+ derivedScope,
114579
+ ...writer ? { builder: writer.builder } : {}
114580
+ });
114581
+ return jsonResponse2({
114582
+ questions: registrations2.map(questionRegistrationView)
114583
+ });
114584
+ }
114585
+ await deps.auth.authorizeOwner(request2);
114586
+ const registrations = await store.list();
114587
+ return jsonResponse2({
114588
+ questions: registrations.map(questionRegistrationView)
114589
+ });
114590
+ }
114591
+ if (request2.method === "POST") {
114592
+ const declared = Number(request2.headers.get("content-length") ?? "0");
114593
+ if (declared > MAX_QUESTION_BODY_BYTES) {
114594
+ throw new ContentTooLargeError({ max: MAX_QUESTION_BODY_BYTES });
114595
+ }
114596
+ const bodyBytes = new Uint8Array(await request2.clone().arrayBuffer());
114597
+ if (bodyBytes.byteLength > MAX_QUESTION_BODY_BYTES) {
114598
+ throw new ContentTooLargeError({ max: MAX_QUESTION_BODY_BYTES });
114599
+ }
114600
+ const parsed = await parseJsonObjectBody(request2.clone(), "Request body must be valid JSON");
114601
+ if (!parsed.ok) {
114602
+ return jsonResponse2(parsed.result.body, {
114603
+ status: parsed.result.status
114604
+ });
114605
+ }
114606
+ const rawScope = parsed.body.derivedScope;
114607
+ const scopeForAuth = typeof rawScope === "string" ? rawScope : "";
114608
+ const writer = await authorizeOwnerOrWriter(deps, request2, scopeForAuth);
114609
+ const registeredBy = writer ? {
114610
+ kind: "builder",
114611
+ builder: writer.builder,
114612
+ grantId: writer.grantId
114613
+ } : { kind: "owner" };
114614
+ let registration;
114615
+ try {
114616
+ if (writer) {
114617
+ const input = parseQuestionInput(parsed.body);
114618
+ const uncovered = uncoveredSourceScopes(input.sourceScopes, writer.grantScopes);
114619
+ if (uncovered.length > 0) {
114620
+ throw new DerivativeSourceNotGrantedError({ scopes: uncovered });
114621
+ }
114622
+ }
114623
+ registration = await createQuestionRegistration({
114624
+ body: parsed.body,
114625
+ registeredBy,
114626
+ store,
114627
+ questionId: deps.createQuestionId?.() ?? crypto.randomUUID(),
114628
+ now
114629
+ });
114630
+ } catch (err2) {
114631
+ await writer?.releaseProof?.();
114632
+ throw err2;
114633
+ }
114634
+ deps.logger?.info?.({
114635
+ questionId: registration.questionId,
114636
+ derivedScope: registration.derivedScope,
114637
+ sourceScopes: registration.sourceScopes,
114638
+ registeredBy: registeredBy.kind,
114639
+ ...writer ? { builder: writer.builder, grantId: writer.grantId } : {}
114640
+ }, "Derivative question registered");
114641
+ scheduler.requestRecompute(registration.questionId, {
114642
+ immediate: true
114643
+ });
114644
+ return jsonResponse2(questionRegistrationView(registration), {
114645
+ status: 201
114646
+ });
114647
+ }
114648
+ return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
114649
+ }
114650
+ const questionId = decodeURIComponent(parts[1] ?? "");
114651
+ if (parts.length === 3) {
114652
+ if (parts[2] !== "recompute") {
114653
+ return errorResponse2(404, "NOT_FOUND", "Not found");
114654
+ }
114655
+ if (request2.method !== "POST") {
114656
+ return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
114657
+ }
114658
+ const { registration } = await loadForCaller(deps, request2, store, questionId);
114659
+ scheduler.requestRecompute(questionId, { immediate: true });
114660
+ return jsonResponse2({
114661
+ questionId,
114662
+ status: registration.status === "pending" ? "pending" : "stale",
114663
+ derivedScope: registration.derivedScope
114664
+ }, { status: 202 });
114665
+ }
114666
+ if (request2.method === "GET") {
114667
+ const { registration } = await loadForCaller(deps, request2, store, questionId);
114668
+ return jsonResponse2(questionRegistrationView(registration));
114669
+ }
114670
+ if (request2.method === "DELETE") {
114671
+ const { registration } = await loadForCaller(deps, request2, store, questionId);
114672
+ await store.delete(questionId);
114673
+ deps.logger?.info?.({ questionId, derivedScope: registration.derivedScope }, "Derivative question deleted");
114674
+ return jsonResponse2({ questionId, deleted: true });
114675
+ }
114676
+ return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
114677
+ } catch (err2) {
114678
+ if (err2 instanceof ProtocolError) {
114679
+ return jsonResponse2(err2.toJSON(), { status: err2.code });
114680
+ }
114681
+ return errorResponse2(500, "INTERNAL_ERROR", "Internal server error");
114682
+ }
114683
+ }
114684
+
114685
+ // ../core/dist/derivatives/e2ee/jcs.js
114686
+ function canonicalizeJson(value) {
114687
+ if (value === null)
114688
+ return "null";
114689
+ switch (typeof value) {
114690
+ case "boolean":
114691
+ return value ? "true" : "false";
114692
+ case "number":
114693
+ if (!Number.isFinite(value)) {
114694
+ throw new TypeError("JCS: non-finite number");
114695
+ }
114696
+ return JSON.stringify(value);
114697
+ case "string":
114698
+ return JSON.stringify(value);
114699
+ case "object": {
114700
+ if (Array.isArray(value)) {
114701
+ return `[${value.map((item) => canonicalizeJson(item)).join(",")}]`;
114702
+ }
114703
+ const record2 = value;
114704
+ const keys = Object.keys(record2).sort();
114705
+ const members = [];
114706
+ for (const key of keys) {
114707
+ const member = record2[key];
114708
+ if (member === void 0) {
114709
+ throw new TypeError(`JCS: undefined member "${key}"`);
114710
+ }
114711
+ members.push(`${JSON.stringify(key)}:${canonicalizeJson(member)}`);
114712
+ }
114713
+ return `{${members.join(",")}}`;
114714
+ }
114715
+ default:
114716
+ throw new TypeError(`JCS: unsupported value of type ${typeof value}`);
114717
+ }
114718
+ }
114719
+ var encoder3 = new TextEncoder();
114720
+ function canonicalJsonBytes(value) {
114721
+ return encoder3.encode(canonicalizeJson(value));
114722
+ }
114723
+
114724
+ // ../core/dist/derivatives/e2ee/aad.js
114725
+ var E2EE_REQUEST_AAD_PURPOSE = "aci.e2ee.request.v2";
114726
+ var E2EE_RESPONSE_AAD_PURPOSE = "aci.e2ee.response.v2";
114727
+ function requestFieldAad(context, field) {
114728
+ return canonicalJsonBytes({
114729
+ purpose: E2EE_REQUEST_AAD_PURPOSE,
114730
+ algo: context.algo,
114731
+ model: context.model,
114732
+ field,
114733
+ nonce: context.nonce,
114734
+ ts: context.ts
114735
+ });
114736
+ }
114737
+ function responseFieldAad(context, field, id2) {
114738
+ return canonicalJsonBytes({
114739
+ purpose: E2EE_RESPONSE_AAD_PURPOSE,
114740
+ algo: context.algo,
114741
+ model: context.model,
114742
+ id: id2,
114743
+ field,
114744
+ nonce: context.nonce,
114745
+ ts: context.ts
114746
+ });
114747
+ }
114748
+
114749
+ // ../core/dist/derivatives/e2ee/suite.js
114750
+ var E2EE_ALGO_X25519 = "x25519-aes-256-gcm-hkdf-sha256";
114751
+ var E2EE_HKDF_INFO_X25519 = "aci.e2ee.v2.x25519";
114752
+ var X25519_PUBLIC_KEY_BYTES = 32;
114753
+ var AES_GCM_NONCE_BYTES = 12;
114754
+ var AES_GCM_TAG_BYTES = 16;
114755
+ var E2eeCipherError = class extends Error {
114756
+ constructor(message) {
114757
+ super(message);
114758
+ this.name = "E2eeCipherError";
114759
+ }
114760
+ };
114761
+ function subtle() {
114762
+ const api = globalThis.crypto?.subtle;
114763
+ if (!api)
114764
+ throw new E2eeCipherError("WebCrypto is not available");
114765
+ return api;
114766
+ }
114767
+ function randomBytes4(length) {
114768
+ const bytes2 = new Uint8Array(length);
114769
+ globalThis.crypto.getRandomValues(bytes2);
114770
+ return bytes2;
114771
+ }
114772
+ function bytesToHex6(bytes2) {
114773
+ let out = "";
114774
+ for (const byte of bytes2)
114775
+ out += byte.toString(16).padStart(2, "0");
114776
+ return out;
114777
+ }
114778
+ function hexToBytes4(hex3) {
114779
+ const clean2 = hex3.startsWith("0x") || hex3.startsWith("0X") ? hex3.slice(2) : hex3;
114780
+ if (clean2.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(clean2)) {
114781
+ throw new E2eeCipherError("malformed hex");
114782
+ }
114783
+ const out = new Uint8Array(clean2.length / 2);
114784
+ for (let i10 = 0; i10 < out.length; i10 += 1) {
114785
+ out[i10] = parseInt(clean2.slice(i10 * 2, i10 * 2 + 2), 16);
114786
+ }
114787
+ return out;
114788
+ }
114789
+ function parseX25519PublicKey(hex3) {
114790
+ const bytes2 = hexToBytes4(hex3);
114791
+ if (bytes2.length !== X25519_PUBLIC_KEY_BYTES) {
114792
+ throw new E2eeCipherError("X25519 public key must be 32 bytes");
114793
+ }
114794
+ return bytes2;
114795
+ }
114796
+ function concat2(...parts) {
114797
+ const total = parts.reduce((sum, part) => sum + part.length, 0);
114798
+ const out = new Uint8Array(total);
114799
+ let offset = 0;
114800
+ for (const part of parts) {
114801
+ out.set(part, offset);
114802
+ offset += part.length;
114803
+ }
114804
+ return out;
114805
+ }
114806
+ function toBuffer(bytes2) {
114807
+ const out = new ArrayBuffer(bytes2.byteLength);
114808
+ new Uint8Array(out).set(bytes2);
114809
+ return out;
114810
+ }
114811
+ async function generateX25519KeyPair() {
114812
+ const pair = await subtle().generateKey({ name: "X25519" }, false, [
114813
+ "deriveBits"
114814
+ ]);
114815
+ const raw = await subtle().exportKey("raw", pair.publicKey);
114816
+ return { privateKey: pair.privateKey, publicKey: new Uint8Array(raw) };
114817
+ }
114818
+ async function deriveFieldKey(privateKey, peerPublicKey, usage) {
114819
+ const api = subtle();
114820
+ const peer = await api.importKey("raw", toBuffer(peerPublicKey), { name: "X25519" }, false, []);
114821
+ const shared = await api.deriveBits({ name: "X25519", public: peer }, privateKey, X25519_PUBLIC_KEY_BYTES * 8);
114822
+ const ikm = await api.importKey("raw", shared, "HKDF", false, ["deriveKey"]);
114823
+ return api.deriveKey({
114824
+ name: "HKDF",
114825
+ hash: "SHA-256",
114826
+ salt: new Uint8Array(0),
114827
+ info: new TextEncoder().encode(E2EE_HKDF_INFO_X25519)
114828
+ }, ikm, { name: "AES-GCM", length: 256 }, false, [usage]);
114829
+ }
114830
+ async function encryptField(input) {
114831
+ const ephemeral = input.ephemeral ?? await generateX25519KeyPair();
114832
+ const nonce = input.nonce ?? randomBytes4(AES_GCM_NONCE_BYTES);
114833
+ if (nonce.length !== AES_GCM_NONCE_BYTES) {
114834
+ throw new E2eeCipherError("AES-GCM nonce must be 12 bytes");
114835
+ }
114836
+ const key = await deriveFieldKey(ephemeral.privateKey, input.recipientPublicKey, "encrypt");
114837
+ const sealed = await subtle().encrypt({
114838
+ name: "AES-GCM",
114839
+ iv: toBuffer(nonce),
114840
+ additionalData: toBuffer(input.aad),
114841
+ tagLength: AES_GCM_TAG_BYTES * 8
114842
+ }, key, new TextEncoder().encode(input.plaintext));
114843
+ return bytesToHex6(concat2(ephemeral.publicKey, nonce, new Uint8Array(sealed)));
114844
+ }
114845
+ async function decryptField(input) {
114846
+ let bytes2;
114847
+ try {
114848
+ bytes2 = hexToBytes4(input.wire);
114849
+ } catch {
114850
+ throw new E2eeCipherError("ciphertext is not hex");
114851
+ }
114852
+ const minimum = X25519_PUBLIC_KEY_BYTES + AES_GCM_NONCE_BYTES + AES_GCM_TAG_BYTES;
114853
+ if (bytes2.length < minimum) {
114854
+ throw new E2eeCipherError("ciphertext is too short");
114855
+ }
114856
+ const ephemeralPublicKey = bytes2.subarray(0, X25519_PUBLIC_KEY_BYTES);
114857
+ const nonce = bytes2.subarray(X25519_PUBLIC_KEY_BYTES, X25519_PUBLIC_KEY_BYTES + AES_GCM_NONCE_BYTES);
114858
+ const sealed = bytes2.subarray(X25519_PUBLIC_KEY_BYTES + AES_GCM_NONCE_BYTES);
114859
+ let key;
114860
+ try {
114861
+ key = await deriveFieldKey(input.privateKey, ephemeralPublicKey, "decrypt");
114862
+ } catch {
114863
+ throw new E2eeCipherError("key agreement failed");
114864
+ }
114865
+ let opened;
114866
+ try {
114867
+ opened = await subtle().decrypt({
114868
+ name: "AES-GCM",
114869
+ iv: toBuffer(nonce),
114870
+ additionalData: toBuffer(input.aad),
114871
+ tagLength: AES_GCM_TAG_BYTES * 8
114872
+ }, key, toBuffer(sealed));
114873
+ } catch {
114874
+ throw new E2eeCipherError("authentication failed");
114875
+ }
114876
+ return new TextDecoder().decode(opened);
114877
+ }
114878
+
114879
+ // ../core/dist/derivatives/e2ee/attestation.js
114880
+ var ACI_API_VERSION = "aci/1";
114881
+ var ACI_REPORT_DATA_PURPOSE = "aci.report_data.v1";
114882
+ var E2EE_VERSION = "2";
114883
+ var PHALA_GATEWAY_BASE_URL = "https://inference.phala.com/v1";
114884
+ var MAX_KEYSET_LIFETIME_S = 400 * 24 * 3600;
114885
+ var DEFAULT_FETCH_TIMEOUT_MS = 15e3;
114886
+ var E2eeAttestationError = class extends Error {
114887
+ code;
114888
+ constructor(code, message) {
114889
+ super(message);
114890
+ this.code = code;
114891
+ this.name = "E2eeAttestationError";
114892
+ }
114893
+ };
114894
+ function isRecord7(value) {
114895
+ return value !== null && typeof value === "object" && !Array.isArray(value);
114896
+ }
114897
+ async function sha256Hex2(bytes2) {
114898
+ const buffer = new ArrayBuffer(bytes2.byteLength);
114899
+ new Uint8Array(buffer).set(bytes2);
114900
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", buffer);
114901
+ return bytesToHex6(new Uint8Array(digest));
114902
+ }
114903
+ async function workloadKeysetDigest(keyset) {
114904
+ return `sha256:${await sha256Hex2(canonicalJsonBytes(keyset))}`;
114905
+ }
114906
+ async function reportDataFor(keysetDigest, nonce) {
114907
+ const nonceJson = nonce === null ? "null" : `"${nonce}"`;
114908
+ const statement = `{"keyset_digest":"${keysetDigest}","nonce":${nonceJson},"purpose":"${ACI_REPORT_DATA_PURPOSE}"}`;
114909
+ return sha256Hex2(new TextEncoder().encode(statement));
114910
+ }
114911
+ function parseReport(body) {
114912
+ if (!isRecord7(body) || typeof body.api_version !== "string" || typeof body.workload_keyset_digest !== "string" || !isRecord7(body.attestation) || typeof body.attestation.tee_type !== "string" || typeof body.attestation.report_data !== "string" || !isRecord7(body.attestation.workload_keyset)) {
114913
+ throw new E2eeAttestationError("malformed_report", "attestation report is missing required fields");
114914
+ }
114915
+ const keyset = body.attestation.workload_keyset;
114916
+ if (typeof keyset.not_after !== "number" || !Array.isArray(keyset.e2ee_public_keys)) {
114917
+ throw new E2eeAttestationError("malformed_report", "workload keyset is missing not_after or e2ee_public_keys");
114918
+ }
114919
+ return body;
114920
+ }
114921
+ async function verifyAciReportBinding(report, nonce, nowSeconds) {
114922
+ if (report.api_version !== ACI_API_VERSION) {
114923
+ throw new E2eeAttestationError("malformed_report", `unsupported attestation api_version ${report.api_version}`);
114924
+ }
114925
+ if (report.attestation.tee_type !== "tdx") {
114926
+ throw new E2eeAttestationError("malformed_report", `unsupported tee_type ${report.attestation.tee_type}`);
114927
+ }
114928
+ const versions = report.service_capabilities?.supported_e2ee_versions;
114929
+ if (!Array.isArray(versions) || !versions.includes(E2EE_VERSION)) {
114930
+ throw new E2eeAttestationError("e2ee_unsupported", "service does not advertise E2EE version 2");
114931
+ }
114932
+ const keyset = report.attestation.workload_keyset;
114933
+ const digest = await workloadKeysetDigest(keyset);
114934
+ if (digest !== report.workload_keyset_digest) {
114935
+ throw new E2eeAttestationError("keyset_digest_mismatch", "workload_keyset_digest does not match the embedded keyset");
114936
+ }
114937
+ const expectedReportData = await reportDataFor(digest, nonce);
114938
+ const reportData = report.attestation.report_data.toLowerCase();
114939
+ if (reportData !== expectedReportData) {
114940
+ throw new E2eeAttestationError("report_data_mismatch", "report_data does not bind the keyset digest and our nonce");
114941
+ }
114942
+ const quoteReportData = report.attestation.evidence?.quote_report_data;
114943
+ if (typeof quoteReportData === "string") {
114944
+ const slot = quoteReportData.toLowerCase();
114945
+ if (slot.length !== 128 || !slot.startsWith(reportData) || !/^0+$/.test(slot.slice(64))) {
114946
+ throw new E2eeAttestationError("report_data_mismatch", "quote report-data slot does not carry report_data zero-padded");
114947
+ }
114948
+ }
114949
+ if (!(nowSeconds < keyset.not_after)) {
114950
+ throw new E2eeAttestationError("keyset_expired", "workload keyset has expired");
114951
+ }
114952
+ if (keyset.not_after - nowSeconds > MAX_KEYSET_LIFETIME_S) {
114953
+ throw new E2eeAttestationError("keyset_expired", "workload keyset not_after is implausibly far in the future");
114954
+ }
114955
+ return digest;
114956
+ }
114957
+ function selectX25519Key(keyset, expectedKeyId) {
114958
+ for (const entry of keyset.e2ee_public_keys) {
114959
+ if (!isRecord7(entry) || entry.algo !== E2EE_ALGO_X25519)
114960
+ continue;
114961
+ if (typeof entry.public_key !== "string")
114962
+ continue;
114963
+ if (expectedKeyId !== void 0 && entry.key_id !== expectedKeyId) {
114964
+ continue;
114965
+ }
114966
+ let publicKey;
114967
+ try {
114968
+ publicKey = parseX25519PublicKey(entry.public_key);
114969
+ } catch {
114970
+ throw new E2eeAttestationError("no_e2ee_key", "the X25519 E2EE key in the keyset is malformed");
114971
+ }
114972
+ return { entry, publicKey };
114973
+ }
114974
+ throw new E2eeAttestationError("no_e2ee_key", expectedKeyId ? `keyset has no ${E2EE_ALGO_X25519} key with key_id ${expectedKeyId}` : `keyset has no ${E2EE_ALGO_X25519} key`);
114975
+ }
114976
+ function attestationUrl(baseUrl, nonce) {
114977
+ return `${baseUrl.replace(/\/+$/, "")}/aci/attestation?nonce=${nonce}`;
114978
+ }
114979
+ async function fetchReport(doFetch, url2, timeoutMs) {
114980
+ let response;
114981
+ try {
114982
+ response = await doFetch(url2, {
114983
+ method: "GET",
114984
+ headers: { Accept: "application/json" },
114985
+ signal: AbortSignal.timeout(timeoutMs)
114986
+ });
114987
+ } catch (err2) {
114988
+ const name = err2 instanceof Error ? err2.name : "Error";
114989
+ throw new E2eeAttestationError("fetch_failed", `attestation fetch failed before a response (${name})`);
114990
+ }
114991
+ if (!response.ok) {
114992
+ return { status: response.status, body: null };
114993
+ }
114994
+ try {
114995
+ return { status: response.status, body: await response.json() };
114996
+ } catch {
114997
+ throw new E2eeAttestationError("malformed_report", "attestation response was not JSON");
114998
+ }
114999
+ }
115000
+ async function fetchGatewayE2eeKey(options) {
115001
+ const doFetch = options.fetch ?? fetch;
115002
+ const clock = options.clock ?? Date.now;
115003
+ const random = options.random ?? randomBytes4;
115004
+ const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
115005
+ const nonce = bytesToHex6(random(32));
115006
+ const fallback = options.fallbackBaseUrl === void 0 ? PHALA_GATEWAY_BASE_URL : options.fallbackBaseUrl;
115007
+ let source = options.baseUrl;
115008
+ let fetched = await fetchReport(doFetch, attestationUrl(source, nonce), timeoutMs);
115009
+ if ((fetched.status === 404 || fetched.status === 405) && fallback !== null && fallback.replace(/\/+$/, "") !== source.replace(/\/+$/, "")) {
115010
+ source = fallback;
115011
+ fetched = await fetchReport(doFetch, attestationUrl(source, nonce), timeoutMs);
115012
+ }
115013
+ if (fetched.body === null) {
115014
+ throw new E2eeAttestationError("fetch_failed", `attestation fetch failed with status ${fetched.status}`);
115015
+ }
115016
+ const report = parseReport(fetched.body);
115017
+ const nowSeconds = Math.floor(clock() / 1e3);
115018
+ const keysetDigest = await verifyAciReportBinding(report, nonce, nowSeconds);
115019
+ const { entry, publicKey } = selectX25519Key(report.attestation.workload_keyset, options.expectedKeyId);
115020
+ if (options.verifyEvidence) {
115021
+ try {
115022
+ await options.verifyEvidence(report);
115023
+ } catch (err2) {
115024
+ const reason = err2 instanceof Error ? err2.message : String(err2);
115025
+ throw new E2eeAttestationError("evidence_rejected", `attestation evidence rejected: ${reason}`);
115026
+ }
115027
+ }
115028
+ return {
115029
+ algo: entry.algo,
115030
+ keyId: entry.key_id,
115031
+ publicKey,
115032
+ publicKeyHex: entry.public_key,
115033
+ keysetDigest,
115034
+ notAfter: report.attestation.workload_keyset.not_after,
115035
+ source,
115036
+ report
115037
+ };
115038
+ }
115039
+
115040
+ // ../core/dist/derivatives/e2ee/phala.js
115041
+ var E2EE_HEADER_VERSION = "X-E2EE-Version";
115042
+ var E2EE_HEADER_CLIENT_PUB_KEY = "X-Client-Pub-Key";
115043
+ var E2EE_HEADER_MODEL_PUB_KEY = "X-Model-Pub-Key";
115044
+ var E2EE_HEADER_NONCE = "X-E2EE-Nonce";
115045
+ var E2EE_HEADER_TIMESTAMP = "X-E2EE-Timestamp";
115046
+ var ACI_HEADER_KEYSET_DIGEST = "X-ACI-Keyset-Digest";
115047
+ var DEFAULT_E2EE_KEY_TTL_MS = 5 * 6e4;
115048
+ function keyFetchError(err2) {
115049
+ if (err2 instanceof E2eeAttestationError) {
115050
+ return new InferenceRequestError(`e2ee key fetch failed (${err2.code}): ${err2.message}`, null, {
115051
+ errorType: `e2ee_attestation_${err2.code}`,
115052
+ retryable: err2.code === "fetch_failed"
115053
+ });
115054
+ }
115055
+ const name = err2 instanceof Error ? err2.name : "Error";
115056
+ return new InferenceRequestError(`e2ee key fetch failed (${name})`, null, {
115057
+ retryable: false
115058
+ });
115059
+ }
115060
+ function createPhalaE2eeEncryption(options) {
115061
+ const clock = options.clock ?? Date.now;
115062
+ const ttlMs = options.keyTtlMs ?? DEFAULT_E2EE_KEY_TTL_MS;
115063
+ let cached2 = null;
115064
+ let inFlight = null;
115065
+ const fetchKey = async () => {
115066
+ const key = await fetchGatewayE2eeKey({
115067
+ baseUrl: options.baseUrl,
115068
+ fetch: options.fetch,
115069
+ clock,
115070
+ expectedKeyId: options.expectedKeyId,
115071
+ verifyEvidence: options.verifyEvidence,
115072
+ fallbackBaseUrl: options.fallbackAttestationBaseUrl
115073
+ });
115074
+ options.logger?.info?.({
115075
+ keyId: key.keyId,
115076
+ algo: key.algo,
115077
+ keysetDigest: key.keysetDigest,
115078
+ notAfter: key.notAfter,
115079
+ source: key.source,
115080
+ evidenceVerified: Boolean(options.verifyEvidence)
115081
+ }, "E2EE gateway key verified");
115082
+ return key;
115083
+ };
115084
+ const getKey = async () => {
115085
+ const now = clock();
115086
+ if (cached2 && now - cached2.fetchedAt < ttlMs && Math.floor(now / 1e3) < cached2.key.notAfter) {
115087
+ return cached2.key;
115088
+ }
115089
+ if (!inFlight) {
115090
+ inFlight = fetchKey().then((key) => {
115091
+ cached2 = { key, fetchedAt: clock() };
115092
+ return key;
115093
+ }).finally(() => {
115094
+ inFlight = null;
115095
+ });
115096
+ }
115097
+ try {
115098
+ return await inFlight;
115099
+ } catch (err2) {
115100
+ throw keyFetchError(err2);
115101
+ }
115102
+ };
115103
+ const invalidateKey = () => {
115104
+ cached2 = null;
115105
+ };
115106
+ return {
115107
+ invalidateKey,
115108
+ currentKey: () => cached2?.key ?? null,
115109
+ async encryptRequest({ model, messages, headers }) {
115110
+ if (typeof model !== "string" || model === "") {
115111
+ throw new InferenceRequestError("e2ee requires a non-empty request model", null, { errorType: "e2ee_invalid_payload_model", retryable: false });
115112
+ }
115113
+ const gatewayKey = await getKey();
115114
+ const client = await generateX25519KeyPair();
115115
+ const context = {
115116
+ algo: gatewayKey.algo,
115117
+ model,
115118
+ nonce: bytesToHex6(randomBytes4(32)),
115119
+ ts: Math.floor(clock() / 1e3)
115120
+ };
115121
+ headers.set(E2EE_HEADER_VERSION, "2");
115122
+ headers.set(E2EE_HEADER_CLIENT_PUB_KEY, bytesToHex6(client.publicKey));
115123
+ headers.set(E2EE_HEADER_MODEL_PUB_KEY, gatewayKey.publicKeyHex);
115124
+ headers.set(E2EE_HEADER_NONCE, context.nonce);
115125
+ headers.set(E2EE_HEADER_TIMESTAMP, String(context.ts));
115126
+ const encrypted = [];
115127
+ for (let index = 0; index < messages.length; index += 1) {
115128
+ const message = messages[index];
115129
+ let content;
115130
+ try {
115131
+ content = await encryptField({
115132
+ plaintext: message.content,
115133
+ recipientPublicKey: gatewayKey.publicKey,
115134
+ aad: requestFieldAad(context, `messages.${index}.content`)
115135
+ });
115136
+ } catch (err2) {
115137
+ const name = err2 instanceof Error ? err2.name : "Error";
115138
+ throw new InferenceRequestError(`e2ee request encryption failed (${name})`, null, { retryable: false });
115139
+ }
115140
+ encrypted.push({ ...message, content });
115141
+ }
115142
+ const request2 = {
115143
+ messages: encrypted,
115144
+ async decryptResponse({ content, field, id: id2, headers: response }) {
115145
+ const served = response.get(ACI_HEADER_KEYSET_DIGEST);
115146
+ if (served && served !== gatewayKey.keysetDigest) {
115147
+ options.logger?.warn?.({ pinned: gatewayKey.keysetDigest, served }, "E2EE keyset digest changed; refetching the attestation report");
115148
+ invalidateKey();
115149
+ }
115150
+ try {
115151
+ return await decryptField({
115152
+ wire: content,
115153
+ privateKey: client.privateKey,
115154
+ aad: responseFieldAad(context, field, id2)
115155
+ });
115156
+ } catch (err2) {
115157
+ const detail = err2 instanceof E2eeCipherError ? err2.message : "unexpected error";
115158
+ throw new InferenceRequestError(`e2ee response decryption failed for ${field} (${detail})`, null, { errorType: "e2ee_decryption_failed", retryable: false });
115159
+ }
115160
+ }
115161
+ };
115162
+ return request2;
115163
+ },
115164
+ async onRejected({ errorType }) {
115165
+ if (errorType === "e2ee_model_key_mismatch") {
115166
+ options.logger?.warn?.({ keyId: cached2?.key.keyId ?? null }, "E2EE model key rejected by the gateway; refetching the attestation report");
115167
+ invalidateKey();
115168
+ return true;
115169
+ }
115170
+ return false;
115171
+ }
115172
+ };
115173
+ }
115174
+
113385
115175
  // ../core/dist/mcp/store.js
113386
115176
  function createInMemoryMcpOAuthAuthorizationStore() {
113387
115177
  const byId = /* @__PURE__ */ new Map();
@@ -124090,7 +125880,7 @@ var Protocol = class {
124090
125880
  const capturedTransport = this._transport;
124091
125881
  const relatedTaskId = request2.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
124092
125882
  if (handler === void 0) {
124093
- const errorResponse3 = {
125883
+ const errorResponse4 = {
124094
125884
  jsonrpc: "2.0",
124095
125885
  id: request2.id,
124096
125886
  error: {
@@ -124101,11 +125891,11 @@ var Protocol = class {
124101
125891
  if (relatedTaskId && this._taskMessageQueue) {
124102
125892
  this._enqueueTaskMessage(relatedTaskId, {
124103
125893
  type: "error",
124104
- message: errorResponse3,
125894
+ message: errorResponse4,
124105
125895
  timestamp: Date.now()
124106
125896
  }, capturedTransport?.sessionId).catch((error51) => this._onerror(new Error(`Failed to enqueue error response: ${error51}`)));
124107
125897
  } else {
124108
- capturedTransport?.send(errorResponse3).catch((error51) => this._onerror(new Error(`Failed to send an error response: ${error51}`)));
125898
+ capturedTransport?.send(errorResponse4).catch((error51) => this._onerror(new Error(`Failed to send an error response: ${error51}`)));
124109
125899
  }
124110
125900
  return;
124111
125901
  }
@@ -124175,7 +125965,7 @@ var Protocol = class {
124175
125965
  if (abortController.signal.aborted) {
124176
125966
  return;
124177
125967
  }
124178
- const errorResponse3 = {
125968
+ const errorResponse4 = {
124179
125969
  jsonrpc: "2.0",
124180
125970
  id: request2.id,
124181
125971
  error: {
@@ -124187,11 +125977,11 @@ var Protocol = class {
124187
125977
  if (relatedTaskId && this._taskMessageQueue) {
124188
125978
  await this._enqueueTaskMessage(relatedTaskId, {
124189
125979
  type: "error",
124190
- message: errorResponse3,
125980
+ message: errorResponse4,
124191
125981
  timestamp: Date.now()
124192
125982
  }, capturedTransport?.sessionId);
124193
125983
  } else {
124194
- await capturedTransport?.send(errorResponse3);
125984
+ await capturedTransport?.send(errorResponse4);
124195
125985
  }
124196
125986
  }).catch((error51) => this._onerror(new Error(`Failed to send response: ${error51}`))).finally(() => {
124197
125987
  if (this._requestHandlerAbortControllers.get(request2.id) === abortController) {
@@ -126729,7 +128519,7 @@ var WebStandardStreamableHTTPServerTransport = class {
126729
128519
  * Only sends if eventStore is configured (opt-in for resumability) and
126730
128520
  * the client's protocol version supports empty SSE data (>= 2025-11-25).
126731
128521
  */
126732
- async writePrimingEvent(controller, encoder3, streamId, protocolVersion) {
128522
+ async writePrimingEvent(controller, encoder4, streamId, protocolVersion) {
126733
128523
  if (!this._eventStore) {
126734
128524
  return;
126735
128525
  }
@@ -126748,7 +128538,7 @@ data:
126748
128538
 
126749
128539
  `;
126750
128540
  }
126751
- controller.enqueue(encoder3.encode(primingEvent));
128541
+ controller.enqueue(encoder4.encode(primingEvent));
126752
128542
  }
126753
128543
  /**
126754
128544
  * Handles GET requests for SSE stream
@@ -126777,7 +128567,7 @@ data:
126777
128567
  this.onerror?.(new Error("Conflict: Only one SSE stream is allowed per session"));
126778
128568
  return this.createJsonErrorResponse(409, -32e3, "Conflict: Only one SSE stream is allowed per session");
126779
128569
  }
126780
- const encoder3 = new TextEncoder();
128570
+ const encoder4 = new TextEncoder();
126781
128571
  let streamController;
126782
128572
  const readable = new ReadableStream({
126783
128573
  start: (controller) => {
@@ -126797,7 +128587,7 @@ data:
126797
128587
  }
126798
128588
  this._streamMapping.set(this._standaloneSseStreamId, {
126799
128589
  controller: streamController,
126800
- encoder: encoder3,
128590
+ encoder: encoder4,
126801
128591
  cleanup: () => {
126802
128592
  this._streamMapping.delete(this._standaloneSseStreamId);
126803
128593
  try {
@@ -126838,7 +128628,7 @@ data:
126838
128628
  if (this.sessionId !== void 0) {
126839
128629
  headers["mcp-session-id"] = this.sessionId;
126840
128630
  }
126841
- const encoder3 = new TextEncoder();
128631
+ const encoder4 = new TextEncoder();
126842
128632
  let streamController;
126843
128633
  const readable = new ReadableStream({
126844
128634
  start: (controller) => {
@@ -126849,7 +128639,7 @@ data:
126849
128639
  });
126850
128640
  const replayedStreamId = await this._eventStore.replayEventsAfter(lastEventId, {
126851
128641
  send: async (eventId, message) => {
126852
- const success2 = this.writeSSEEvent(streamController, encoder3, message, eventId);
128642
+ const success2 = this.writeSSEEvent(streamController, encoder4, message, eventId);
126853
128643
  if (!success2) {
126854
128644
  this.onerror?.(new Error("Failed replay events"));
126855
128645
  try {
@@ -126861,7 +128651,7 @@ data:
126861
128651
  });
126862
128652
  this._streamMapping.set(replayedStreamId, {
126863
128653
  controller: streamController,
126864
- encoder: encoder3,
128654
+ encoder: encoder4,
126865
128655
  cleanup: () => {
126866
128656
  this._streamMapping.delete(replayedStreamId);
126867
128657
  try {
@@ -126879,7 +128669,7 @@ data:
126879
128669
  /**
126880
128670
  * Writes an event to an SSE stream via controller with proper formatting
126881
128671
  */
126882
- writeSSEEvent(controller, encoder3, message, eventId) {
128672
+ writeSSEEvent(controller, encoder4, message, eventId) {
126883
128673
  try {
126884
128674
  let eventData = `event: message
126885
128675
  `;
@@ -126890,7 +128680,7 @@ data:
126890
128680
  eventData += `data: ${JSON.stringify(message)}
126891
128681
 
126892
128682
  `;
126893
- controller.enqueue(encoder3.encode(eventData));
128683
+ controller.enqueue(encoder4.encode(eventData));
126894
128684
  return true;
126895
128685
  } catch (error51) {
126896
128686
  this.onerror?.(error51);
@@ -127012,7 +128802,7 @@ data:
127012
128802
  }
127013
128803
  });
127014
128804
  }
127015
- const encoder3 = new TextEncoder();
128805
+ const encoder4 = new TextEncoder();
127016
128806
  let streamController;
127017
128807
  const readable = new ReadableStream({
127018
128808
  start: (controller) => {
@@ -127034,7 +128824,7 @@ data:
127034
128824
  if (isJSONRPCRequest(message)) {
127035
128825
  this._streamMapping.set(streamId, {
127036
128826
  controller: streamController,
127037
- encoder: encoder3,
128827
+ encoder: encoder4,
127038
128828
  cleanup: () => {
127039
128829
  this._streamMapping.delete(streamId);
127040
128830
  try {
@@ -127046,7 +128836,7 @@ data:
127046
128836
  this._requestToStreamMapping.set(message.id, streamId);
127047
128837
  }
127048
128838
  }
127049
- await this.writePrimingEvent(streamController, encoder3, streamId, clientProtocolVersion);
128839
+ await this.writePrimingEvent(streamController, encoder4, streamId, clientProtocolVersion);
127050
128840
  for (const message of messages) {
127051
128841
  let closeSSEStream;
127052
128842
  let closeStandaloneSSEStream;
@@ -127814,16 +129604,16 @@ async function collectDiagnosticsWithTimeout(recorder, options, timeoutMs = DIAG
127814
129604
  }
127815
129605
 
127816
129606
  // ../lite/dist/runtime.js
127817
- function jsonResponse2(body, init) {
129607
+ function jsonResponse3(body, init) {
127818
129608
  const headers = new Headers(init?.headers);
127819
129609
  headers.set("Content-Type", "application/json");
127820
129610
  return new Response(JSON.stringify(body), { ...init, headers });
127821
129611
  }
127822
129612
  function protocolErrorResponse2(err2) {
127823
- return jsonResponse2(err2.toJSON(), { status: err2.code });
129613
+ return jsonResponse3(err2.toJSON(), { status: err2.code });
127824
129614
  }
127825
- function errorResponse2(status2, errorCode, message) {
127826
- return jsonResponse2({
129615
+ function errorResponse3(status2, errorCode, message) {
129616
+ return jsonResponse3({
127827
129617
  error: {
127828
129618
  code: status2,
127829
129619
  errorCode,
@@ -127832,7 +129622,7 @@ function errorResponse2(status2, errorCode, message) {
127832
129622
  }, { status: status2 });
127833
129623
  }
127834
129624
  function mcpUnauthorized(origin, message = "MCP authorization required") {
127835
- return jsonResponse2({
129625
+ return jsonResponse3({
127836
129626
  error: {
127837
129627
  code: 401,
127838
129628
  errorCode: "MCP_AUTH_REQUIRED",
@@ -127881,7 +129671,7 @@ function redirectWithOAuthError(redirectUri, error51, description, state) {
127881
129671
  url2.searchParams.set("state", state);
127882
129672
  return Response.redirect(url2.toString(), 302);
127883
129673
  } catch {
127884
- return jsonResponse2({
129674
+ return jsonResponse3({
127885
129675
  error: error51,
127886
129676
  error_description: description,
127887
129677
  ...state ? { state } : {}
@@ -128087,11 +129877,11 @@ function createPsLiteRuntime(options) {
128087
129877
  if (err2 instanceof ProtocolError) {
128088
129878
  return protocolErrorResponse2(err2);
128089
129879
  }
128090
- return errorResponse2(500, "INTERNAL_ERROR", "Internal server error");
129880
+ return errorResponse3(500, "INTERNAL_ERROR", "Internal server error");
128091
129881
  }
128092
129882
  }
128093
129883
  function sendContractResult(result) {
128094
- return jsonResponse2(result.body, { status: result.status });
129884
+ return jsonResponse3(result.body, { status: result.status });
128095
129885
  }
128096
129886
  function ownerAddress() {
128097
129887
  return options.serverOwner ?? options.identity?.address;
@@ -128099,7 +129889,7 @@ function createPsLiteRuntime(options) {
128099
129889
  async function handleAuthDevice(request2, url2) {
128100
129890
  if (url2.pathname === "/auth/device") {
128101
129891
  if (request2.method !== "POST") {
128102
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
129892
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128103
129893
  }
128104
129894
  return sendContractResult(initiateDeviceSessionContract({
128105
129895
  sessionStore: deviceSessions,
@@ -128113,7 +129903,7 @@ function createPsLiteRuntime(options) {
128113
129903
  }
128114
129904
  if (url2.pathname === "/auth/device/poll") {
128115
129905
  if (request2.method !== "GET") {
128116
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
129906
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128117
129907
  }
128118
129908
  return sendContractResult(pollDeviceSessionContract({
128119
129909
  sessionStore: deviceSessions,
@@ -128125,11 +129915,11 @@ function createPsLiteRuntime(options) {
128125
129915
  if (url2.pathname === "/auth/device/approve") {
128126
129916
  const sessionId = url2.searchParams.get("session");
128127
129917
  if (!sessionId) {
128128
- return request2.method === "GET" ? new Response("Missing session parameter", { status: 400 }) : jsonResponse2({ error: { code: 400, message: "Missing session parameter" } }, { status: 400 });
129918
+ return request2.method === "GET" ? new Response("Missing session parameter", { status: 400 }) : jsonResponse3({ error: { code: 400, message: "Missing session parameter" } }, { status: 400 });
128129
129919
  }
128130
129920
  const session = deviceSessions.get(sessionId);
128131
129921
  if (!session) {
128132
- return request2.method === "GET" ? new Response("Session expired or invalid", { status: 404 }) : jsonResponse2({ error: { code: 404, message: "Session expired or invalid" } }, { status: 404 });
129922
+ return request2.method === "GET" ? new Response("Session expired or invalid", { status: 404 }) : jsonResponse3({ error: { code: 404, message: "Session expired or invalid" } }, { status: 404 });
128133
129923
  }
128134
129924
  if (request2.method === "GET") {
128135
129925
  return new Response("Device authorization pending", {
@@ -128137,10 +129927,10 @@ function createPsLiteRuntime(options) {
128137
129927
  });
128138
129928
  }
128139
129929
  if (request2.method !== "POST") {
128140
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
129930
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128141
129931
  }
128142
129932
  if (session.status === "approved") {
128143
- return jsonResponse2({ status: "already_approved" });
129933
+ return jsonResponse3({ status: "already_approved" });
128144
129934
  }
128145
129935
  await auth.authorizeOwner(request2);
128146
129936
  return sendContractResult(await approveDeviceSessionContract({
@@ -128156,7 +129946,7 @@ function createPsLiteRuntime(options) {
128156
129946
  if (request2.method === "DELETE") {
128157
129947
  const token2 = bearerToken(request2);
128158
129948
  if (!token2) {
128159
- return jsonResponse2({ error: { code: 401, message: "Missing Bearer token" } }, { status: 401 });
129949
+ return jsonResponse3({ error: { code: 401, message: "Missing Bearer token" } }, { status: 401 });
128160
129950
  }
128161
129951
  return sendContractResult(await revokeDeviceTokenContract({
128162
129952
  tokenStore,
@@ -128164,11 +129954,11 @@ function createPsLiteRuntime(options) {
128164
129954
  }));
128165
129955
  }
128166
129956
  if (request2.method !== "POST") {
128167
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
129957
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128168
129958
  }
128169
129959
  const token = bearerToken(request2);
128170
129960
  if (!options.accessToken || token !== options.accessToken) {
128171
- return jsonResponse2({
129961
+ return jsonResponse3({
128172
129962
  error: {
128173
129963
  code: 403,
128174
129964
  message: "Only control-plane tokens can provision Personal Server session tokens"
@@ -128179,10 +129969,10 @@ function createPsLiteRuntime(options) {
128179
129969
  try {
128180
129970
  body = await request2.json();
128181
129971
  } catch {
128182
- return jsonResponse2({ error: { code: 400, message: "Request body must be valid JSON" } }, { status: 400 });
129972
+ return jsonResponse3({ error: { code: 400, message: "Request body must be valid JSON" } }, { status: 400 });
128183
129973
  }
128184
129974
  if (!body.token || typeof body.token !== "string") {
128185
- return jsonResponse2({ error: { code: 400, message: "Missing token" } }, { status: 400 });
129975
+ return jsonResponse3({ error: { code: 400, message: "Missing token" } }, { status: 400 });
128186
129976
  }
128187
129977
  return sendContractResult(await provisionDeviceTokenContract({
128188
129978
  tokenStore,
@@ -128198,10 +129988,12 @@ function createPsLiteRuntime(options) {
128198
129988
  activate() {
128199
129989
  active = true;
128200
129990
  options.syncManager?.start?.();
129991
+ options.derivatives?.scheduler.start();
128201
129992
  },
128202
129993
  deactivate() {
128203
129994
  active = false;
128204
129995
  void options.syncManager?.stop?.();
129996
+ options.derivatives?.scheduler.stop();
128205
129997
  },
128206
129998
  isAvailable() {
128207
129999
  return active;
@@ -128235,7 +130027,7 @@ function createPsLiteRuntime(options) {
128235
130027
  accessLogs: accessLogReader.capabilities?.accessLogs ?? "custom",
128236
130028
  config: options.stateCapabilities?.config ?? (options.saveConfig ? "custom" : "indexeddb")
128237
130029
  };
128238
- return jsonResponse2({
130030
+ return jsonResponse3({
128239
130031
  status: active ? "healthy" : "unavailable",
128240
130032
  runtime: "ps-lite",
128241
130033
  storage: options.storage.kind,
@@ -128253,7 +130045,7 @@ function createPsLiteRuntime(options) {
128253
130045
  }
128254
130046
  if (url2.pathname === "/v1/diagnostics") {
128255
130047
  if (request2.method !== "GET") {
128256
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130048
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128257
130049
  }
128258
130050
  try {
128259
130051
  await auth.authorizeOwner(request2);
@@ -128264,7 +130056,7 @@ function createPsLiteRuntime(options) {
128264
130056
  throw err2;
128265
130057
  }
128266
130058
  if (!options.diagnostics) {
128267
- return jsonResponse2({
130059
+ return jsonResponse3({
128268
130060
  error: {
128269
130061
  code: 404,
128270
130062
  errorCode: "DIAGNOSTICS_NOT_CONFIGURED",
@@ -128278,7 +130070,7 @@ function createPsLiteRuntime(options) {
128278
130070
  syncStatus: syncStatus2,
128279
130071
  storage: dataStorage
128280
130072
  });
128281
- return jsonResponse2(snapshot);
130073
+ return jsonResponse3(snapshot);
128282
130074
  }
128283
130075
  if (!active) {
128284
130076
  return unavailableResponse();
@@ -128313,9 +130105,16 @@ function createPsLiteRuntime(options) {
128313
130105
  // serverOwner is absent the accessRecord is safely omitted.
128314
130106
  serverOwner: options.serverOwner,
128315
130107
  serverSigner: x402ServerSigner,
128316
- lineageGateway: options.lineageGateway
130108
+ lineageGateway: options.lineageGateway,
130109
+ // Recompute on refresh: a new local version marks every
130110
+ // question that reads the scope stale.
130111
+ onDataWritten: options.derivatives ? (event) => options.derivatives?.scheduler.markSourceChanged(event.scope, { lineageSources: event.lineageSources }) : void 0
128317
130112
  }, { basePath: dataPrefix });
128318
130113
  }
130114
+ const derivativesPrefix = "/v1/derivatives";
130115
+ if (url2.pathname.startsWith(`${derivativesPrefix}/`)) {
130116
+ return handlePersonalServerDerivativesRequest(request2, { auth, compute: options.derivatives ?? null, now }, { basePath: derivativesPrefix });
130117
+ }
128319
130118
  if (url2.pathname.startsWith("/auth/device")) {
128320
130119
  const response = await handleAuthDevice(request2, url2);
128321
130120
  if (response)
@@ -128404,7 +130203,7 @@ function createPsLiteRuntime(options) {
128404
130203
  if (mcpResponse)
128405
130204
  return mcpResponse;
128406
130205
  }
128407
- return errorResponse2(404, "NOT_FOUND", "Not found");
130206
+ return errorResponse3(404, "NOT_FOUND", "Not found");
128408
130207
  });
128409
130208
  }
128410
130209
  };
@@ -128415,22 +130214,22 @@ async function handleMcpRoute(input) {
128415
130214
  const ownerAuthorizationPrefix = "/v1/mcp/oauth/authorizations";
128416
130215
  if (pathname === "/.well-known/oauth-protected-resource/mcp") {
128417
130216
  if (!resolveMcpApprovalUrl(input.approvalUrl)) {
128418
- return errorResponse2(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
130217
+ return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
128419
130218
  }
128420
- return jsonResponse2(protectedResourceMetadata(input.serverOrigin));
130219
+ return jsonResponse3(protectedResourceMetadata(input.serverOrigin));
128421
130220
  }
128422
130221
  if (pathname === "/.well-known/oauth-authorization-server") {
128423
130222
  if (!resolveMcpApprovalUrl(input.approvalUrl)) {
128424
- return errorResponse2(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
130223
+ return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
128425
130224
  }
128426
- return jsonResponse2(authorizationServerMetadata(input.serverOrigin));
130225
+ return jsonResponse3(authorizationServerMetadata(input.serverOrigin));
128427
130226
  }
128428
130227
  if (pathname === "/mcp/oauth/register") {
128429
130228
  if (!resolveMcpApprovalUrl(input.approvalUrl)) {
128430
- return errorResponse2(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
130229
+ return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
128431
130230
  }
128432
130231
  if (input.request.method !== "POST") {
128433
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130232
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128434
130233
  }
128435
130234
  let body = {};
128436
130235
  try {
@@ -128438,7 +130237,7 @@ async function handleMcpRoute(input) {
128438
130237
  } catch {
128439
130238
  body = {};
128440
130239
  }
128441
- return jsonResponse2({
130240
+ return jsonResponse3({
128442
130241
  client_id: `mcp-client-${crypto.randomUUID()}`,
128443
130242
  client_name: body.client_name ?? "Claude",
128444
130243
  redirect_uris: Array.isArray(body.redirect_uris) ? body.redirect_uris : [],
@@ -128449,10 +130248,10 @@ async function handleMcpRoute(input) {
128449
130248
  }
128450
130249
  if (pathname === "/mcp/oauth/authorize") {
128451
130250
  if (!resolveMcpApprovalUrl(input.approvalUrl)) {
128452
- return errorResponse2(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
130251
+ return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
128453
130252
  }
128454
130253
  if (input.request.method !== "GET") {
128455
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130254
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128456
130255
  }
128457
130256
  const responseType = input.url.searchParams.get("response_type");
128458
130257
  const clientId = input.url.searchParams.get("client_id") ?? "";
@@ -128480,7 +130279,7 @@ async function handleMcpRoute(input) {
128480
130279
  });
128481
130280
  const approvalUrl = resolveMcpApprovalUrl(input.approvalUrl);
128482
130281
  if (!approvalUrl) {
128483
- return errorResponse2(500, "MCP_APPROVAL_URL_MISSING", "MCP OAuth approval URL is not configured");
130282
+ return errorResponse3(500, "MCP_APPROVAL_URL_MISSING", "MCP OAuth approval URL is not configured");
128484
130283
  }
128485
130284
  const approve = new URL(approvalUrl);
128486
130285
  approve.searchParams.set("mcp_authorization", created.authorizationId);
@@ -128493,14 +130292,14 @@ async function handleMcpRoute(input) {
128493
130292
  }
128494
130293
  if (pathname === "/mcp/oauth/token") {
128495
130294
  if (!resolveMcpApprovalUrl(input.approvalUrl)) {
128496
- return errorResponse2(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
130295
+ return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
128497
130296
  }
128498
130297
  if (input.request.method !== "POST") {
128499
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130298
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128500
130299
  }
128501
130300
  const body = await parseFormBody(input.request);
128502
130301
  if (body.get("grant_type") !== "authorization_code") {
128503
- return jsonResponse2({
130302
+ return jsonResponse3({
128504
130303
  error: "unsupported_grant_type",
128505
130304
  error_description: "Only authorization_code is supported"
128506
130305
  }, { status: 400 });
@@ -128516,13 +130315,13 @@ async function handleMcpRoute(input) {
128516
130315
  connectionStore: input.store,
128517
130316
  now: input.now
128518
130317
  });
128519
- return jsonResponse2({
130318
+ return jsonResponse3({
128520
130319
  access_token: token.accessToken,
128521
130320
  token_type: "Bearer",
128522
130321
  ...token.scope ? { scope: token.scope } : {}
128523
130322
  });
128524
130323
  } catch (err2) {
128525
- return jsonResponse2({
130324
+ return jsonResponse3({
128526
130325
  error: err2 instanceof McpOAuthAuthorizationError ? err2.code : "invalid_grant",
128527
130326
  error_description: err2 instanceof Error ? err2.message : String(err2)
128528
130327
  }, { status: 400 });
@@ -128540,28 +130339,28 @@ async function handleMcpRoute(input) {
128540
130339
  const tail = pathname.slice(ownerAuthorizationPrefix.length + 1);
128541
130340
  const [id2, action] = tail.split("/");
128542
130341
  if (!id2) {
128543
- return errorResponse2(404, "NOT_FOUND", "Not found");
130342
+ return errorResponse3(404, "NOT_FOUND", "Not found");
128544
130343
  }
128545
130344
  if (!action && input.request.method === "GET") {
128546
130345
  const record2 = await input.authorizationStore.getById(id2);
128547
130346
  if (!record2) {
128548
- return errorResponse2(404, "NOT_FOUND", "Authorization not found");
130347
+ return errorResponse3(404, "NOT_FOUND", "Authorization not found");
128549
130348
  }
128550
- return jsonResponse2(toMcpOAuthAuthorizationView(record2));
130349
+ return jsonResponse3(toMcpOAuthAuthorizationView(record2));
128551
130350
  }
128552
130351
  if (action === "approve") {
128553
130352
  if (input.request.method !== "POST") {
128554
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130353
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128555
130354
  }
128556
130355
  let body = {};
128557
130356
  try {
128558
130357
  body = await input.request.json();
128559
130358
  } catch {
128560
- return errorResponse2(400, "INVALID_BODY", "Body must be JSON");
130359
+ return errorResponse3(400, "INVALID_BODY", "Body must be JSON");
128561
130360
  }
128562
130361
  if (Array.isArray(body.scopes) && body.scopes.length > 0) {
128563
130362
  if (!input.gateway || !input.gatewayConfig?.url) {
128564
- return errorResponse2(500, "SERVER_NOT_CONFIGURED", "Gateway config is not configured");
130363
+ return errorResponse3(500, "SERVER_NOT_CONFIGURED", "Gateway config is not configured");
128565
130364
  }
128566
130365
  try {
128567
130366
  const approved = await approveMcpOAuthAuthorizationWithScopes({
@@ -128579,16 +130378,16 @@ async function handleMcpRoute(input) {
128579
130378
  serverSigner: input.serverSigner,
128580
130379
  now: input.now
128581
130380
  });
128582
- return jsonResponse2({ redirectTo: approved.redirectTo });
130381
+ return jsonResponse3({ redirectTo: approved.redirectTo });
128583
130382
  } catch (err2) {
128584
130383
  if (err2 instanceof McpOAuthAuthorizationError) {
128585
- return errorResponse2(err2.status, err2.code, err2.message);
130384
+ return errorResponse3(err2.status, err2.code, err2.message);
128586
130385
  }
128587
130386
  throw err2;
128588
130387
  }
128589
130388
  }
128590
130389
  if (!Array.isArray(body.grants) || body.grants.length === 0) {
128591
- return errorResponse2(400, "GRANTS_REQUIRED", "Approve requires grants or scopes");
130390
+ return errorResponse3(400, "GRANTS_REQUIRED", "Approve requires grants or scopes");
128592
130391
  }
128593
130392
  try {
128594
130393
  const approved = await approveMcpOAuthAuthorization({ authorizationId: id2, grants: body.grants }, {
@@ -128596,15 +130395,15 @@ async function handleMcpRoute(input) {
128596
130395
  authorizationStore: input.authorizationStore,
128597
130396
  now: input.now
128598
130397
  });
128599
- return jsonResponse2({ redirectTo: approved.redirectTo });
130398
+ return jsonResponse3({ redirectTo: approved.redirectTo });
128600
130399
  } catch (err2) {
128601
130400
  if (err2 instanceof McpOAuthAuthorizationError) {
128602
- return errorResponse2(err2.status, err2.code, err2.message);
130401
+ return errorResponse3(err2.status, err2.code, err2.message);
128603
130402
  }
128604
130403
  throw err2;
128605
130404
  }
128606
130405
  }
128607
- return errorResponse2(404, "NOT_FOUND", "Not found");
130406
+ return errorResponse3(404, "NOT_FOUND", "Not found");
128608
130407
  }
128609
130408
  if (pathname === ownerPrefix || pathname.startsWith(`${ownerPrefix}/`)) {
128610
130409
  try {
@@ -128628,41 +130427,41 @@ async function handleMcpRoute(input) {
128628
130427
  publicOrigin: input.serverOrigin,
128629
130428
  now: input.now
128630
130429
  });
128631
- return jsonResponse2(created, { status: 201 });
130430
+ return jsonResponse3(created, { status: 201 });
128632
130431
  }
128633
130432
  if (input.request.method === "GET") {
128634
130433
  const records = await listMcpConnectionViews(input.store);
128635
- return jsonResponse2({ connections: records });
130434
+ return jsonResponse3({ connections: records });
128636
130435
  }
128637
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130436
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128638
130437
  }
128639
130438
  const tail = pathname.slice(ownerPrefix.length + 1);
128640
130439
  const [id2, action] = tail.split("/");
128641
130440
  if (!id2) {
128642
- return errorResponse2(404, "NOT_FOUND", "Not found");
130441
+ return errorResponse3(404, "NOT_FOUND", "Not found");
128643
130442
  }
128644
130443
  if (action === "approve") {
128645
130444
  if (input.request.method !== "POST") {
128646
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130445
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128647
130446
  }
128648
130447
  let body = {};
128649
130448
  try {
128650
130449
  body = await input.request.json();
128651
130450
  } catch {
128652
- return errorResponse2(400, "INVALID_BODY", "Body must be JSON");
130451
+ return errorResponse3(400, "INVALID_BODY", "Body must be JSON");
128653
130452
  }
128654
130453
  if (!Array.isArray(body.grants) || body.grants.length === 0) {
128655
- return errorResponse2(400, "GRANTS_REQUIRED", "Approve requires at least one grant \u2014 mint grants in the consent flow first");
130454
+ return errorResponse3(400, "GRANTS_REQUIRED", "Approve requires at least one grant \u2014 mint grants in the consent flow first");
128656
130455
  }
128657
130456
  try {
128658
130457
  const updated = await approveMcpConnection({ connectionId: id2, grants: body.grants }, { store: input.store, now: input.now });
128659
- return jsonResponse2(toMcpConnectionView(updated));
130458
+ return jsonResponse3(toMcpConnectionView(updated));
128660
130459
  } catch (err2) {
128661
130460
  if (err2 instanceof McpConnectionNotFoundError) {
128662
- return errorResponse2(404, "NOT_FOUND", err2.message);
130461
+ return errorResponse3(404, "NOT_FOUND", err2.message);
128663
130462
  }
128664
130463
  if (err2 instanceof McpConnectionStateError) {
128665
- return errorResponse2(409, "INVALID_STATE", err2.message);
130464
+ return errorResponse3(409, "INVALID_STATE", err2.message);
128666
130465
  }
128667
130466
  throw err2;
128668
130467
  }
@@ -128674,22 +130473,22 @@ async function handleMcpRoute(input) {
128674
130473
  store: input.store,
128675
130474
  now: input.now
128676
130475
  });
128677
- return jsonResponse2(toMcpConnectionView(updated));
130476
+ return jsonResponse3(toMcpConnectionView(updated));
128678
130477
  } catch (err2) {
128679
130478
  if (err2 instanceof McpConnectionNotFoundError) {
128680
- return errorResponse2(404, "NOT_FOUND", err2.message);
130479
+ return errorResponse3(404, "NOT_FOUND", err2.message);
128681
130480
  }
128682
130481
  throw err2;
128683
130482
  }
128684
130483
  }
128685
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130484
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128686
130485
  }
128687
- return errorResponse2(404, "NOT_FOUND", "Not found");
130486
+ return errorResponse3(404, "NOT_FOUND", "Not found");
128688
130487
  }
128689
130488
  async function handleMcpToken(rawToken, options) {
128690
130489
  if (!rawToken) {
128691
130490
  if (!options.oauthChallenge) {
128692
- return errorResponse2(401, "INVALID_TOKEN", "Missing MCP connection token");
130491
+ return errorResponse3(401, "INVALID_TOKEN", "Missing MCP connection token");
128693
130492
  }
128694
130493
  return mcpUnauthorized(input.serverOrigin);
128695
130494
  }
@@ -128697,7 +130496,7 @@ async function handleMcpRoute(input) {
128697
130496
  const record2 = await input.store.getByTokenHash(tokenHash);
128698
130497
  if (!record2) {
128699
130498
  if (!options.oauthChallenge) {
128700
- return errorResponse2(401, "INVALID_TOKEN", "Unknown or revoked MCP connection");
130499
+ return errorResponse3(401, "INVALID_TOKEN", "Unknown or revoked MCP connection");
128701
130500
  }
128702
130501
  return mcpUnauthorized(input.serverOrigin, "Unknown or revoked MCP connection");
128703
130502
  }
@@ -128741,10 +130540,10 @@ async function handleMcpRoute(input) {
128741
130540
  throw err2;
128742
130541
  }
128743
130542
  if (input.request.method !== "GET") {
128744
- return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
130543
+ return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
128745
130544
  }
128746
130545
  const snapshot = input.activityRecorder ? input.activityRecorder.snapshot() : { events: [], running: 0, total: 0 };
128747
- return jsonResponse2(snapshot);
130546
+ return jsonResponse3(snapshot);
128748
130547
  }
128749
130548
  if (pathname === "/mcp") {
128750
130549
  return handleMcpToken(bearerToken(input.request), {
@@ -128755,7 +130554,7 @@ async function handleMcpRoute(input) {
128755
130554
  if (pathname.startsWith(mcpPrefix)) {
128756
130555
  const rawToken = decodeURIComponent(pathname.slice(mcpPrefix.length));
128757
130556
  if (!rawToken || rawToken.includes("/")) {
128758
- return errorResponse2(404, "NOT_FOUND", "Not found");
130557
+ return errorResponse3(404, "NOT_FOUND", "Not found");
128759
130558
  }
128760
130559
  return handleMcpToken(rawToken, { oauthChallenge: false });
128761
130560
  }
@@ -129402,6 +131201,24 @@ async function downloadOne(deps, record2) {
129402
131201
  }
129403
131202
  diagnostics?.onIndexEnd(record2.id, envelope.scope);
129404
131203
  logger.info({ dataPointId: record2.id, scope: envelope.scope, path: relativePath }, "Downloaded and indexed data point");
131204
+ if (deps.onDataPointIndexed) {
131205
+ try {
131206
+ let lineageSources;
131207
+ try {
131208
+ lineageSources = readStoredLineage(envelope.data)?.sources;
131209
+ } catch {
131210
+ }
131211
+ deps.onDataPointIndexed({
131212
+ scope: envelope.scope,
131213
+ dataPointId: record2.id,
131214
+ version: Number(record2.expectedVersion),
131215
+ collectedAt: envelope.collectedAt,
131216
+ lineageSources
131217
+ });
131218
+ } catch (err2) {
131219
+ logger.warn({ scope: envelope.scope, error: err2.message }, "onDataPointIndexed hook failed; data point already indexed");
131220
+ }
131221
+ }
129405
131222
  return {
129406
131223
  dataPointId: record2.id,
129407
131224
  scope: envelope.scope,
@@ -130481,7 +132298,8 @@ async function createPsLiteSyncManager(options) {
130481
132298
  logger,
130482
132299
  diagnostics: downloadDiagnostics,
130483
132300
  dataPointFeed,
130484
- scopeDeletions
132301
+ scopeDeletions,
132302
+ onDataPointIndexed: options.onDataPointIndexed
130485
132303
  }, {
130486
132304
  deleteData,
130487
132305
  pendingBlobDeletions,
@@ -130509,6 +132327,65 @@ async function createPsLiteSyncManager(options) {
130509
132327
  return { syncManager, serverOwner, dataPointFeed, scopeDeletions };
130510
132328
  }
130511
132329
 
132330
+ // ../lite/dist/derivatives.js
132331
+ var QUESTIONS_KEY = "derivative-questions-v1";
132332
+ async function createPsLiteQuestionStore(stateStore) {
132333
+ const saved = await stateStore.get(QUESTIONS_KEY);
132334
+ const initial = saved?.version === 1 ? saved.questions : [];
132335
+ return createInMemoryQuestionStore({
132336
+ initial,
132337
+ onChange: (questions) => stateStore.set(QUESTIONS_KEY, {
132338
+ version: 1,
132339
+ questions
132340
+ })
132341
+ });
132342
+ }
132343
+ function psLiteInferenceConfigured(config2) {
132344
+ return config2.inference.baseUrl.replace(/\/+$/, "") !== DEFAULT_INFERENCE_BASE_URL.replace(/\/+$/, "");
132345
+ }
132346
+ function createPsLiteDerivativeCompute(options) {
132347
+ const logger = options.logger ? {
132348
+ info: (payload, message) => options.logger?.info(payload, message),
132349
+ warn: (payload, message) => options.logger?.warn(payload, message)
132350
+ } : void 0;
132351
+ const provider = options.provider ?? createOpenAiCompatibleInferenceProvider({
132352
+ baseUrl: options.config.inference.baseUrl,
132353
+ model: options.config.inference.model,
132354
+ // E2EE v2 to the Phala gateway (WebCrypto only, so it runs in the
132355
+ // browser): the relay sees ciphertext. `inference.e2ee: false` turns
132356
+ // it off for local development against a provider without ACI.
132357
+ encryption: options.config.inference.e2ee ? createPhalaE2eeEncryption({
132358
+ baseUrl: options.config.inference.baseUrl,
132359
+ logger
132360
+ }) : void 0
132361
+ });
132362
+ const scheduler = createRecomputeScheduler({
132363
+ store: options.store,
132364
+ debounceMs: options.config.inference.recomputeDebounceMs,
132365
+ serverOwner: options.serverOwner,
132366
+ now: options.now,
132367
+ logger,
132368
+ compute: (questionId) => computeQuestion(questionId, {
132369
+ // A -> B -> C: a question reading this derived scope recomputes.
132370
+ onDerivedWritten: (event) => scheduler.markSourceChanged(event.scope, {
132371
+ lineageSources: event.lineageSources
132372
+ }),
132373
+ runtimeAvailability: options.runtimeAvailability,
132374
+ storage: options.storage,
132375
+ store: options.store,
132376
+ provider,
132377
+ serverOwner: options.serverOwner,
132378
+ maxSourceItems: options.config.inference.maxSourceItems,
132379
+ syncManager: options.syncManager?.() ?? null,
132380
+ scopeDeletions: options.scopeDeletions?.(),
132381
+ writePolicyPorts: options.writePolicyPorts,
132382
+ now: options.now,
132383
+ logger
132384
+ })
132385
+ });
132386
+ return { store: options.store, scheduler, provider };
132387
+ }
132388
+
130512
132389
  // ../lite/dist/persistence.js
130513
132390
  function assertCompletePsLitePersistenceBundle(bundle) {
130514
132391
  if (!bundle || typeof bundle !== "object") {
@@ -130573,6 +132450,29 @@ async function createIndexedDbPsLiteRuntime(options) {
130573
132450
  });
130574
132451
  let syncManager = options.syncManager ?? null;
130575
132452
  let scopeDeletions = options.scopeDeletions;
132453
+ let runtimeRef = null;
132454
+ let derivatives = options.derivatives ?? null;
132455
+ if (derivatives === null && options.derivatives === void 0 && (options.inferenceProvider || psLiteInferenceConfigured(config2))) {
132456
+ derivatives = createPsLiteDerivativeCompute({
132457
+ config: config2,
132458
+ storage,
132459
+ store: await createPsLiteQuestionStore(stateStore),
132460
+ serverOwner,
132461
+ syncManager: () => syncManager,
132462
+ scopeDeletions: () => scopeDeletions,
132463
+ writePolicyPorts: {
132464
+ authSessionVerifier: gateway,
132465
+ grantVerifier: gateway
132466
+ },
132467
+ runtimeAvailability: {
132468
+ isAvailable: () => runtimeRef?.isAvailable() ?? Boolean(options.active)
132469
+ },
132470
+ provider: options.inferenceProvider,
132471
+ logger: options.logger
132472
+ });
132473
+ } else if (derivatives === null && options.derivatives === void 0) {
132474
+ options.logger?.warn({ baseUrl: config2.inference.baseUrl }, "Derivative compute disabled: inference.baseUrl is the direct-provider default; point it at the Vana inference relay");
132475
+ }
130576
132476
  if (!syncManager && config2.sync.enabled) {
130577
132477
  const sync = await createPsLiteSyncManager({
130578
132478
  config: config2,
@@ -130586,12 +132486,14 @@ async function createIndexedDbPsLiteRuntime(options) {
130586
132486
  scopeDeletions,
130587
132487
  diagnostics,
130588
132488
  logger: options.logger,
130589
- lineageGateway
132489
+ lineageGateway,
132490
+ onDataPointIndexed: (event) => derivatives?.scheduler.markSourceChanged(event.scope, {
132491
+ lineageSources: event.lineageSources
132492
+ })
130590
132493
  });
130591
132494
  syncManager = sync.syncManager;
130592
132495
  scopeDeletions = sync.scopeDeletions;
130593
132496
  }
130594
- let runtimeRef = null;
130595
132497
  const auth = options.auth ?? createWeb3SignedPsLiteAuth({
130596
132498
  origin: () => options.runtimeOrigin ?? config2.server.origin,
130597
132499
  ownerAddress: serverOwner,
@@ -130621,6 +132523,7 @@ async function createIndexedDbPsLiteRuntime(options) {
130621
132523
  scopeDeletions,
130622
132524
  diagnostics,
130623
132525
  lineageGateway,
132526
+ derivatives,
130624
132527
  saveConfig: async (nextConfig) => {
130625
132528
  const saved = await savePsLiteConfig(stateStore, nextConfig);
130626
132529
  Object.assign(config2, saved);
@@ -130643,7 +132546,8 @@ async function createIndexedDbPsLiteRuntime(options) {
130643
132546
  storage,
130644
132547
  tokenStore,
130645
132548
  accessLogStore,
130646
- syncManager
132549
+ syncManager,
132550
+ derivatives
130647
132551
  };
130648
132552
  }
130649
132553