@opendatalabs/personal-server-ts-server 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-auth.d.ts.map +1 -1
- package/dist/api-auth.js +1 -0
- package/dist/api-auth.js.map +1 -1
- package/dist/app.d.ts +9 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +30 -3
- package/dist/app.js.map +1 -1
- package/dist/bootstrap.d.ts +8 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +48 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/routes/data.d.ts +6 -0
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +1 -0
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/derivatives.d.ts +33 -0
- package/dist/routes/derivatives.d.ts.map +1 -0
- package/dist/routes/derivatives.js +33 -0
- package/dist/routes/derivatives.js.map +1 -0
- package/dist/storage/question-store.d.ts +9 -0
- package/dist/storage/question-store.d.ts.map +1 -0
- package/dist/storage/question-store.js +114 -0
- package/dist/storage/question-store.js.map +1 -0
- package/dist/ui/ps-lite-debug.js +1423 -82
- package/package.json +3 -3
package/dist/ui/ps-lite-debug.js
CHANGED
|
@@ -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,17 @@ 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
|
+
// Newest-first items kept per source scope when a prompt is assembled.
|
|
109760
|
+
maxSourceItems: 50,
|
|
109761
|
+
// Quiet period after a source scope changes before a recompute starts.
|
|
109762
|
+
recomputeDebounceMs: 5e3
|
|
109722
109763
|
}
|
|
109723
109764
|
};
|
|
109724
109765
|
var StorageBackend = external_exports.enum([
|
|
@@ -109772,7 +109813,13 @@ var ServerConfigSchema = external_exports.object({
|
|
|
109772
109813
|
enabled: external_exports.boolean().default(DEFAULTS.tunnel.enabled),
|
|
109773
109814
|
serverAddr: external_exports.string().default(DEFAULTS.tunnel.serverAddr),
|
|
109774
109815
|
serverPort: external_exports.number().int().min(1).max(65535).default(DEFAULTS.tunnel.serverPort)
|
|
109775
|
-
}).default(DEFAULTS.tunnel)
|
|
109816
|
+
}).default(DEFAULTS.tunnel),
|
|
109817
|
+
inference: external_exports.object({
|
|
109818
|
+
baseUrl: external_exports.url().default(DEFAULTS.inference.baseUrl),
|
|
109819
|
+
model: external_exports.string().min(1).default(DEFAULTS.inference.model),
|
|
109820
|
+
maxSourceItems: external_exports.number().int().min(1).max(1e4).default(DEFAULTS.inference.maxSourceItems),
|
|
109821
|
+
recomputeDebounceMs: external_exports.number().int().min(0).max(36e5).default(DEFAULTS.inference.recomputeDebounceMs)
|
|
109822
|
+
}).default(DEFAULTS.inference)
|
|
109776
109823
|
});
|
|
109777
109824
|
|
|
109778
109825
|
// ../lite/dist/state.js
|
|
@@ -112676,6 +112723,18 @@ function apiLoggerAsLogger(logger) {
|
|
|
112676
112723
|
error: (payload, message) => (logger?.error ?? noop)(payload, message ?? "")
|
|
112677
112724
|
};
|
|
112678
112725
|
}
|
|
112726
|
+
function notifyDataWritten(deps, event) {
|
|
112727
|
+
if (!deps.onDataWritten)
|
|
112728
|
+
return;
|
|
112729
|
+
try {
|
|
112730
|
+
deps.onDataWritten(event);
|
|
112731
|
+
} catch (err2) {
|
|
112732
|
+
deps.logger?.warn?.({
|
|
112733
|
+
scope: event.scope,
|
|
112734
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
112735
|
+
}, "onDataWritten hook failed; record already stored");
|
|
112736
|
+
}
|
|
112737
|
+
}
|
|
112679
112738
|
function notifyNewData(syncManager) {
|
|
112680
112739
|
if (!syncManager)
|
|
112681
112740
|
return;
|
|
@@ -113040,6 +113099,11 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
113040
113099
|
}, "Binary data file ingested");
|
|
113041
113100
|
await logBuilderWrite();
|
|
113042
113101
|
notifyNewData(deps.syncManager);
|
|
113102
|
+
notifyDataWritten(deps, {
|
|
113103
|
+
scope: scopeResult.scope,
|
|
113104
|
+
collectedAt: collectedAtValue,
|
|
113105
|
+
lineageSources: lineage2?.sources
|
|
113106
|
+
});
|
|
113043
113107
|
return jsonResponse(result2.response, { status: 201 });
|
|
113044
113108
|
}
|
|
113045
113109
|
const parsed = await parseJsonObjectBody(request2, "Request body must be valid JSON");
|
|
@@ -113067,6 +113131,11 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
113067
113131
|
}, "Data file ingested");
|
|
113068
113132
|
await logBuilderWrite();
|
|
113069
113133
|
notifyNewData(deps.syncManager);
|
|
113134
|
+
notifyDataWritten(deps, {
|
|
113135
|
+
scope: scopeResult.scope,
|
|
113136
|
+
collectedAt: collectedAtValue,
|
|
113137
|
+
lineageSources: lineage?.sources
|
|
113138
|
+
});
|
|
113070
113139
|
return jsonResponse(result.response, { status: 201 });
|
|
113071
113140
|
} catch (err2) {
|
|
113072
113141
|
if (err2 instanceof IngestPersistedError) {
|
|
@@ -113293,6 +113362,93 @@ async function handlePersonalServerOauthTokenRequest(request2, deps) {
|
|
|
113293
113362
|
});
|
|
113294
113363
|
}
|
|
113295
113364
|
|
|
113365
|
+
// ../core/dist/derivatives/types.js
|
|
113366
|
+
function questionRegistrationView(registration) {
|
|
113367
|
+
return {
|
|
113368
|
+
questionId: registration.questionId,
|
|
113369
|
+
derivedScope: registration.derivedScope,
|
|
113370
|
+
sourceScopes: [...registration.sourceScopes],
|
|
113371
|
+
question: registration.question,
|
|
113372
|
+
model: registration.model,
|
|
113373
|
+
registeredBy: registration.registeredBy,
|
|
113374
|
+
status: registration.status,
|
|
113375
|
+
error: registration.error,
|
|
113376
|
+
createdAt: registration.createdAt,
|
|
113377
|
+
updatedAt: registration.updatedAt,
|
|
113378
|
+
lastComputedAt: registration.lastComputedAt,
|
|
113379
|
+
derivedVersion: registration.derivedVersion,
|
|
113380
|
+
derivedCollectedAt: registration.derivedCollectedAt
|
|
113381
|
+
};
|
|
113382
|
+
}
|
|
113383
|
+
|
|
113384
|
+
// ../core/dist/derivatives/store.js
|
|
113385
|
+
function clone2(registration) {
|
|
113386
|
+
return {
|
|
113387
|
+
...registration,
|
|
113388
|
+
sourceScopes: [...registration.sourceScopes],
|
|
113389
|
+
registeredBy: { ...registration.registeredBy }
|
|
113390
|
+
};
|
|
113391
|
+
}
|
|
113392
|
+
function matchesQuestionFilter(registration, filter) {
|
|
113393
|
+
if (!filter)
|
|
113394
|
+
return true;
|
|
113395
|
+
if (filter.derivedScope && registration.derivedScope !== filter.derivedScope)
|
|
113396
|
+
return false;
|
|
113397
|
+
if (filter.sourceScope && !registration.sourceScopes.includes(filter.sourceScope))
|
|
113398
|
+
return false;
|
|
113399
|
+
if (filter.builder) {
|
|
113400
|
+
const by2 = registration.registeredBy;
|
|
113401
|
+
if (by2.kind !== "builder" || by2.builder.toLowerCase() !== filter.builder.toLowerCase())
|
|
113402
|
+
return false;
|
|
113403
|
+
}
|
|
113404
|
+
return true;
|
|
113405
|
+
}
|
|
113406
|
+
function sortQuestions(registrations) {
|
|
113407
|
+
return [...registrations].sort((a10, b10) => a10.createdAt.localeCompare(b10.createdAt) || a10.questionId.localeCompare(b10.questionId));
|
|
113408
|
+
}
|
|
113409
|
+
function createInMemoryQuestionStore(options = {}) {
|
|
113410
|
+
const byId = /* @__PURE__ */ new Map();
|
|
113411
|
+
for (const registration of options.initial ?? []) {
|
|
113412
|
+
byId.set(registration.questionId, clone2(registration));
|
|
113413
|
+
}
|
|
113414
|
+
async function changed() {
|
|
113415
|
+
if (!options.onChange)
|
|
113416
|
+
return;
|
|
113417
|
+
await options.onChange(sortQuestions([...byId.values()]).map(clone2));
|
|
113418
|
+
}
|
|
113419
|
+
return {
|
|
113420
|
+
async list(filter) {
|
|
113421
|
+
return sortQuestions([...byId.values()].filter((registration) => matchesQuestionFilter(registration, filter))).map(clone2);
|
|
113422
|
+
},
|
|
113423
|
+
async get(questionId) {
|
|
113424
|
+
const registration = byId.get(questionId);
|
|
113425
|
+
return registration ? clone2(registration) : null;
|
|
113426
|
+
},
|
|
113427
|
+
async insert(registration) {
|
|
113428
|
+
if (byId.has(registration.questionId)) {
|
|
113429
|
+
throw new Error(`Question ${registration.questionId} is already registered`);
|
|
113430
|
+
}
|
|
113431
|
+
byId.set(registration.questionId, clone2(registration));
|
|
113432
|
+
await changed();
|
|
113433
|
+
},
|
|
113434
|
+
async update(questionId, patch) {
|
|
113435
|
+
const current = byId.get(questionId);
|
|
113436
|
+
if (!current)
|
|
113437
|
+
return null;
|
|
113438
|
+
const next = { ...current, ...patch };
|
|
113439
|
+
byId.set(questionId, next);
|
|
113440
|
+
await changed();
|
|
113441
|
+
return clone2(next);
|
|
113442
|
+
},
|
|
113443
|
+
async delete(questionId) {
|
|
113444
|
+
const existed = byId.delete(questionId);
|
|
113445
|
+
if (existed)
|
|
113446
|
+
await changed();
|
|
113447
|
+
return existed;
|
|
113448
|
+
}
|
|
113449
|
+
};
|
|
113450
|
+
}
|
|
113451
|
+
|
|
113296
113452
|
// ../core/dist/policy/data-read.js
|
|
113297
113453
|
function parseGrantExpiresAtSeconds(value) {
|
|
113298
113454
|
if (value === null || value === void 0 || value === "0")
|
|
@@ -113382,6 +113538,1084 @@ async function verifyDataReadPolicy(input, ports) {
|
|
|
113382
113538
|
return grant;
|
|
113383
113539
|
}
|
|
113384
113540
|
|
|
113541
|
+
// ../core/dist/policy/data-write.js
|
|
113542
|
+
var WRITE_SCOPE_PREFIX = "write:";
|
|
113543
|
+
function isWriteScopeEntry(entry) {
|
|
113544
|
+
return entry.startsWith(WRITE_SCOPE_PREFIX);
|
|
113545
|
+
}
|
|
113546
|
+
function writeScopePatterns(grantScopes) {
|
|
113547
|
+
return grantScopes.filter(isWriteScopeEntry).map((entry) => entry.slice(WRITE_SCOPE_PREFIX.length)).filter((pattern) => pattern.length > 0);
|
|
113548
|
+
}
|
|
113549
|
+
function scopeCoveredByWriteGrant(requestedScope, grantScopes) {
|
|
113550
|
+
return writeScopePatterns(grantScopes).some((pattern) => scopeMatchesPattern(requestedScope, pattern));
|
|
113551
|
+
}
|
|
113552
|
+
async function verifyDataWritePolicy(input, ports) {
|
|
113553
|
+
const available = await ports.runtimeAvailability?.isAvailable();
|
|
113554
|
+
if (available === false) {
|
|
113555
|
+
throw new PsUnavailableError();
|
|
113556
|
+
}
|
|
113557
|
+
const builder = await ports.authSessionVerifier.getBuilder(input.signer);
|
|
113558
|
+
if (!builder) {
|
|
113559
|
+
throw new UnregisteredBuilderError();
|
|
113560
|
+
}
|
|
113561
|
+
if (!input.grantId) {
|
|
113562
|
+
throw new GrantRequiredError({
|
|
113563
|
+
reason: "No grantId bound to the write session"
|
|
113564
|
+
});
|
|
113565
|
+
}
|
|
113566
|
+
const grant = await ports.grantVerifier.getGrant(input.grantId);
|
|
113567
|
+
if (!grant) {
|
|
113568
|
+
throw new GrantRequiredError({
|
|
113569
|
+
reason: "Grant not found",
|
|
113570
|
+
grantId: input.grantId
|
|
113571
|
+
});
|
|
113572
|
+
}
|
|
113573
|
+
if (grant.revokedAt !== null) {
|
|
113574
|
+
throw new GrantRevokedError({ grantId: grant.id });
|
|
113575
|
+
}
|
|
113576
|
+
if (!grant.scopes || writeScopePatterns(grant.scopes).length === 0) {
|
|
113577
|
+
throw new ScopeMismatchError({
|
|
113578
|
+
requestedScope: input.requestedScope,
|
|
113579
|
+
reason: "Grant has no write scopes"
|
|
113580
|
+
});
|
|
113581
|
+
}
|
|
113582
|
+
if (grant.expiresAt !== null && grant.expiresAt !== void 0) {
|
|
113583
|
+
const expiresAtSec = parseGrantExpiresAtSeconds(grant.expiresAt);
|
|
113584
|
+
if (expiresAtSec === null) {
|
|
113585
|
+
throw new ScopeMismatchError({
|
|
113586
|
+
requestedScope: input.requestedScope,
|
|
113587
|
+
reason: "Grant expiry is invalid"
|
|
113588
|
+
});
|
|
113589
|
+
}
|
|
113590
|
+
if (expiresAtSec > 0) {
|
|
113591
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
113592
|
+
if (expiresAtSec < nowSec) {
|
|
113593
|
+
throw new GrantExpiredError({
|
|
113594
|
+
expiresAt: expiresAtSec
|
|
113595
|
+
});
|
|
113596
|
+
}
|
|
113597
|
+
}
|
|
113598
|
+
}
|
|
113599
|
+
if (!scopeCoveredByWriteGrant(input.requestedScope, grant.scopes)) {
|
|
113600
|
+
throw new ScopeMismatchError({
|
|
113601
|
+
requestedScope: input.requestedScope,
|
|
113602
|
+
grantedScopes: grant.scopes,
|
|
113603
|
+
reason: "Grant does not authorize writing to this scope"
|
|
113604
|
+
});
|
|
113605
|
+
}
|
|
113606
|
+
if (builder.id.toLowerCase() !== grant.granteeId.toLowerCase()) {
|
|
113607
|
+
throw new InvalidSignatureError3({
|
|
113608
|
+
reason: "Write signer is not the grant builder",
|
|
113609
|
+
expected: grant.granteeId,
|
|
113610
|
+
actual: input.signer
|
|
113611
|
+
});
|
|
113612
|
+
}
|
|
113613
|
+
if (!input.serverOwner) {
|
|
113614
|
+
throw new ServerNotConfiguredError({
|
|
113615
|
+
reason: "serverOwner is required to verify grant ownership"
|
|
113616
|
+
});
|
|
113617
|
+
}
|
|
113618
|
+
if (!grant.grantorAddress || grant.grantorAddress.toLowerCase() !== input.serverOwner.toLowerCase()) {
|
|
113619
|
+
throw new GrantOwnerMismatchError({
|
|
113620
|
+
grantId: grant.id,
|
|
113621
|
+
expected: input.serverOwner,
|
|
113622
|
+
actual: grant.grantorAddress ?? null
|
|
113623
|
+
});
|
|
113624
|
+
}
|
|
113625
|
+
await ports.writeFeeVerifier?.assertWriteAllowed({
|
|
113626
|
+
builder: input.signer,
|
|
113627
|
+
grant,
|
|
113628
|
+
scope: input.requestedScope
|
|
113629
|
+
});
|
|
113630
|
+
return grant;
|
|
113631
|
+
}
|
|
113632
|
+
|
|
113633
|
+
// ../core/dist/derivatives/registration.js
|
|
113634
|
+
var MAX_QUESTION_SOURCE_SCOPES = 16;
|
|
113635
|
+
var MAX_QUESTION_CHARS = 8e3;
|
|
113636
|
+
var MAX_MODEL_CHARS = 128;
|
|
113637
|
+
var MAX_ECHOED_SCOPE_CHARS = 128;
|
|
113638
|
+
var MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
|
|
113639
|
+
function isRecord4(value) {
|
|
113640
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113641
|
+
}
|
|
113642
|
+
function parseScope(value, field) {
|
|
113643
|
+
if (typeof value !== "string") {
|
|
113644
|
+
throw new DerivativeQuestionInvalidError(`${field} must be a scope string`, {
|
|
113645
|
+
field
|
|
113646
|
+
});
|
|
113647
|
+
}
|
|
113648
|
+
const parsed = parseDataScopeContract(value);
|
|
113649
|
+
if (!parsed.ok) {
|
|
113650
|
+
throw new DerivativeQuestionInvalidError(`${field} is not a valid scope: ${parsed.body.message}`, { field, scope: value.slice(0, MAX_ECHOED_SCOPE_CHARS) });
|
|
113651
|
+
}
|
|
113652
|
+
return parsed.scope;
|
|
113653
|
+
}
|
|
113654
|
+
function parseQuestionInput(body) {
|
|
113655
|
+
if (!isRecord4(body)) {
|
|
113656
|
+
throw new DerivativeQuestionInvalidError("Body must be a JSON object");
|
|
113657
|
+
}
|
|
113658
|
+
const derivedScope = parseScope(body.derivedScope, "derivedScope");
|
|
113659
|
+
if (!Array.isArray(body.sourceScopes) || body.sourceScopes.length === 0) {
|
|
113660
|
+
throw new DerivativeQuestionInvalidError("sourceScopes must be a non-empty array of scopes", { field: "sourceScopes" });
|
|
113661
|
+
}
|
|
113662
|
+
if (body.sourceScopes.length > MAX_QUESTION_SOURCE_SCOPES) {
|
|
113663
|
+
throw new DerivativeQuestionInvalidError(`sourceScopes lists ${body.sourceScopes.length} scopes; the maximum is ${MAX_QUESTION_SOURCE_SCOPES}`, { field: "sourceScopes", max: MAX_QUESTION_SOURCE_SCOPES });
|
|
113664
|
+
}
|
|
113665
|
+
const sourceScopes = [];
|
|
113666
|
+
for (const entry of body.sourceScopes) {
|
|
113667
|
+
const scope = parseScope(entry, "sourceScopes[]");
|
|
113668
|
+
if (sourceScopes.includes(scope)) {
|
|
113669
|
+
throw new DerivativeQuestionInvalidError("sourceScopes lists the same scope twice", { field: "sourceScopes", duplicate: scope });
|
|
113670
|
+
}
|
|
113671
|
+
if (scope === derivedScope) {
|
|
113672
|
+
throw new DerivativeQuestionInvalidError("derivedScope cannot be one of its own sources", { field: "sourceScopes", scope });
|
|
113673
|
+
}
|
|
113674
|
+
sourceScopes.push(scope);
|
|
113675
|
+
}
|
|
113676
|
+
if (typeof body.question !== "string" || body.question.trim() === "") {
|
|
113677
|
+
throw new DerivativeQuestionInvalidError("question must be a non-empty string", { field: "question" });
|
|
113678
|
+
}
|
|
113679
|
+
if (body.question.length > MAX_QUESTION_CHARS) {
|
|
113680
|
+
throw new DerivativeQuestionInvalidError(`question is ${body.question.length} characters; the maximum is ${MAX_QUESTION_CHARS}`, { field: "question", max: MAX_QUESTION_CHARS });
|
|
113681
|
+
}
|
|
113682
|
+
let model = null;
|
|
113683
|
+
if (body.model !== void 0 && body.model !== null) {
|
|
113684
|
+
if (typeof body.model !== "string" || body.model.length > MAX_MODEL_CHARS || !MODEL_ID.test(body.model)) {
|
|
113685
|
+
throw new DerivativeQuestionInvalidError("model must be a provider model id", { field: "model" });
|
|
113686
|
+
}
|
|
113687
|
+
model = body.model;
|
|
113688
|
+
}
|
|
113689
|
+
assertDerivedScopeNaming(derivedScope, sourceScopes);
|
|
113690
|
+
return { derivedScope, sourceScopes, question: body.question, model };
|
|
113691
|
+
}
|
|
113692
|
+
function findDerivationCycle(candidate, existing) {
|
|
113693
|
+
const sourcesOf = /* @__PURE__ */ new Map();
|
|
113694
|
+
const add2 = (derived, sources) => {
|
|
113695
|
+
const set2 = sourcesOf.get(derived) ?? /* @__PURE__ */ new Set();
|
|
113696
|
+
for (const source of sources)
|
|
113697
|
+
set2.add(source);
|
|
113698
|
+
sourcesOf.set(derived, set2);
|
|
113699
|
+
};
|
|
113700
|
+
for (const registration of existing) {
|
|
113701
|
+
add2(registration.derivedScope, registration.sourceScopes);
|
|
113702
|
+
}
|
|
113703
|
+
add2(candidate.derivedScope, candidate.sourceScopes);
|
|
113704
|
+
const target = candidate.derivedScope;
|
|
113705
|
+
const visited = /* @__PURE__ */ new Set();
|
|
113706
|
+
const stack = [
|
|
113707
|
+
{ scope: target, path: [target] }
|
|
113708
|
+
];
|
|
113709
|
+
while (stack.length > 0) {
|
|
113710
|
+
const { scope, path } = stack.pop();
|
|
113711
|
+
for (const source of sourcesOf.get(scope) ?? []) {
|
|
113712
|
+
if (source === target)
|
|
113713
|
+
return [...path, source];
|
|
113714
|
+
if (visited.has(source))
|
|
113715
|
+
continue;
|
|
113716
|
+
visited.add(source);
|
|
113717
|
+
stack.push({ scope: source, path: [...path, source] });
|
|
113718
|
+
}
|
|
113719
|
+
}
|
|
113720
|
+
return null;
|
|
113721
|
+
}
|
|
113722
|
+
async function createQuestionRegistration(input) {
|
|
113723
|
+
const parsed = parseQuestionInput(input.body);
|
|
113724
|
+
const cycle = findDerivationCycle(parsed, await input.store.list());
|
|
113725
|
+
if (cycle) {
|
|
113726
|
+
throw new DerivativeCycleError({
|
|
113727
|
+
derivedScope: parsed.derivedScope,
|
|
113728
|
+
path: cycle
|
|
113729
|
+
});
|
|
113730
|
+
}
|
|
113731
|
+
const at3 = input.now().toISOString();
|
|
113732
|
+
const registration = {
|
|
113733
|
+
questionId: input.questionId,
|
|
113734
|
+
derivedScope: parsed.derivedScope,
|
|
113735
|
+
sourceScopes: parsed.sourceScopes,
|
|
113736
|
+
question: parsed.question,
|
|
113737
|
+
model: parsed.model,
|
|
113738
|
+
registeredBy: input.registeredBy,
|
|
113739
|
+
status: "pending",
|
|
113740
|
+
error: null,
|
|
113741
|
+
createdAt: at3,
|
|
113742
|
+
updatedAt: at3,
|
|
113743
|
+
lastComputedAt: null,
|
|
113744
|
+
derivedVersion: null,
|
|
113745
|
+
derivedCollectedAt: null
|
|
113746
|
+
};
|
|
113747
|
+
await input.store.insert(registration);
|
|
113748
|
+
return registration;
|
|
113749
|
+
}
|
|
113750
|
+
function uncoveredSourceScopes(sourceScopes, grantScopes) {
|
|
113751
|
+
const readEntries = (grantScopes ?? []).filter((entry) => !isWriteScopeEntry(entry));
|
|
113752
|
+
return sourceScopes.filter((scope) => !scopeCoveredByGrant(scope, readEntries));
|
|
113753
|
+
}
|
|
113754
|
+
|
|
113755
|
+
// ../core/dist/derivatives/prompt.js
|
|
113756
|
+
var DEFAULT_MAX_SOURCE_ITEMS = 50;
|
|
113757
|
+
var DEFAULT_MAX_SOURCE_CHARS = 2e5;
|
|
113758
|
+
var TIMESTAMP_KEYS = [
|
|
113759
|
+
"collectedAt",
|
|
113760
|
+
"updatedAt",
|
|
113761
|
+
"updated_at",
|
|
113762
|
+
"update_time",
|
|
113763
|
+
"createdAt",
|
|
113764
|
+
"created_at",
|
|
113765
|
+
"create_time",
|
|
113766
|
+
"timestamp",
|
|
113767
|
+
"time",
|
|
113768
|
+
"date",
|
|
113769
|
+
"publishedAt",
|
|
113770
|
+
"published_at"
|
|
113771
|
+
];
|
|
113772
|
+
var RESERVED_KEYS = /* @__PURE__ */ new Set(["$lineage", "$writtenBy", "$binary"]);
|
|
113773
|
+
function isRecord5(value) {
|
|
113774
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113775
|
+
}
|
|
113776
|
+
function timestampOf(item) {
|
|
113777
|
+
if (!isRecord5(item))
|
|
113778
|
+
return null;
|
|
113779
|
+
for (const key of TIMESTAMP_KEYS) {
|
|
113780
|
+
const value = item[key];
|
|
113781
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
113782
|
+
return value < 1e12 ? value * 1e3 : value;
|
|
113783
|
+
}
|
|
113784
|
+
if (typeof value === "string") {
|
|
113785
|
+
const parsed = Date.parse(value);
|
|
113786
|
+
if (!Number.isNaN(parsed))
|
|
113787
|
+
return parsed;
|
|
113788
|
+
}
|
|
113789
|
+
}
|
|
113790
|
+
return null;
|
|
113791
|
+
}
|
|
113792
|
+
function sortNewestFirst(items) {
|
|
113793
|
+
const indexed = items.map((item, index) => ({
|
|
113794
|
+
item,
|
|
113795
|
+
index,
|
|
113796
|
+
at: timestampOf(item)
|
|
113797
|
+
}));
|
|
113798
|
+
const dated = indexed.filter((entry) => entry.at !== null).sort((a10, b10) => b10.at - a10.at || b10.index - a10.index);
|
|
113799
|
+
const undated = indexed.filter((entry) => entry.at === null).reverse();
|
|
113800
|
+
return [...dated, ...undated].map((entry) => entry.item);
|
|
113801
|
+
}
|
|
113802
|
+
function trimSourceData(data, options = {}) {
|
|
113803
|
+
const maxItems = Math.max(1, options.maxItems ?? DEFAULT_MAX_SOURCE_ITEMS);
|
|
113804
|
+
const maxChars = Math.max(1, options.maxChars ?? DEFAULT_MAX_SOURCE_CHARS);
|
|
113805
|
+
let kept = 0;
|
|
113806
|
+
let total = 0;
|
|
113807
|
+
const trimArray = (items, limit2) => {
|
|
113808
|
+
total += items.length;
|
|
113809
|
+
const sorted = sortNewestFirst(items).slice(0, limit2);
|
|
113810
|
+
kept += sorted.length;
|
|
113811
|
+
return sorted;
|
|
113812
|
+
};
|
|
113813
|
+
const build = (limit2) => {
|
|
113814
|
+
kept = 0;
|
|
113815
|
+
total = 0;
|
|
113816
|
+
if (Array.isArray(data))
|
|
113817
|
+
return trimArray(data, limit2);
|
|
113818
|
+
if (isRecord5(data)) {
|
|
113819
|
+
const out = {};
|
|
113820
|
+
for (const [key, value] of Object.entries(data)) {
|
|
113821
|
+
if (RESERVED_KEYS.has(key))
|
|
113822
|
+
continue;
|
|
113823
|
+
out[key] = Array.isArray(value) ? trimArray(value, limit2) : value;
|
|
113824
|
+
}
|
|
113825
|
+
return out;
|
|
113826
|
+
}
|
|
113827
|
+
return data;
|
|
113828
|
+
};
|
|
113829
|
+
let limit = maxItems;
|
|
113830
|
+
let result = build(limit);
|
|
113831
|
+
let text = JSON.stringify(result) ?? "null";
|
|
113832
|
+
while (text.length > maxChars && limit > 1) {
|
|
113833
|
+
limit = Math.max(1, Math.floor(limit / 2));
|
|
113834
|
+
result = build(limit);
|
|
113835
|
+
text = JSON.stringify(result) ?? "null";
|
|
113836
|
+
}
|
|
113837
|
+
if (text.length > maxChars) {
|
|
113838
|
+
return {
|
|
113839
|
+
data: `${text.slice(0, maxChars)}...[truncated]`,
|
|
113840
|
+
kept,
|
|
113841
|
+
total,
|
|
113842
|
+
truncated: true
|
|
113843
|
+
};
|
|
113844
|
+
}
|
|
113845
|
+
return { data: result, kept, total, truncated: false };
|
|
113846
|
+
}
|
|
113847
|
+
var SYSTEM_PROMPT = [
|
|
113848
|
+
"You answer a question about a person using ONLY the user data provided in the message.",
|
|
113849
|
+
"Do not use outside knowledge and do not guess; if the data does not support an answer, say so in the answer.",
|
|
113850
|
+
"Respond with a single JSON object and nothing else, with exactly these fields:",
|
|
113851
|
+
' "answer": string, the answer to the question, written for the person the data belongs to;',
|
|
113852
|
+
' "evidence": string, a short summary of which parts of the data support the answer.'
|
|
113853
|
+
].join("\n");
|
|
113854
|
+
function buildQuestionMessages(input) {
|
|
113855
|
+
const sections = input.sources.map((source) => {
|
|
113856
|
+
const note = source.total > source.kept ? ` (newest ${source.kept} of ${source.total} items)` : "";
|
|
113857
|
+
const cut = source.truncated ? " (truncated)" : "";
|
|
113858
|
+
return [
|
|
113859
|
+
`### Scope: ${source.scope}${note}${cut}`,
|
|
113860
|
+
`Collected at: ${source.collectedAt}`,
|
|
113861
|
+
JSON.stringify(source.data)
|
|
113862
|
+
].join("\n");
|
|
113863
|
+
});
|
|
113864
|
+
const user = [
|
|
113865
|
+
"## Question",
|
|
113866
|
+
input.question,
|
|
113867
|
+
"",
|
|
113868
|
+
"## User data",
|
|
113869
|
+
...sections,
|
|
113870
|
+
"",
|
|
113871
|
+
"Answer the question as a JSON object with the fields answer and evidence."
|
|
113872
|
+
].join("\n");
|
|
113873
|
+
return [
|
|
113874
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
113875
|
+
{ role: "user", content: user }
|
|
113876
|
+
];
|
|
113877
|
+
}
|
|
113878
|
+
function parseAnswer(content) {
|
|
113879
|
+
const candidates = [content.trim()];
|
|
113880
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(content);
|
|
113881
|
+
if (fenced?.[1])
|
|
113882
|
+
candidates.unshift(fenced[1].trim());
|
|
113883
|
+
const first = content.indexOf("{");
|
|
113884
|
+
const last2 = content.lastIndexOf("}");
|
|
113885
|
+
if (first !== -1 && last2 > first) {
|
|
113886
|
+
candidates.push(content.slice(first, last2 + 1));
|
|
113887
|
+
}
|
|
113888
|
+
for (const candidate of candidates) {
|
|
113889
|
+
try {
|
|
113890
|
+
const parsed = JSON.parse(candidate);
|
|
113891
|
+
if (isRecord5(parsed) && typeof parsed.answer === "string") {
|
|
113892
|
+
return {
|
|
113893
|
+
answer: parsed.answer,
|
|
113894
|
+
evidence: typeof parsed.evidence === "string" ? parsed.evidence : null
|
|
113895
|
+
};
|
|
113896
|
+
}
|
|
113897
|
+
} catch {
|
|
113898
|
+
}
|
|
113899
|
+
}
|
|
113900
|
+
return { answer: content.trim(), evidence: null };
|
|
113901
|
+
}
|
|
113902
|
+
|
|
113903
|
+
// ../core/dist/derivatives/inference.js
|
|
113904
|
+
var DEFAULT_INFERENCE_BASE_URL = "https://inference.phala.com/v1";
|
|
113905
|
+
var DEFAULT_INFERENCE_MODEL = "z-ai/glm-5.2";
|
|
113906
|
+
var DEFAULT_INFERENCE_TIMEOUT_MS = 12e4;
|
|
113907
|
+
var DEFAULT_INFERENCE_MAX_TOKENS = 2048;
|
|
113908
|
+
var DEFAULT_INFERENCE_REQUEST_FIELDS = {
|
|
113909
|
+
provider: { aci_verified: true, zdr: true }
|
|
113910
|
+
};
|
|
113911
|
+
var InferenceRequestError = class extends Error {
|
|
113912
|
+
status;
|
|
113913
|
+
constructor(message, status2) {
|
|
113914
|
+
super(message);
|
|
113915
|
+
this.status = status2;
|
|
113916
|
+
this.name = "InferenceRequestError";
|
|
113917
|
+
}
|
|
113918
|
+
};
|
|
113919
|
+
function isRecord6(value) {
|
|
113920
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113921
|
+
}
|
|
113922
|
+
function readUsage(value) {
|
|
113923
|
+
if (!isRecord6(value))
|
|
113924
|
+
return void 0;
|
|
113925
|
+
const num2 = (v10) => typeof v10 === "number" ? v10 : void 0;
|
|
113926
|
+
const usage = {
|
|
113927
|
+
promptTokens: num2(value.prompt_tokens),
|
|
113928
|
+
completionTokens: num2(value.completion_tokens),
|
|
113929
|
+
totalTokens: num2(value.total_tokens)
|
|
113930
|
+
};
|
|
113931
|
+
return usage;
|
|
113932
|
+
}
|
|
113933
|
+
function readContent(body) {
|
|
113934
|
+
if (!isRecord6(body) || !Array.isArray(body.choices))
|
|
113935
|
+
return null;
|
|
113936
|
+
const first = body.choices[0];
|
|
113937
|
+
if (!isRecord6(first) || !isRecord6(first.message))
|
|
113938
|
+
return null;
|
|
113939
|
+
const content = first.message.content;
|
|
113940
|
+
if (typeof content === "string")
|
|
113941
|
+
return content;
|
|
113942
|
+
if (Array.isArray(content)) {
|
|
113943
|
+
const text = content.map((part) => isRecord6(part) && typeof part.text === "string" ? part.text : "").join("");
|
|
113944
|
+
return text;
|
|
113945
|
+
}
|
|
113946
|
+
return null;
|
|
113947
|
+
}
|
|
113948
|
+
function createOpenAiCompatibleInferenceProvider(options = {}) {
|
|
113949
|
+
const base = (options.baseUrl ?? DEFAULT_INFERENCE_BASE_URL).replace(/\/+$/, "");
|
|
113950
|
+
const defaultModel = options.model ?? DEFAULT_INFERENCE_MODEL;
|
|
113951
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_INFERENCE_TIMEOUT_MS;
|
|
113952
|
+
const doFetch = options.fetch ?? fetch;
|
|
113953
|
+
const requestFields = options.requestFields ?? DEFAULT_INFERENCE_REQUEST_FIELDS;
|
|
113954
|
+
return {
|
|
113955
|
+
defaultModel,
|
|
113956
|
+
async chat(input) {
|
|
113957
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
113958
|
+
if (options.apiKey) {
|
|
113959
|
+
headers.set("Authorization", `Bearer ${options.apiKey}`);
|
|
113960
|
+
}
|
|
113961
|
+
let messages = input.messages;
|
|
113962
|
+
if (options.encryption) {
|
|
113963
|
+
({ messages } = await options.encryption.encryptRequest({
|
|
113964
|
+
messages,
|
|
113965
|
+
headers
|
|
113966
|
+
}));
|
|
113967
|
+
}
|
|
113968
|
+
const body = {
|
|
113969
|
+
...requestFields,
|
|
113970
|
+
model: input.model || defaultModel,
|
|
113971
|
+
messages,
|
|
113972
|
+
max_tokens: input.maxTokens ?? DEFAULT_INFERENCE_MAX_TOKENS
|
|
113973
|
+
};
|
|
113974
|
+
let response;
|
|
113975
|
+
try {
|
|
113976
|
+
response = await doFetch(`${base}/chat/completions`, {
|
|
113977
|
+
method: "POST",
|
|
113978
|
+
headers,
|
|
113979
|
+
body: JSON.stringify(body),
|
|
113980
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
113981
|
+
});
|
|
113982
|
+
} catch (err2) {
|
|
113983
|
+
const name = err2 instanceof Error ? err2.name : "Error";
|
|
113984
|
+
throw new InferenceRequestError(`inference request failed before a response (${name})`, null);
|
|
113985
|
+
}
|
|
113986
|
+
if (!response.ok) {
|
|
113987
|
+
throw new InferenceRequestError(`inference request failed with status ${response.status}`, response.status);
|
|
113988
|
+
}
|
|
113989
|
+
let parsed;
|
|
113990
|
+
try {
|
|
113991
|
+
parsed = await response.json();
|
|
113992
|
+
} catch {
|
|
113993
|
+
throw new InferenceRequestError("inference response was not JSON", response.status);
|
|
113994
|
+
}
|
|
113995
|
+
let content = readContent(parsed);
|
|
113996
|
+
if (content === null || content.trim() === "") {
|
|
113997
|
+
throw new InferenceRequestError("inference response carried no assistant content", response.status);
|
|
113998
|
+
}
|
|
113999
|
+
if (options.encryption) {
|
|
114000
|
+
content = await options.encryption.decryptResponse({
|
|
114001
|
+
content,
|
|
114002
|
+
headers: response.headers
|
|
114003
|
+
});
|
|
114004
|
+
}
|
|
114005
|
+
const receiptId = response.headers.get("x-receipt-id") ?? void 0;
|
|
114006
|
+
const aciIdentity = response.headers.get("x-aci-identity") ?? void 0;
|
|
114007
|
+
return {
|
|
114008
|
+
content,
|
|
114009
|
+
usage: readUsage(isRecord6(parsed) ? parsed.usage : void 0),
|
|
114010
|
+
...receiptId ? { receiptId } : {},
|
|
114011
|
+
...aciIdentity ? { aciIdentity } : {}
|
|
114012
|
+
};
|
|
114013
|
+
}
|
|
114014
|
+
};
|
|
114015
|
+
}
|
|
114016
|
+
|
|
114017
|
+
// ../core/dist/derivatives/compute.js
|
|
114018
|
+
var DEFAULT_RETRY_DELAYS_MS = [1e3, 4e3];
|
|
114019
|
+
function isRetryableInferenceError(err2) {
|
|
114020
|
+
return err2 instanceof InferenceRequestError && (err2.status === null || err2.status === 429 || err2.status >= 500);
|
|
114021
|
+
}
|
|
114022
|
+
async function withRetries(deps, attempt, retryable) {
|
|
114023
|
+
const delays = deps.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
|
|
114024
|
+
const sleep2 = deps.sleep ?? ((ms3) => new Promise((r10) => setTimeout(r10, ms3)));
|
|
114025
|
+
for (let index = 0; ; index += 1) {
|
|
114026
|
+
try {
|
|
114027
|
+
return await attempt();
|
|
114028
|
+
} catch (err2) {
|
|
114029
|
+
if (index >= delays.length || !retryable(err2))
|
|
114030
|
+
throw err2;
|
|
114031
|
+
await sleep2(delays[index]);
|
|
114032
|
+
}
|
|
114033
|
+
}
|
|
114034
|
+
}
|
|
114035
|
+
var ComputeFailure = class extends Error {
|
|
114036
|
+
constructor(message) {
|
|
114037
|
+
super(message);
|
|
114038
|
+
this.name = "ComputeFailure";
|
|
114039
|
+
}
|
|
114040
|
+
};
|
|
114041
|
+
function shortError(err2) {
|
|
114042
|
+
if (err2 instanceof ComputeFailure)
|
|
114043
|
+
return err2.message;
|
|
114044
|
+
if (err2 instanceof InferenceRequestError)
|
|
114045
|
+
return err2.message;
|
|
114046
|
+
if (err2 instanceof ProtocolError)
|
|
114047
|
+
return `${err2.errorCode}: ${err2.message}`;
|
|
114048
|
+
return `compute failed (${err2 instanceof Error ? err2.name : "Error"})`;
|
|
114049
|
+
}
|
|
114050
|
+
function collectedAtStamp(now, isTaken) {
|
|
114051
|
+
const base = now();
|
|
114052
|
+
base.setUTCMilliseconds(0);
|
|
114053
|
+
for (let bump = 0; bump < 60; bump += 1) {
|
|
114054
|
+
const candidate = new Date(base.getTime() + bump * 1e3).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
114055
|
+
if (!isTaken(candidate))
|
|
114056
|
+
return candidate;
|
|
114057
|
+
}
|
|
114058
|
+
throw new ComputeFailure("could not allocate a version stamp");
|
|
114059
|
+
}
|
|
114060
|
+
async function tombstoneMarker(scopeDeletions, scope) {
|
|
114061
|
+
if (!scopeDeletions)
|
|
114062
|
+
return null;
|
|
114063
|
+
const verdict = await scopeDeletions.resolve(scope);
|
|
114064
|
+
if (!verdict.deleted || verdict.version === null)
|
|
114065
|
+
return null;
|
|
114066
|
+
const version4 = Number(verdict.version);
|
|
114067
|
+
return Number.isSafeInteger(version4) ? version4 : null;
|
|
114068
|
+
}
|
|
114069
|
+
function localScopesById2(storage, serverOwner) {
|
|
114070
|
+
const byId = /* @__PURE__ */ new Map();
|
|
114071
|
+
for (let offset = 0; ; offset += LOCAL_SCOPE_SCAN_PAGE) {
|
|
114072
|
+
const { scopes, total } = storage.listScopes({
|
|
114073
|
+
limit: LOCAL_SCOPE_SCAN_PAGE,
|
|
114074
|
+
offset
|
|
114075
|
+
});
|
|
114076
|
+
for (const summary of scopes) {
|
|
114077
|
+
byId.set(computeDataPointId(serverOwner, summary.scope), summary.scope);
|
|
114078
|
+
}
|
|
114079
|
+
if (scopes.length === 0 || offset + scopes.length >= total)
|
|
114080
|
+
break;
|
|
114081
|
+
}
|
|
114082
|
+
return byId;
|
|
114083
|
+
}
|
|
114084
|
+
async function assertNoLineageCycle(deps, registration, serverOwner, sourceLineage) {
|
|
114085
|
+
const derivedId = computeDataPointId(serverOwner, registration.derivedScope);
|
|
114086
|
+
let byId = null;
|
|
114087
|
+
const visited = /* @__PURE__ */ new Set();
|
|
114088
|
+
const stack = [];
|
|
114089
|
+
for (const [scope, sources] of sourceLineage) {
|
|
114090
|
+
for (const id2 of sources)
|
|
114091
|
+
stack.push({ id: id2, path: [scope] });
|
|
114092
|
+
}
|
|
114093
|
+
while (stack.length > 0) {
|
|
114094
|
+
const { id: id2, path } = stack.pop();
|
|
114095
|
+
if (id2 === derivedId) {
|
|
114096
|
+
throw new DerivativeCycleError({
|
|
114097
|
+
derivedScope: registration.derivedScope,
|
|
114098
|
+
path: [registration.derivedScope, ...path, registration.derivedScope]
|
|
114099
|
+
});
|
|
114100
|
+
}
|
|
114101
|
+
if (visited.has(id2))
|
|
114102
|
+
continue;
|
|
114103
|
+
visited.add(id2);
|
|
114104
|
+
byId ??= localScopesById2(deps.storage, serverOwner);
|
|
114105
|
+
const scope = byId.get(id2);
|
|
114106
|
+
if (!scope)
|
|
114107
|
+
continue;
|
|
114108
|
+
const entry = deps.storage.findEntry({ scope });
|
|
114109
|
+
if (!entry)
|
|
114110
|
+
continue;
|
|
114111
|
+
let sources = [];
|
|
114112
|
+
try {
|
|
114113
|
+
const envelope = await deps.storage.readEnvelope(scope, entry.collectedAt);
|
|
114114
|
+
sources = readStoredLineage(envelope.data)?.sources ?? [];
|
|
114115
|
+
} catch {
|
|
114116
|
+
}
|
|
114117
|
+
for (const next of sources)
|
|
114118
|
+
stack.push({ id: next, path: [...path, scope] });
|
|
114119
|
+
}
|
|
114120
|
+
}
|
|
114121
|
+
async function loadSource(deps, scope) {
|
|
114122
|
+
const entry = deps.storage.findEntry({ scope });
|
|
114123
|
+
const deletion = await resolveReadDeletion({ scopeDeletions: deps.scopeDeletions, serverOwner: deps.serverOwner }, scope, entry);
|
|
114124
|
+
if (deletion) {
|
|
114125
|
+
throw new ComputeFailure(`source scope ${scope} is deleted`);
|
|
114126
|
+
}
|
|
114127
|
+
if (!entry) {
|
|
114128
|
+
throw new ComputeFailure(`source scope ${scope} has no local data`);
|
|
114129
|
+
}
|
|
114130
|
+
let envelope;
|
|
114131
|
+
try {
|
|
114132
|
+
envelope = await deps.storage.readEnvelope(scope, entry.collectedAt);
|
|
114133
|
+
} catch {
|
|
114134
|
+
throw new ComputeFailure(`source scope ${scope} could not be read`);
|
|
114135
|
+
}
|
|
114136
|
+
let lineageSources = [];
|
|
114137
|
+
try {
|
|
114138
|
+
lineageSources = readStoredLineage(envelope.data)?.sources ?? [];
|
|
114139
|
+
} catch {
|
|
114140
|
+
}
|
|
114141
|
+
const raw = isBinaryEnvelope(envelope) ? {
|
|
114142
|
+
binary: true,
|
|
114143
|
+
note: "binary record; its content is not included in the prompt"
|
|
114144
|
+
} : envelope.data;
|
|
114145
|
+
const trimmed = trimSourceData(raw, {
|
|
114146
|
+
maxItems: deps.maxSourceItems,
|
|
114147
|
+
maxChars: deps.maxSourceChars
|
|
114148
|
+
});
|
|
114149
|
+
return {
|
|
114150
|
+
source: {
|
|
114151
|
+
scope,
|
|
114152
|
+
collectedAt: entry.collectedAt,
|
|
114153
|
+
version: entry.version,
|
|
114154
|
+
data: trimmed.data,
|
|
114155
|
+
kept: trimmed.kept,
|
|
114156
|
+
total: trimmed.total,
|
|
114157
|
+
truncated: trimmed.truncated
|
|
114158
|
+
},
|
|
114159
|
+
lineageSources
|
|
114160
|
+
};
|
|
114161
|
+
}
|
|
114162
|
+
async function assertGrantStillValid(deps, registration) {
|
|
114163
|
+
if (registration.registeredBy.kind !== "builder")
|
|
114164
|
+
return;
|
|
114165
|
+
if (!deps.writePolicyPorts) {
|
|
114166
|
+
throw new ComputeFailure("builder grant verification is not configured");
|
|
114167
|
+
}
|
|
114168
|
+
if (!deps.serverOwner) {
|
|
114169
|
+
throw new ComputeFailure("server owner is not configured");
|
|
114170
|
+
}
|
|
114171
|
+
const { builder, grantId } = registration.registeredBy;
|
|
114172
|
+
const ports = deps.writePolicyPorts;
|
|
114173
|
+
const serverOwner = deps.serverOwner;
|
|
114174
|
+
const grant = await withRetries(deps, () => verifyDataWritePolicy({
|
|
114175
|
+
signer: builder,
|
|
114176
|
+
grantId,
|
|
114177
|
+
requestedScope: registration.derivedScope,
|
|
114178
|
+
serverOwner
|
|
114179
|
+
}, ports), (err2) => !(err2 instanceof ProtocolError));
|
|
114180
|
+
const uncovered = uncoveredSourceScopes(registration.sourceScopes, grant.scopes ?? []);
|
|
114181
|
+
if (uncovered.length > 0) {
|
|
114182
|
+
throw new DerivativeSourceNotGrantedError({ scopes: uncovered });
|
|
114183
|
+
}
|
|
114184
|
+
}
|
|
114185
|
+
async function computeQuestion(questionId, deps) {
|
|
114186
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
114187
|
+
if (await deps.runtimeAvailability?.isAvailable() === false) {
|
|
114188
|
+
return { status: "skipped", reason: "runtime-unavailable" };
|
|
114189
|
+
}
|
|
114190
|
+
const registration = await deps.store.get(questionId);
|
|
114191
|
+
if (!registration)
|
|
114192
|
+
return { status: "skipped", reason: "unknown-question" };
|
|
114193
|
+
try {
|
|
114194
|
+
if (!deps.serverOwner) {
|
|
114195
|
+
throw new ComputeFailure("server owner is not configured");
|
|
114196
|
+
}
|
|
114197
|
+
const serverOwner = deps.serverOwner;
|
|
114198
|
+
await assertGrantStillValid(deps, registration);
|
|
114199
|
+
assertDerivedScopeNaming(registration.derivedScope, registration.sourceScopes);
|
|
114200
|
+
const sources = [];
|
|
114201
|
+
const sourceLineage = /* @__PURE__ */ new Map();
|
|
114202
|
+
for (const scope of registration.sourceScopes) {
|
|
114203
|
+
const loaded = await loadSource(deps, scope);
|
|
114204
|
+
sources.push(loaded.source);
|
|
114205
|
+
sourceLineage.set(scope, loaded.lineageSources);
|
|
114206
|
+
}
|
|
114207
|
+
await assertNoLineageCycle(deps, registration, serverOwner, sourceLineage);
|
|
114208
|
+
const messages = buildQuestionMessages({
|
|
114209
|
+
question: registration.question,
|
|
114210
|
+
sources
|
|
114211
|
+
});
|
|
114212
|
+
const model = registration.model ?? deps.provider.defaultModel;
|
|
114213
|
+
const reply = await withRetries(deps, () => deps.provider.chat({ model, messages, maxTokens: deps.maxTokens }), isRetryableInferenceError);
|
|
114214
|
+
const parsed = parseAnswer(reply.content);
|
|
114215
|
+
const computedAt = now().toISOString();
|
|
114216
|
+
const lineageIds = registration.sourceScopes.map((scope) => computeDataPointId(serverOwner, scope));
|
|
114217
|
+
const record2 = {
|
|
114218
|
+
questionId: registration.questionId,
|
|
114219
|
+
question: registration.question,
|
|
114220
|
+
answer: parsed.answer,
|
|
114221
|
+
evidence: parsed.evidence,
|
|
114222
|
+
model,
|
|
114223
|
+
computedAt,
|
|
114224
|
+
sources: sources.map((source) => ({
|
|
114225
|
+
scope: source.scope,
|
|
114226
|
+
version: source.version,
|
|
114227
|
+
collectedAt: source.collectedAt
|
|
114228
|
+
})),
|
|
114229
|
+
lineage: lineageIds,
|
|
114230
|
+
...reply.receiptId || reply.aciIdentity ? {
|
|
114231
|
+
inference: {
|
|
114232
|
+
...reply.receiptId ? { receiptId: reply.receiptId } : {},
|
|
114233
|
+
...reply.aciIdentity ? { aciIdentity: reply.aciIdentity } : {}
|
|
114234
|
+
}
|
|
114235
|
+
} : {}
|
|
114236
|
+
};
|
|
114237
|
+
const lineage = {
|
|
114238
|
+
sources: lineageIds,
|
|
114239
|
+
writtenAt: computedAt
|
|
114240
|
+
};
|
|
114241
|
+
const collectedAt2 = collectedAtStamp(now, (candidate) => deps.storage.findEntry({
|
|
114242
|
+
scope: registration.derivedScope,
|
|
114243
|
+
at: candidate
|
|
114244
|
+
})?.collectedAt === candidate);
|
|
114245
|
+
const written = await ingestDataContract({
|
|
114246
|
+
storage: deps.storage,
|
|
114247
|
+
scopeParam: registration.derivedScope,
|
|
114248
|
+
body: record2,
|
|
114249
|
+
collectedAt: collectedAt2,
|
|
114250
|
+
status: deps.syncManager ? "syncing" : "stored",
|
|
114251
|
+
lineage,
|
|
114252
|
+
afterTombstoneVersion: await tombstoneMarker(deps.scopeDeletions, registration.derivedScope)
|
|
114253
|
+
});
|
|
114254
|
+
if (!written.ok) {
|
|
114255
|
+
throw new ComputeFailure(`derived record rejected: ${written.body.error}`);
|
|
114256
|
+
}
|
|
114257
|
+
const entry = deps.storage.findEntry({
|
|
114258
|
+
scope: registration.derivedScope,
|
|
114259
|
+
at: collectedAt2
|
|
114260
|
+
});
|
|
114261
|
+
const updated = await deps.store.update(questionId, {
|
|
114262
|
+
status: "ready",
|
|
114263
|
+
error: null,
|
|
114264
|
+
updatedAt: computedAt,
|
|
114265
|
+
lastComputedAt: computedAt,
|
|
114266
|
+
derivedVersion: entry?.version ?? null,
|
|
114267
|
+
derivedCollectedAt: collectedAt2
|
|
114268
|
+
});
|
|
114269
|
+
if (deps.syncManager?.notifyNewData) {
|
|
114270
|
+
deps.syncManager.notifyNewData();
|
|
114271
|
+
} else if (deps.syncManager?.trigger) {
|
|
114272
|
+
void deps.syncManager.trigger().catch(() => void 0);
|
|
114273
|
+
}
|
|
114274
|
+
try {
|
|
114275
|
+
deps.onDerivedWritten?.({
|
|
114276
|
+
scope: registration.derivedScope,
|
|
114277
|
+
collectedAt: collectedAt2,
|
|
114278
|
+
lineageSources: lineageIds
|
|
114279
|
+
});
|
|
114280
|
+
} catch (err2) {
|
|
114281
|
+
deps.logger?.warn?.({
|
|
114282
|
+
questionId,
|
|
114283
|
+
derivedScope: registration.derivedScope,
|
|
114284
|
+
error: err2 instanceof Error ? err2.name : String(err2)
|
|
114285
|
+
}, "onDerivedWritten hook failed; derivative already written");
|
|
114286
|
+
}
|
|
114287
|
+
deps.logger?.info?.({
|
|
114288
|
+
questionId,
|
|
114289
|
+
derivedScope: registration.derivedScope,
|
|
114290
|
+
sourceScopes: registration.sourceScopes,
|
|
114291
|
+
model,
|
|
114292
|
+
version: entry?.version ?? null,
|
|
114293
|
+
receiptId: reply.receiptId ?? null
|
|
114294
|
+
}, "Derivative question computed");
|
|
114295
|
+
return {
|
|
114296
|
+
status: "ready",
|
|
114297
|
+
registration: updated ?? { ...registration, status: "ready" }
|
|
114298
|
+
};
|
|
114299
|
+
} catch (err2) {
|
|
114300
|
+
const error51 = shortError(err2);
|
|
114301
|
+
const at3 = now().toISOString();
|
|
114302
|
+
const updated = await deps.store.update(questionId, {
|
|
114303
|
+
status: "failed",
|
|
114304
|
+
error: error51,
|
|
114305
|
+
updatedAt: at3
|
|
114306
|
+
});
|
|
114307
|
+
deps.logger?.warn?.({ questionId, derivedScope: registration.derivedScope, error: error51 }, "Derivative question compute failed");
|
|
114308
|
+
return {
|
|
114309
|
+
status: "failed",
|
|
114310
|
+
registration: updated ?? { ...registration, status: "failed", error: error51 },
|
|
114311
|
+
error: error51
|
|
114312
|
+
};
|
|
114313
|
+
}
|
|
114314
|
+
}
|
|
114315
|
+
|
|
114316
|
+
// ../core/dist/derivatives/scheduler.js
|
|
114317
|
+
var defaultTimers = {
|
|
114318
|
+
setTimeout: (callback, ms3) => setTimeout(callback, ms3),
|
|
114319
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
114320
|
+
};
|
|
114321
|
+
function createRecomputeScheduler(options) {
|
|
114322
|
+
const debounceMs = options.debounceMs ?? 5e3;
|
|
114323
|
+
const timers = options.timers ?? defaultTimers;
|
|
114324
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
114325
|
+
const states = /* @__PURE__ */ new Map();
|
|
114326
|
+
const pending = /* @__PURE__ */ new Set();
|
|
114327
|
+
let stopped = false;
|
|
114328
|
+
function track(promise2) {
|
|
114329
|
+
pending.add(promise2);
|
|
114330
|
+
const done = () => pending.delete(promise2);
|
|
114331
|
+
promise2.then(done, done);
|
|
114332
|
+
return promise2;
|
|
114333
|
+
}
|
|
114334
|
+
function warn(payload, message) {
|
|
114335
|
+
options.logger?.warn?.(payload, message);
|
|
114336
|
+
}
|
|
114337
|
+
function stateFor(questionId) {
|
|
114338
|
+
let state = states.get(questionId);
|
|
114339
|
+
if (!state) {
|
|
114340
|
+
state = { timer: null, running: null, rerun: false };
|
|
114341
|
+
states.set(questionId, state);
|
|
114342
|
+
}
|
|
114343
|
+
return state;
|
|
114344
|
+
}
|
|
114345
|
+
function run(questionId) {
|
|
114346
|
+
if (stopped)
|
|
114347
|
+
return;
|
|
114348
|
+
const state = stateFor(questionId);
|
|
114349
|
+
if (state.running) {
|
|
114350
|
+
state.rerun = true;
|
|
114351
|
+
return;
|
|
114352
|
+
}
|
|
114353
|
+
state.running = track(Promise.resolve().then(() => options.compute(questionId)).then(() => void 0, (err2) => warn({
|
|
114354
|
+
questionId,
|
|
114355
|
+
error: err2 instanceof Error ? err2.name : String(err2)
|
|
114356
|
+
}, "Derivative compute threw")).then(async () => {
|
|
114357
|
+
state.running = null;
|
|
114358
|
+
if (state.rerun) {
|
|
114359
|
+
state.rerun = false;
|
|
114360
|
+
await markStale(questionId);
|
|
114361
|
+
schedule(questionId, 0);
|
|
114362
|
+
} else if (!states.get(questionId)?.timer) {
|
|
114363
|
+
states.delete(questionId);
|
|
114364
|
+
}
|
|
114365
|
+
}));
|
|
114366
|
+
}
|
|
114367
|
+
function schedule(questionId, delayMs) {
|
|
114368
|
+
if (stopped)
|
|
114369
|
+
return;
|
|
114370
|
+
const state = stateFor(questionId);
|
|
114371
|
+
if (state.timer !== null)
|
|
114372
|
+
timers.clearTimeout(state.timer);
|
|
114373
|
+
state.timer = timers.setTimeout(() => {
|
|
114374
|
+
state.timer = null;
|
|
114375
|
+
run(questionId);
|
|
114376
|
+
}, delayMs);
|
|
114377
|
+
}
|
|
114378
|
+
async function markStale(questionId) {
|
|
114379
|
+
const registration = await options.store.get(questionId);
|
|
114380
|
+
if (!registration)
|
|
114381
|
+
return;
|
|
114382
|
+
if (registration.status === "ready" || registration.status === "failed") {
|
|
114383
|
+
await options.store.update(questionId, {
|
|
114384
|
+
status: "stale",
|
|
114385
|
+
updatedAt: now().toISOString()
|
|
114386
|
+
});
|
|
114387
|
+
}
|
|
114388
|
+
}
|
|
114389
|
+
return {
|
|
114390
|
+
markSourceChanged(scope, opts) {
|
|
114391
|
+
if (stopped)
|
|
114392
|
+
return;
|
|
114393
|
+
const lineage = new Set((opts?.lineageSources ?? []).map((id2) => id2.toLowerCase()));
|
|
114394
|
+
void track((async () => {
|
|
114395
|
+
const affected = await options.store.list({ sourceScope: scope });
|
|
114396
|
+
for (const registration of affected) {
|
|
114397
|
+
if (options.serverOwner && lineage.has(computeDataPointId(options.serverOwner, registration.derivedScope))) {
|
|
114398
|
+
continue;
|
|
114399
|
+
}
|
|
114400
|
+
await markStale(registration.questionId);
|
|
114401
|
+
schedule(registration.questionId, debounceMs);
|
|
114402
|
+
}
|
|
114403
|
+
})().catch((err2) => warn({ scope, error: err2 instanceof Error ? err2.name : String(err2) }, "Could not mark derivative questions stale")));
|
|
114404
|
+
},
|
|
114405
|
+
requestRecompute(questionId, opts) {
|
|
114406
|
+
if (stopped)
|
|
114407
|
+
return;
|
|
114408
|
+
void track(markStale(questionId).catch((err2) => warn({
|
|
114409
|
+
questionId,
|
|
114410
|
+
error: err2 instanceof Error ? err2.name : String(err2)
|
|
114411
|
+
}, "Could not mark derivative question stale")).then(() => schedule(questionId, opts?.immediate ? 0 : debounceMs)));
|
|
114412
|
+
},
|
|
114413
|
+
async whenIdle() {
|
|
114414
|
+
const waitForTimers = !options.timers;
|
|
114415
|
+
for (; ; ) {
|
|
114416
|
+
while (pending.size > 0) {
|
|
114417
|
+
await Promise.allSettled([...pending]);
|
|
114418
|
+
}
|
|
114419
|
+
const busy = [...states.values()].some((state) => state.running !== null || waitForTimers && state.timer !== null);
|
|
114420
|
+
if (!busy)
|
|
114421
|
+
return;
|
|
114422
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
114423
|
+
}
|
|
114424
|
+
},
|
|
114425
|
+
stop() {
|
|
114426
|
+
stopped = true;
|
|
114427
|
+
for (const state of states.values()) {
|
|
114428
|
+
if (state.timer !== null)
|
|
114429
|
+
timers.clearTimeout(state.timer);
|
|
114430
|
+
state.timer = null;
|
|
114431
|
+
}
|
|
114432
|
+
},
|
|
114433
|
+
start() {
|
|
114434
|
+
if (!stopped)
|
|
114435
|
+
return;
|
|
114436
|
+
stopped = false;
|
|
114437
|
+
void track((async () => {
|
|
114438
|
+
for (const registration of await options.store.list()) {
|
|
114439
|
+
if (registration.status === "pending" || registration.status === "stale") {
|
|
114440
|
+
schedule(registration.questionId, 0);
|
|
114441
|
+
}
|
|
114442
|
+
}
|
|
114443
|
+
})().catch((err2) => warn({ error: err2 instanceof Error ? err2.name : String(err2) }, "Could not reschedule derivative questions")));
|
|
114444
|
+
}
|
|
114445
|
+
};
|
|
114446
|
+
}
|
|
114447
|
+
|
|
114448
|
+
// ../core/dist/derivatives/api.js
|
|
114449
|
+
var MAX_QUESTION_BODY_BYTES = 16 * 1024;
|
|
114450
|
+
function jsonResponse2(body, init) {
|
|
114451
|
+
const headers = new Headers(init?.headers);
|
|
114452
|
+
headers.set("Content-Type", "application/json");
|
|
114453
|
+
return new Response(JSON.stringify(body), { ...init, headers });
|
|
114454
|
+
}
|
|
114455
|
+
function errorResponse2(status2, errorCode, message) {
|
|
114456
|
+
return jsonResponse2({ error: { code: status2, errorCode, message } }, { status: status2 });
|
|
114457
|
+
}
|
|
114458
|
+
function stripBasePath2(pathname, basePath) {
|
|
114459
|
+
if (!basePath || basePath === "/")
|
|
114460
|
+
return pathname;
|
|
114461
|
+
if (pathname === basePath)
|
|
114462
|
+
return "/";
|
|
114463
|
+
if (pathname.startsWith(`${basePath}/`))
|
|
114464
|
+
return pathname.slice(basePath.length);
|
|
114465
|
+
return pathname;
|
|
114466
|
+
}
|
|
114467
|
+
async function authorizeOwnerOrWriter(deps, request2, scope) {
|
|
114468
|
+
if (deps.auth.authorizeWrite) {
|
|
114469
|
+
return await deps.auth.authorizeWrite({ request: request2, scope }) ?? void 0;
|
|
114470
|
+
}
|
|
114471
|
+
await deps.auth.authorizeOwner(request2);
|
|
114472
|
+
return void 0;
|
|
114473
|
+
}
|
|
114474
|
+
function sameBuilder(a10, b10) {
|
|
114475
|
+
return a10.toLowerCase() === b10.toLowerCase();
|
|
114476
|
+
}
|
|
114477
|
+
async function loadForCaller(deps, request2, store, questionId) {
|
|
114478
|
+
const registration = await store.get(questionId);
|
|
114479
|
+
if (!registration) {
|
|
114480
|
+
await deps.auth.authorizeOwner(request2);
|
|
114481
|
+
throw new DerivativeQuestionNotFoundError({ questionId });
|
|
114482
|
+
}
|
|
114483
|
+
const writer = await authorizeOwnerOrWriter(deps, request2, registration.derivedScope);
|
|
114484
|
+
if (writer) {
|
|
114485
|
+
const by2 = registration.registeredBy;
|
|
114486
|
+
if (by2.kind !== "builder" || !sameBuilder(by2.builder, writer.builder)) {
|
|
114487
|
+
await writer.releaseProof?.();
|
|
114488
|
+
throw new DerivativeQuestionNotFoundError({ questionId });
|
|
114489
|
+
}
|
|
114490
|
+
}
|
|
114491
|
+
return { registration, writer };
|
|
114492
|
+
}
|
|
114493
|
+
async function handlePersonalServerDerivativesRequest(request2, deps, options = {}) {
|
|
114494
|
+
try {
|
|
114495
|
+
const url2 = new URL(request2.url);
|
|
114496
|
+
const pathname = stripBasePath2(url2.pathname, options.basePath);
|
|
114497
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
114498
|
+
if (parts[0] !== "questions" || parts.length > 3) {
|
|
114499
|
+
return errorResponse2(404, "NOT_FOUND", "Not found");
|
|
114500
|
+
}
|
|
114501
|
+
const compute = deps.compute;
|
|
114502
|
+
if (!compute)
|
|
114503
|
+
throw new DerivativeComputeUnavailableError();
|
|
114504
|
+
const { store, scheduler } = compute;
|
|
114505
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
114506
|
+
if (parts.length === 1) {
|
|
114507
|
+
if (request2.method === "GET") {
|
|
114508
|
+
const derivedScope = url2.searchParams.get("derivedScope") ?? void 0;
|
|
114509
|
+
if (derivedScope) {
|
|
114510
|
+
const writer = await authorizeOwnerOrWriter(deps, request2, derivedScope);
|
|
114511
|
+
const registrations2 = await store.list({
|
|
114512
|
+
derivedScope,
|
|
114513
|
+
...writer ? { builder: writer.builder } : {}
|
|
114514
|
+
});
|
|
114515
|
+
return jsonResponse2({
|
|
114516
|
+
questions: registrations2.map(questionRegistrationView)
|
|
114517
|
+
});
|
|
114518
|
+
}
|
|
114519
|
+
await deps.auth.authorizeOwner(request2);
|
|
114520
|
+
const registrations = await store.list();
|
|
114521
|
+
return jsonResponse2({
|
|
114522
|
+
questions: registrations.map(questionRegistrationView)
|
|
114523
|
+
});
|
|
114524
|
+
}
|
|
114525
|
+
if (request2.method === "POST") {
|
|
114526
|
+
const declared = Number(request2.headers.get("content-length") ?? "0");
|
|
114527
|
+
if (declared > MAX_QUESTION_BODY_BYTES) {
|
|
114528
|
+
throw new ContentTooLargeError({ max: MAX_QUESTION_BODY_BYTES });
|
|
114529
|
+
}
|
|
114530
|
+
const bodyBytes = new Uint8Array(await request2.clone().arrayBuffer());
|
|
114531
|
+
if (bodyBytes.byteLength > MAX_QUESTION_BODY_BYTES) {
|
|
114532
|
+
throw new ContentTooLargeError({ max: MAX_QUESTION_BODY_BYTES });
|
|
114533
|
+
}
|
|
114534
|
+
const parsed = await parseJsonObjectBody(request2.clone(), "Request body must be valid JSON");
|
|
114535
|
+
if (!parsed.ok) {
|
|
114536
|
+
return jsonResponse2(parsed.result.body, {
|
|
114537
|
+
status: parsed.result.status
|
|
114538
|
+
});
|
|
114539
|
+
}
|
|
114540
|
+
const rawScope = parsed.body.derivedScope;
|
|
114541
|
+
const scopeForAuth = typeof rawScope === "string" ? rawScope : "";
|
|
114542
|
+
const writer = await authorizeOwnerOrWriter(deps, request2, scopeForAuth);
|
|
114543
|
+
const registeredBy = writer ? {
|
|
114544
|
+
kind: "builder",
|
|
114545
|
+
builder: writer.builder,
|
|
114546
|
+
grantId: writer.grantId
|
|
114547
|
+
} : { kind: "owner" };
|
|
114548
|
+
let registration;
|
|
114549
|
+
try {
|
|
114550
|
+
if (writer) {
|
|
114551
|
+
const input = parseQuestionInput(parsed.body);
|
|
114552
|
+
const uncovered = uncoveredSourceScopes(input.sourceScopes, writer.grantScopes);
|
|
114553
|
+
if (uncovered.length > 0) {
|
|
114554
|
+
throw new DerivativeSourceNotGrantedError({ scopes: uncovered });
|
|
114555
|
+
}
|
|
114556
|
+
}
|
|
114557
|
+
registration = await createQuestionRegistration({
|
|
114558
|
+
body: parsed.body,
|
|
114559
|
+
registeredBy,
|
|
114560
|
+
store,
|
|
114561
|
+
questionId: deps.createQuestionId?.() ?? crypto.randomUUID(),
|
|
114562
|
+
now
|
|
114563
|
+
});
|
|
114564
|
+
} catch (err2) {
|
|
114565
|
+
await writer?.releaseProof?.();
|
|
114566
|
+
throw err2;
|
|
114567
|
+
}
|
|
114568
|
+
deps.logger?.info?.({
|
|
114569
|
+
questionId: registration.questionId,
|
|
114570
|
+
derivedScope: registration.derivedScope,
|
|
114571
|
+
sourceScopes: registration.sourceScopes,
|
|
114572
|
+
registeredBy: registeredBy.kind,
|
|
114573
|
+
...writer ? { builder: writer.builder, grantId: writer.grantId } : {}
|
|
114574
|
+
}, "Derivative question registered");
|
|
114575
|
+
scheduler.requestRecompute(registration.questionId, {
|
|
114576
|
+
immediate: true
|
|
114577
|
+
});
|
|
114578
|
+
return jsonResponse2(questionRegistrationView(registration), {
|
|
114579
|
+
status: 201
|
|
114580
|
+
});
|
|
114581
|
+
}
|
|
114582
|
+
return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
114583
|
+
}
|
|
114584
|
+
const questionId = decodeURIComponent(parts[1] ?? "");
|
|
114585
|
+
if (parts.length === 3) {
|
|
114586
|
+
if (parts[2] !== "recompute") {
|
|
114587
|
+
return errorResponse2(404, "NOT_FOUND", "Not found");
|
|
114588
|
+
}
|
|
114589
|
+
if (request2.method !== "POST") {
|
|
114590
|
+
return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
114591
|
+
}
|
|
114592
|
+
const { registration } = await loadForCaller(deps, request2, store, questionId);
|
|
114593
|
+
scheduler.requestRecompute(questionId, { immediate: true });
|
|
114594
|
+
return jsonResponse2({
|
|
114595
|
+
questionId,
|
|
114596
|
+
status: registration.status === "pending" ? "pending" : "stale",
|
|
114597
|
+
derivedScope: registration.derivedScope
|
|
114598
|
+
}, { status: 202 });
|
|
114599
|
+
}
|
|
114600
|
+
if (request2.method === "GET") {
|
|
114601
|
+
const { registration } = await loadForCaller(deps, request2, store, questionId);
|
|
114602
|
+
return jsonResponse2(questionRegistrationView(registration));
|
|
114603
|
+
}
|
|
114604
|
+
if (request2.method === "DELETE") {
|
|
114605
|
+
const { registration } = await loadForCaller(deps, request2, store, questionId);
|
|
114606
|
+
await store.delete(questionId);
|
|
114607
|
+
deps.logger?.info?.({ questionId, derivedScope: registration.derivedScope }, "Derivative question deleted");
|
|
114608
|
+
return jsonResponse2({ questionId, deleted: true });
|
|
114609
|
+
}
|
|
114610
|
+
return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
114611
|
+
} catch (err2) {
|
|
114612
|
+
if (err2 instanceof ProtocolError) {
|
|
114613
|
+
return jsonResponse2(err2.toJSON(), { status: err2.code });
|
|
114614
|
+
}
|
|
114615
|
+
return errorResponse2(500, "INTERNAL_ERROR", "Internal server error");
|
|
114616
|
+
}
|
|
114617
|
+
}
|
|
114618
|
+
|
|
113385
114619
|
// ../core/dist/mcp/store.js
|
|
113386
114620
|
function createInMemoryMcpOAuthAuthorizationStore() {
|
|
113387
114621
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -124090,7 +125324,7 @@ var Protocol = class {
|
|
|
124090
125324
|
const capturedTransport = this._transport;
|
|
124091
125325
|
const relatedTaskId = request2.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
124092
125326
|
if (handler === void 0) {
|
|
124093
|
-
const
|
|
125327
|
+
const errorResponse4 = {
|
|
124094
125328
|
jsonrpc: "2.0",
|
|
124095
125329
|
id: request2.id,
|
|
124096
125330
|
error: {
|
|
@@ -124101,11 +125335,11 @@ var Protocol = class {
|
|
|
124101
125335
|
if (relatedTaskId && this._taskMessageQueue) {
|
|
124102
125336
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
124103
125337
|
type: "error",
|
|
124104
|
-
message:
|
|
125338
|
+
message: errorResponse4,
|
|
124105
125339
|
timestamp: Date.now()
|
|
124106
125340
|
}, capturedTransport?.sessionId).catch((error51) => this._onerror(new Error(`Failed to enqueue error response: ${error51}`)));
|
|
124107
125341
|
} else {
|
|
124108
|
-
capturedTransport?.send(
|
|
125342
|
+
capturedTransport?.send(errorResponse4).catch((error51) => this._onerror(new Error(`Failed to send an error response: ${error51}`)));
|
|
124109
125343
|
}
|
|
124110
125344
|
return;
|
|
124111
125345
|
}
|
|
@@ -124175,7 +125409,7 @@ var Protocol = class {
|
|
|
124175
125409
|
if (abortController.signal.aborted) {
|
|
124176
125410
|
return;
|
|
124177
125411
|
}
|
|
124178
|
-
const
|
|
125412
|
+
const errorResponse4 = {
|
|
124179
125413
|
jsonrpc: "2.0",
|
|
124180
125414
|
id: request2.id,
|
|
124181
125415
|
error: {
|
|
@@ -124187,11 +125421,11 @@ var Protocol = class {
|
|
|
124187
125421
|
if (relatedTaskId && this._taskMessageQueue) {
|
|
124188
125422
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
124189
125423
|
type: "error",
|
|
124190
|
-
message:
|
|
125424
|
+
message: errorResponse4,
|
|
124191
125425
|
timestamp: Date.now()
|
|
124192
125426
|
}, capturedTransport?.sessionId);
|
|
124193
125427
|
} else {
|
|
124194
|
-
await capturedTransport?.send(
|
|
125428
|
+
await capturedTransport?.send(errorResponse4);
|
|
124195
125429
|
}
|
|
124196
125430
|
}).catch((error51) => this._onerror(new Error(`Failed to send response: ${error51}`))).finally(() => {
|
|
124197
125431
|
if (this._requestHandlerAbortControllers.get(request2.id) === abortController) {
|
|
@@ -127814,16 +129048,16 @@ async function collectDiagnosticsWithTimeout(recorder, options, timeoutMs = DIAG
|
|
|
127814
129048
|
}
|
|
127815
129049
|
|
|
127816
129050
|
// ../lite/dist/runtime.js
|
|
127817
|
-
function
|
|
129051
|
+
function jsonResponse3(body, init) {
|
|
127818
129052
|
const headers = new Headers(init?.headers);
|
|
127819
129053
|
headers.set("Content-Type", "application/json");
|
|
127820
129054
|
return new Response(JSON.stringify(body), { ...init, headers });
|
|
127821
129055
|
}
|
|
127822
129056
|
function protocolErrorResponse2(err2) {
|
|
127823
|
-
return
|
|
129057
|
+
return jsonResponse3(err2.toJSON(), { status: err2.code });
|
|
127824
129058
|
}
|
|
127825
|
-
function
|
|
127826
|
-
return
|
|
129059
|
+
function errorResponse3(status2, errorCode, message) {
|
|
129060
|
+
return jsonResponse3({
|
|
127827
129061
|
error: {
|
|
127828
129062
|
code: status2,
|
|
127829
129063
|
errorCode,
|
|
@@ -127832,7 +129066,7 @@ function errorResponse2(status2, errorCode, message) {
|
|
|
127832
129066
|
}, { status: status2 });
|
|
127833
129067
|
}
|
|
127834
129068
|
function mcpUnauthorized(origin, message = "MCP authorization required") {
|
|
127835
|
-
return
|
|
129069
|
+
return jsonResponse3({
|
|
127836
129070
|
error: {
|
|
127837
129071
|
code: 401,
|
|
127838
129072
|
errorCode: "MCP_AUTH_REQUIRED",
|
|
@@ -127881,7 +129115,7 @@ function redirectWithOAuthError(redirectUri, error51, description, state) {
|
|
|
127881
129115
|
url2.searchParams.set("state", state);
|
|
127882
129116
|
return Response.redirect(url2.toString(), 302);
|
|
127883
129117
|
} catch {
|
|
127884
|
-
return
|
|
129118
|
+
return jsonResponse3({
|
|
127885
129119
|
error: error51,
|
|
127886
129120
|
error_description: description,
|
|
127887
129121
|
...state ? { state } : {}
|
|
@@ -128087,11 +129321,11 @@ function createPsLiteRuntime(options) {
|
|
|
128087
129321
|
if (err2 instanceof ProtocolError) {
|
|
128088
129322
|
return protocolErrorResponse2(err2);
|
|
128089
129323
|
}
|
|
128090
|
-
return
|
|
129324
|
+
return errorResponse3(500, "INTERNAL_ERROR", "Internal server error");
|
|
128091
129325
|
}
|
|
128092
129326
|
}
|
|
128093
129327
|
function sendContractResult(result) {
|
|
128094
|
-
return
|
|
129328
|
+
return jsonResponse3(result.body, { status: result.status });
|
|
128095
129329
|
}
|
|
128096
129330
|
function ownerAddress() {
|
|
128097
129331
|
return options.serverOwner ?? options.identity?.address;
|
|
@@ -128099,7 +129333,7 @@ function createPsLiteRuntime(options) {
|
|
|
128099
129333
|
async function handleAuthDevice(request2, url2) {
|
|
128100
129334
|
if (url2.pathname === "/auth/device") {
|
|
128101
129335
|
if (request2.method !== "POST") {
|
|
128102
|
-
return
|
|
129336
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128103
129337
|
}
|
|
128104
129338
|
return sendContractResult(initiateDeviceSessionContract({
|
|
128105
129339
|
sessionStore: deviceSessions,
|
|
@@ -128113,7 +129347,7 @@ function createPsLiteRuntime(options) {
|
|
|
128113
129347
|
}
|
|
128114
129348
|
if (url2.pathname === "/auth/device/poll") {
|
|
128115
129349
|
if (request2.method !== "GET") {
|
|
128116
|
-
return
|
|
129350
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128117
129351
|
}
|
|
128118
129352
|
return sendContractResult(pollDeviceSessionContract({
|
|
128119
129353
|
sessionStore: deviceSessions,
|
|
@@ -128125,11 +129359,11 @@ function createPsLiteRuntime(options) {
|
|
|
128125
129359
|
if (url2.pathname === "/auth/device/approve") {
|
|
128126
129360
|
const sessionId = url2.searchParams.get("session");
|
|
128127
129361
|
if (!sessionId) {
|
|
128128
|
-
return request2.method === "GET" ? new Response("Missing session parameter", { status: 400 }) :
|
|
129362
|
+
return request2.method === "GET" ? new Response("Missing session parameter", { status: 400 }) : jsonResponse3({ error: { code: 400, message: "Missing session parameter" } }, { status: 400 });
|
|
128129
129363
|
}
|
|
128130
129364
|
const session = deviceSessions.get(sessionId);
|
|
128131
129365
|
if (!session) {
|
|
128132
|
-
return request2.method === "GET" ? new Response("Session expired or invalid", { status: 404 }) :
|
|
129366
|
+
return request2.method === "GET" ? new Response("Session expired or invalid", { status: 404 }) : jsonResponse3({ error: { code: 404, message: "Session expired or invalid" } }, { status: 404 });
|
|
128133
129367
|
}
|
|
128134
129368
|
if (request2.method === "GET") {
|
|
128135
129369
|
return new Response("Device authorization pending", {
|
|
@@ -128137,10 +129371,10 @@ function createPsLiteRuntime(options) {
|
|
|
128137
129371
|
});
|
|
128138
129372
|
}
|
|
128139
129373
|
if (request2.method !== "POST") {
|
|
128140
|
-
return
|
|
129374
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128141
129375
|
}
|
|
128142
129376
|
if (session.status === "approved") {
|
|
128143
|
-
return
|
|
129377
|
+
return jsonResponse3({ status: "already_approved" });
|
|
128144
129378
|
}
|
|
128145
129379
|
await auth.authorizeOwner(request2);
|
|
128146
129380
|
return sendContractResult(await approveDeviceSessionContract({
|
|
@@ -128156,7 +129390,7 @@ function createPsLiteRuntime(options) {
|
|
|
128156
129390
|
if (request2.method === "DELETE") {
|
|
128157
129391
|
const token2 = bearerToken(request2);
|
|
128158
129392
|
if (!token2) {
|
|
128159
|
-
return
|
|
129393
|
+
return jsonResponse3({ error: { code: 401, message: "Missing Bearer token" } }, { status: 401 });
|
|
128160
129394
|
}
|
|
128161
129395
|
return sendContractResult(await revokeDeviceTokenContract({
|
|
128162
129396
|
tokenStore,
|
|
@@ -128164,11 +129398,11 @@ function createPsLiteRuntime(options) {
|
|
|
128164
129398
|
}));
|
|
128165
129399
|
}
|
|
128166
129400
|
if (request2.method !== "POST") {
|
|
128167
|
-
return
|
|
129401
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128168
129402
|
}
|
|
128169
129403
|
const token = bearerToken(request2);
|
|
128170
129404
|
if (!options.accessToken || token !== options.accessToken) {
|
|
128171
|
-
return
|
|
129405
|
+
return jsonResponse3({
|
|
128172
129406
|
error: {
|
|
128173
129407
|
code: 403,
|
|
128174
129408
|
message: "Only control-plane tokens can provision Personal Server session tokens"
|
|
@@ -128179,10 +129413,10 @@ function createPsLiteRuntime(options) {
|
|
|
128179
129413
|
try {
|
|
128180
129414
|
body = await request2.json();
|
|
128181
129415
|
} catch {
|
|
128182
|
-
return
|
|
129416
|
+
return jsonResponse3({ error: { code: 400, message: "Request body must be valid JSON" } }, { status: 400 });
|
|
128183
129417
|
}
|
|
128184
129418
|
if (!body.token || typeof body.token !== "string") {
|
|
128185
|
-
return
|
|
129419
|
+
return jsonResponse3({ error: { code: 400, message: "Missing token" } }, { status: 400 });
|
|
128186
129420
|
}
|
|
128187
129421
|
return sendContractResult(await provisionDeviceTokenContract({
|
|
128188
129422
|
tokenStore,
|
|
@@ -128198,10 +129432,12 @@ function createPsLiteRuntime(options) {
|
|
|
128198
129432
|
activate() {
|
|
128199
129433
|
active = true;
|
|
128200
129434
|
options.syncManager?.start?.();
|
|
129435
|
+
options.derivatives?.scheduler.start();
|
|
128201
129436
|
},
|
|
128202
129437
|
deactivate() {
|
|
128203
129438
|
active = false;
|
|
128204
129439
|
void options.syncManager?.stop?.();
|
|
129440
|
+
options.derivatives?.scheduler.stop();
|
|
128205
129441
|
},
|
|
128206
129442
|
isAvailable() {
|
|
128207
129443
|
return active;
|
|
@@ -128235,7 +129471,7 @@ function createPsLiteRuntime(options) {
|
|
|
128235
129471
|
accessLogs: accessLogReader.capabilities?.accessLogs ?? "custom",
|
|
128236
129472
|
config: options.stateCapabilities?.config ?? (options.saveConfig ? "custom" : "indexeddb")
|
|
128237
129473
|
};
|
|
128238
|
-
return
|
|
129474
|
+
return jsonResponse3({
|
|
128239
129475
|
status: active ? "healthy" : "unavailable",
|
|
128240
129476
|
runtime: "ps-lite",
|
|
128241
129477
|
storage: options.storage.kind,
|
|
@@ -128253,7 +129489,7 @@ function createPsLiteRuntime(options) {
|
|
|
128253
129489
|
}
|
|
128254
129490
|
if (url2.pathname === "/v1/diagnostics") {
|
|
128255
129491
|
if (request2.method !== "GET") {
|
|
128256
|
-
return
|
|
129492
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128257
129493
|
}
|
|
128258
129494
|
try {
|
|
128259
129495
|
await auth.authorizeOwner(request2);
|
|
@@ -128264,7 +129500,7 @@ function createPsLiteRuntime(options) {
|
|
|
128264
129500
|
throw err2;
|
|
128265
129501
|
}
|
|
128266
129502
|
if (!options.diagnostics) {
|
|
128267
|
-
return
|
|
129503
|
+
return jsonResponse3({
|
|
128268
129504
|
error: {
|
|
128269
129505
|
code: 404,
|
|
128270
129506
|
errorCode: "DIAGNOSTICS_NOT_CONFIGURED",
|
|
@@ -128278,7 +129514,7 @@ function createPsLiteRuntime(options) {
|
|
|
128278
129514
|
syncStatus: syncStatus2,
|
|
128279
129515
|
storage: dataStorage
|
|
128280
129516
|
});
|
|
128281
|
-
return
|
|
129517
|
+
return jsonResponse3(snapshot);
|
|
128282
129518
|
}
|
|
128283
129519
|
if (!active) {
|
|
128284
129520
|
return unavailableResponse();
|
|
@@ -128313,9 +129549,16 @@ function createPsLiteRuntime(options) {
|
|
|
128313
129549
|
// serverOwner is absent the accessRecord is safely omitted.
|
|
128314
129550
|
serverOwner: options.serverOwner,
|
|
128315
129551
|
serverSigner: x402ServerSigner,
|
|
128316
|
-
lineageGateway: options.lineageGateway
|
|
129552
|
+
lineageGateway: options.lineageGateway,
|
|
129553
|
+
// Recompute on refresh: a new local version marks every
|
|
129554
|
+
// question that reads the scope stale.
|
|
129555
|
+
onDataWritten: options.derivatives ? (event) => options.derivatives?.scheduler.markSourceChanged(event.scope, { lineageSources: event.lineageSources }) : void 0
|
|
128317
129556
|
}, { basePath: dataPrefix });
|
|
128318
129557
|
}
|
|
129558
|
+
const derivativesPrefix = "/v1/derivatives";
|
|
129559
|
+
if (url2.pathname.startsWith(`${derivativesPrefix}/`)) {
|
|
129560
|
+
return handlePersonalServerDerivativesRequest(request2, { auth, compute: options.derivatives ?? null, now }, { basePath: derivativesPrefix });
|
|
129561
|
+
}
|
|
128319
129562
|
if (url2.pathname.startsWith("/auth/device")) {
|
|
128320
129563
|
const response = await handleAuthDevice(request2, url2);
|
|
128321
129564
|
if (response)
|
|
@@ -128404,7 +129647,7 @@ function createPsLiteRuntime(options) {
|
|
|
128404
129647
|
if (mcpResponse)
|
|
128405
129648
|
return mcpResponse;
|
|
128406
129649
|
}
|
|
128407
|
-
return
|
|
129650
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128408
129651
|
});
|
|
128409
129652
|
}
|
|
128410
129653
|
};
|
|
@@ -128415,22 +129658,22 @@ async function handleMcpRoute(input) {
|
|
|
128415
129658
|
const ownerAuthorizationPrefix = "/v1/mcp/oauth/authorizations";
|
|
128416
129659
|
if (pathname === "/.well-known/oauth-protected-resource/mcp") {
|
|
128417
129660
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
128418
|
-
return
|
|
129661
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
128419
129662
|
}
|
|
128420
|
-
return
|
|
129663
|
+
return jsonResponse3(protectedResourceMetadata(input.serverOrigin));
|
|
128421
129664
|
}
|
|
128422
129665
|
if (pathname === "/.well-known/oauth-authorization-server") {
|
|
128423
129666
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
128424
|
-
return
|
|
129667
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
128425
129668
|
}
|
|
128426
|
-
return
|
|
129669
|
+
return jsonResponse3(authorizationServerMetadata(input.serverOrigin));
|
|
128427
129670
|
}
|
|
128428
129671
|
if (pathname === "/mcp/oauth/register") {
|
|
128429
129672
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
128430
|
-
return
|
|
129673
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
128431
129674
|
}
|
|
128432
129675
|
if (input.request.method !== "POST") {
|
|
128433
|
-
return
|
|
129676
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128434
129677
|
}
|
|
128435
129678
|
let body = {};
|
|
128436
129679
|
try {
|
|
@@ -128438,7 +129681,7 @@ async function handleMcpRoute(input) {
|
|
|
128438
129681
|
} catch {
|
|
128439
129682
|
body = {};
|
|
128440
129683
|
}
|
|
128441
|
-
return
|
|
129684
|
+
return jsonResponse3({
|
|
128442
129685
|
client_id: `mcp-client-${crypto.randomUUID()}`,
|
|
128443
129686
|
client_name: body.client_name ?? "Claude",
|
|
128444
129687
|
redirect_uris: Array.isArray(body.redirect_uris) ? body.redirect_uris : [],
|
|
@@ -128449,10 +129692,10 @@ async function handleMcpRoute(input) {
|
|
|
128449
129692
|
}
|
|
128450
129693
|
if (pathname === "/mcp/oauth/authorize") {
|
|
128451
129694
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
128452
|
-
return
|
|
129695
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
128453
129696
|
}
|
|
128454
129697
|
if (input.request.method !== "GET") {
|
|
128455
|
-
return
|
|
129698
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128456
129699
|
}
|
|
128457
129700
|
const responseType = input.url.searchParams.get("response_type");
|
|
128458
129701
|
const clientId = input.url.searchParams.get("client_id") ?? "";
|
|
@@ -128480,7 +129723,7 @@ async function handleMcpRoute(input) {
|
|
|
128480
129723
|
});
|
|
128481
129724
|
const approvalUrl = resolveMcpApprovalUrl(input.approvalUrl);
|
|
128482
129725
|
if (!approvalUrl) {
|
|
128483
|
-
return
|
|
129726
|
+
return errorResponse3(500, "MCP_APPROVAL_URL_MISSING", "MCP OAuth approval URL is not configured");
|
|
128484
129727
|
}
|
|
128485
129728
|
const approve = new URL(approvalUrl);
|
|
128486
129729
|
approve.searchParams.set("mcp_authorization", created.authorizationId);
|
|
@@ -128493,14 +129736,14 @@ async function handleMcpRoute(input) {
|
|
|
128493
129736
|
}
|
|
128494
129737
|
if (pathname === "/mcp/oauth/token") {
|
|
128495
129738
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
128496
|
-
return
|
|
129739
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
128497
129740
|
}
|
|
128498
129741
|
if (input.request.method !== "POST") {
|
|
128499
|
-
return
|
|
129742
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128500
129743
|
}
|
|
128501
129744
|
const body = await parseFormBody(input.request);
|
|
128502
129745
|
if (body.get("grant_type") !== "authorization_code") {
|
|
128503
|
-
return
|
|
129746
|
+
return jsonResponse3({
|
|
128504
129747
|
error: "unsupported_grant_type",
|
|
128505
129748
|
error_description: "Only authorization_code is supported"
|
|
128506
129749
|
}, { status: 400 });
|
|
@@ -128516,13 +129759,13 @@ async function handleMcpRoute(input) {
|
|
|
128516
129759
|
connectionStore: input.store,
|
|
128517
129760
|
now: input.now
|
|
128518
129761
|
});
|
|
128519
|
-
return
|
|
129762
|
+
return jsonResponse3({
|
|
128520
129763
|
access_token: token.accessToken,
|
|
128521
129764
|
token_type: "Bearer",
|
|
128522
129765
|
...token.scope ? { scope: token.scope } : {}
|
|
128523
129766
|
});
|
|
128524
129767
|
} catch (err2) {
|
|
128525
|
-
return
|
|
129768
|
+
return jsonResponse3({
|
|
128526
129769
|
error: err2 instanceof McpOAuthAuthorizationError ? err2.code : "invalid_grant",
|
|
128527
129770
|
error_description: err2 instanceof Error ? err2.message : String(err2)
|
|
128528
129771
|
}, { status: 400 });
|
|
@@ -128540,28 +129783,28 @@ async function handleMcpRoute(input) {
|
|
|
128540
129783
|
const tail = pathname.slice(ownerAuthorizationPrefix.length + 1);
|
|
128541
129784
|
const [id2, action] = tail.split("/");
|
|
128542
129785
|
if (!id2) {
|
|
128543
|
-
return
|
|
129786
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128544
129787
|
}
|
|
128545
129788
|
if (!action && input.request.method === "GET") {
|
|
128546
129789
|
const record2 = await input.authorizationStore.getById(id2);
|
|
128547
129790
|
if (!record2) {
|
|
128548
|
-
return
|
|
129791
|
+
return errorResponse3(404, "NOT_FOUND", "Authorization not found");
|
|
128549
129792
|
}
|
|
128550
|
-
return
|
|
129793
|
+
return jsonResponse3(toMcpOAuthAuthorizationView(record2));
|
|
128551
129794
|
}
|
|
128552
129795
|
if (action === "approve") {
|
|
128553
129796
|
if (input.request.method !== "POST") {
|
|
128554
|
-
return
|
|
129797
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128555
129798
|
}
|
|
128556
129799
|
let body = {};
|
|
128557
129800
|
try {
|
|
128558
129801
|
body = await input.request.json();
|
|
128559
129802
|
} catch {
|
|
128560
|
-
return
|
|
129803
|
+
return errorResponse3(400, "INVALID_BODY", "Body must be JSON");
|
|
128561
129804
|
}
|
|
128562
129805
|
if (Array.isArray(body.scopes) && body.scopes.length > 0) {
|
|
128563
129806
|
if (!input.gateway || !input.gatewayConfig?.url) {
|
|
128564
|
-
return
|
|
129807
|
+
return errorResponse3(500, "SERVER_NOT_CONFIGURED", "Gateway config is not configured");
|
|
128565
129808
|
}
|
|
128566
129809
|
try {
|
|
128567
129810
|
const approved = await approveMcpOAuthAuthorizationWithScopes({
|
|
@@ -128579,16 +129822,16 @@ async function handleMcpRoute(input) {
|
|
|
128579
129822
|
serverSigner: input.serverSigner,
|
|
128580
129823
|
now: input.now
|
|
128581
129824
|
});
|
|
128582
|
-
return
|
|
129825
|
+
return jsonResponse3({ redirectTo: approved.redirectTo });
|
|
128583
129826
|
} catch (err2) {
|
|
128584
129827
|
if (err2 instanceof McpOAuthAuthorizationError) {
|
|
128585
|
-
return
|
|
129828
|
+
return errorResponse3(err2.status, err2.code, err2.message);
|
|
128586
129829
|
}
|
|
128587
129830
|
throw err2;
|
|
128588
129831
|
}
|
|
128589
129832
|
}
|
|
128590
129833
|
if (!Array.isArray(body.grants) || body.grants.length === 0) {
|
|
128591
|
-
return
|
|
129834
|
+
return errorResponse3(400, "GRANTS_REQUIRED", "Approve requires grants or scopes");
|
|
128592
129835
|
}
|
|
128593
129836
|
try {
|
|
128594
129837
|
const approved = await approveMcpOAuthAuthorization({ authorizationId: id2, grants: body.grants }, {
|
|
@@ -128596,15 +129839,15 @@ async function handleMcpRoute(input) {
|
|
|
128596
129839
|
authorizationStore: input.authorizationStore,
|
|
128597
129840
|
now: input.now
|
|
128598
129841
|
});
|
|
128599
|
-
return
|
|
129842
|
+
return jsonResponse3({ redirectTo: approved.redirectTo });
|
|
128600
129843
|
} catch (err2) {
|
|
128601
129844
|
if (err2 instanceof McpOAuthAuthorizationError) {
|
|
128602
|
-
return
|
|
129845
|
+
return errorResponse3(err2.status, err2.code, err2.message);
|
|
128603
129846
|
}
|
|
128604
129847
|
throw err2;
|
|
128605
129848
|
}
|
|
128606
129849
|
}
|
|
128607
|
-
return
|
|
129850
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128608
129851
|
}
|
|
128609
129852
|
if (pathname === ownerPrefix || pathname.startsWith(`${ownerPrefix}/`)) {
|
|
128610
129853
|
try {
|
|
@@ -128628,41 +129871,41 @@ async function handleMcpRoute(input) {
|
|
|
128628
129871
|
publicOrigin: input.serverOrigin,
|
|
128629
129872
|
now: input.now
|
|
128630
129873
|
});
|
|
128631
|
-
return
|
|
129874
|
+
return jsonResponse3(created, { status: 201 });
|
|
128632
129875
|
}
|
|
128633
129876
|
if (input.request.method === "GET") {
|
|
128634
129877
|
const records = await listMcpConnectionViews(input.store);
|
|
128635
|
-
return
|
|
129878
|
+
return jsonResponse3({ connections: records });
|
|
128636
129879
|
}
|
|
128637
|
-
return
|
|
129880
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128638
129881
|
}
|
|
128639
129882
|
const tail = pathname.slice(ownerPrefix.length + 1);
|
|
128640
129883
|
const [id2, action] = tail.split("/");
|
|
128641
129884
|
if (!id2) {
|
|
128642
|
-
return
|
|
129885
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128643
129886
|
}
|
|
128644
129887
|
if (action === "approve") {
|
|
128645
129888
|
if (input.request.method !== "POST") {
|
|
128646
|
-
return
|
|
129889
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128647
129890
|
}
|
|
128648
129891
|
let body = {};
|
|
128649
129892
|
try {
|
|
128650
129893
|
body = await input.request.json();
|
|
128651
129894
|
} catch {
|
|
128652
|
-
return
|
|
129895
|
+
return errorResponse3(400, "INVALID_BODY", "Body must be JSON");
|
|
128653
129896
|
}
|
|
128654
129897
|
if (!Array.isArray(body.grants) || body.grants.length === 0) {
|
|
128655
|
-
return
|
|
129898
|
+
return errorResponse3(400, "GRANTS_REQUIRED", "Approve requires at least one grant \u2014 mint grants in the consent flow first");
|
|
128656
129899
|
}
|
|
128657
129900
|
try {
|
|
128658
129901
|
const updated = await approveMcpConnection({ connectionId: id2, grants: body.grants }, { store: input.store, now: input.now });
|
|
128659
|
-
return
|
|
129902
|
+
return jsonResponse3(toMcpConnectionView(updated));
|
|
128660
129903
|
} catch (err2) {
|
|
128661
129904
|
if (err2 instanceof McpConnectionNotFoundError) {
|
|
128662
|
-
return
|
|
129905
|
+
return errorResponse3(404, "NOT_FOUND", err2.message);
|
|
128663
129906
|
}
|
|
128664
129907
|
if (err2 instanceof McpConnectionStateError) {
|
|
128665
|
-
return
|
|
129908
|
+
return errorResponse3(409, "INVALID_STATE", err2.message);
|
|
128666
129909
|
}
|
|
128667
129910
|
throw err2;
|
|
128668
129911
|
}
|
|
@@ -128674,22 +129917,22 @@ async function handleMcpRoute(input) {
|
|
|
128674
129917
|
store: input.store,
|
|
128675
129918
|
now: input.now
|
|
128676
129919
|
});
|
|
128677
|
-
return
|
|
129920
|
+
return jsonResponse3(toMcpConnectionView(updated));
|
|
128678
129921
|
} catch (err2) {
|
|
128679
129922
|
if (err2 instanceof McpConnectionNotFoundError) {
|
|
128680
|
-
return
|
|
129923
|
+
return errorResponse3(404, "NOT_FOUND", err2.message);
|
|
128681
129924
|
}
|
|
128682
129925
|
throw err2;
|
|
128683
129926
|
}
|
|
128684
129927
|
}
|
|
128685
|
-
return
|
|
129928
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128686
129929
|
}
|
|
128687
|
-
return
|
|
129930
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128688
129931
|
}
|
|
128689
129932
|
async function handleMcpToken(rawToken, options) {
|
|
128690
129933
|
if (!rawToken) {
|
|
128691
129934
|
if (!options.oauthChallenge) {
|
|
128692
|
-
return
|
|
129935
|
+
return errorResponse3(401, "INVALID_TOKEN", "Missing MCP connection token");
|
|
128693
129936
|
}
|
|
128694
129937
|
return mcpUnauthorized(input.serverOrigin);
|
|
128695
129938
|
}
|
|
@@ -128697,7 +129940,7 @@ async function handleMcpRoute(input) {
|
|
|
128697
129940
|
const record2 = await input.store.getByTokenHash(tokenHash);
|
|
128698
129941
|
if (!record2) {
|
|
128699
129942
|
if (!options.oauthChallenge) {
|
|
128700
|
-
return
|
|
129943
|
+
return errorResponse3(401, "INVALID_TOKEN", "Unknown or revoked MCP connection");
|
|
128701
129944
|
}
|
|
128702
129945
|
return mcpUnauthorized(input.serverOrigin, "Unknown or revoked MCP connection");
|
|
128703
129946
|
}
|
|
@@ -128741,10 +129984,10 @@ async function handleMcpRoute(input) {
|
|
|
128741
129984
|
throw err2;
|
|
128742
129985
|
}
|
|
128743
129986
|
if (input.request.method !== "GET") {
|
|
128744
|
-
return
|
|
129987
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128745
129988
|
}
|
|
128746
129989
|
const snapshot = input.activityRecorder ? input.activityRecorder.snapshot() : { events: [], running: 0, total: 0 };
|
|
128747
|
-
return
|
|
129990
|
+
return jsonResponse3(snapshot);
|
|
128748
129991
|
}
|
|
128749
129992
|
if (pathname === "/mcp") {
|
|
128750
129993
|
return handleMcpToken(bearerToken(input.request), {
|
|
@@ -128755,7 +129998,7 @@ async function handleMcpRoute(input) {
|
|
|
128755
129998
|
if (pathname.startsWith(mcpPrefix)) {
|
|
128756
129999
|
const rawToken = decodeURIComponent(pathname.slice(mcpPrefix.length));
|
|
128757
130000
|
if (!rawToken || rawToken.includes("/")) {
|
|
128758
|
-
return
|
|
130001
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128759
130002
|
}
|
|
128760
130003
|
return handleMcpToken(rawToken, { oauthChallenge: false });
|
|
128761
130004
|
}
|
|
@@ -129402,6 +130645,24 @@ async function downloadOne(deps, record2) {
|
|
|
129402
130645
|
}
|
|
129403
130646
|
diagnostics?.onIndexEnd(record2.id, envelope.scope);
|
|
129404
130647
|
logger.info({ dataPointId: record2.id, scope: envelope.scope, path: relativePath }, "Downloaded and indexed data point");
|
|
130648
|
+
if (deps.onDataPointIndexed) {
|
|
130649
|
+
try {
|
|
130650
|
+
let lineageSources;
|
|
130651
|
+
try {
|
|
130652
|
+
lineageSources = readStoredLineage(envelope.data)?.sources;
|
|
130653
|
+
} catch {
|
|
130654
|
+
}
|
|
130655
|
+
deps.onDataPointIndexed({
|
|
130656
|
+
scope: envelope.scope,
|
|
130657
|
+
dataPointId: record2.id,
|
|
130658
|
+
version: Number(record2.expectedVersion),
|
|
130659
|
+
collectedAt: envelope.collectedAt,
|
|
130660
|
+
lineageSources
|
|
130661
|
+
});
|
|
130662
|
+
} catch (err2) {
|
|
130663
|
+
logger.warn({ scope: envelope.scope, error: err2.message }, "onDataPointIndexed hook failed; data point already indexed");
|
|
130664
|
+
}
|
|
130665
|
+
}
|
|
129405
130666
|
return {
|
|
129406
130667
|
dataPointId: record2.id,
|
|
129407
130668
|
scope: envelope.scope,
|
|
@@ -130481,7 +131742,8 @@ async function createPsLiteSyncManager(options) {
|
|
|
130481
131742
|
logger,
|
|
130482
131743
|
diagnostics: downloadDiagnostics,
|
|
130483
131744
|
dataPointFeed,
|
|
130484
|
-
scopeDeletions
|
|
131745
|
+
scopeDeletions,
|
|
131746
|
+
onDataPointIndexed: options.onDataPointIndexed
|
|
130485
131747
|
}, {
|
|
130486
131748
|
deleteData,
|
|
130487
131749
|
pendingBlobDeletions,
|
|
@@ -130509,6 +131771,58 @@ async function createPsLiteSyncManager(options) {
|
|
|
130509
131771
|
return { syncManager, serverOwner, dataPointFeed, scopeDeletions };
|
|
130510
131772
|
}
|
|
130511
131773
|
|
|
131774
|
+
// ../lite/dist/derivatives.js
|
|
131775
|
+
var QUESTIONS_KEY = "derivative-questions-v1";
|
|
131776
|
+
async function createPsLiteQuestionStore(stateStore) {
|
|
131777
|
+
const saved = await stateStore.get(QUESTIONS_KEY);
|
|
131778
|
+
const initial = saved?.version === 1 ? saved.questions : [];
|
|
131779
|
+
return createInMemoryQuestionStore({
|
|
131780
|
+
initial,
|
|
131781
|
+
onChange: (questions) => stateStore.set(QUESTIONS_KEY, {
|
|
131782
|
+
version: 1,
|
|
131783
|
+
questions
|
|
131784
|
+
})
|
|
131785
|
+
});
|
|
131786
|
+
}
|
|
131787
|
+
function psLiteInferenceConfigured(config2) {
|
|
131788
|
+
return config2.inference.baseUrl.replace(/\/+$/, "") !== DEFAULT_INFERENCE_BASE_URL.replace(/\/+$/, "");
|
|
131789
|
+
}
|
|
131790
|
+
function createPsLiteDerivativeCompute(options) {
|
|
131791
|
+
const provider = options.provider ?? createOpenAiCompatibleInferenceProvider({
|
|
131792
|
+
baseUrl: options.config.inference.baseUrl,
|
|
131793
|
+
model: options.config.inference.model
|
|
131794
|
+
});
|
|
131795
|
+
const logger = options.logger ? {
|
|
131796
|
+
info: (payload, message) => options.logger?.info(payload, message),
|
|
131797
|
+
warn: (payload, message) => options.logger?.warn(payload, message)
|
|
131798
|
+
} : void 0;
|
|
131799
|
+
const scheduler = createRecomputeScheduler({
|
|
131800
|
+
store: options.store,
|
|
131801
|
+
debounceMs: options.config.inference.recomputeDebounceMs,
|
|
131802
|
+
serverOwner: options.serverOwner,
|
|
131803
|
+
now: options.now,
|
|
131804
|
+
logger,
|
|
131805
|
+
compute: (questionId) => computeQuestion(questionId, {
|
|
131806
|
+
// A -> B -> C: a question reading this derived scope recomputes.
|
|
131807
|
+
onDerivedWritten: (event) => scheduler.markSourceChanged(event.scope, {
|
|
131808
|
+
lineageSources: event.lineageSources
|
|
131809
|
+
}),
|
|
131810
|
+
runtimeAvailability: options.runtimeAvailability,
|
|
131811
|
+
storage: options.storage,
|
|
131812
|
+
store: options.store,
|
|
131813
|
+
provider,
|
|
131814
|
+
serverOwner: options.serverOwner,
|
|
131815
|
+
maxSourceItems: options.config.inference.maxSourceItems,
|
|
131816
|
+
syncManager: options.syncManager?.() ?? null,
|
|
131817
|
+
scopeDeletions: options.scopeDeletions?.(),
|
|
131818
|
+
writePolicyPorts: options.writePolicyPorts,
|
|
131819
|
+
now: options.now,
|
|
131820
|
+
logger
|
|
131821
|
+
})
|
|
131822
|
+
});
|
|
131823
|
+
return { store: options.store, scheduler, provider };
|
|
131824
|
+
}
|
|
131825
|
+
|
|
130512
131826
|
// ../lite/dist/persistence.js
|
|
130513
131827
|
function assertCompletePsLitePersistenceBundle(bundle) {
|
|
130514
131828
|
if (!bundle || typeof bundle !== "object") {
|
|
@@ -130573,6 +131887,29 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
130573
131887
|
});
|
|
130574
131888
|
let syncManager = options.syncManager ?? null;
|
|
130575
131889
|
let scopeDeletions = options.scopeDeletions;
|
|
131890
|
+
let runtimeRef = null;
|
|
131891
|
+
let derivatives = options.derivatives ?? null;
|
|
131892
|
+
if (derivatives === null && options.derivatives === void 0 && (options.inferenceProvider || psLiteInferenceConfigured(config2))) {
|
|
131893
|
+
derivatives = createPsLiteDerivativeCompute({
|
|
131894
|
+
config: config2,
|
|
131895
|
+
storage,
|
|
131896
|
+
store: await createPsLiteQuestionStore(stateStore),
|
|
131897
|
+
serverOwner,
|
|
131898
|
+
syncManager: () => syncManager,
|
|
131899
|
+
scopeDeletions: () => scopeDeletions,
|
|
131900
|
+
writePolicyPorts: {
|
|
131901
|
+
authSessionVerifier: gateway,
|
|
131902
|
+
grantVerifier: gateway
|
|
131903
|
+
},
|
|
131904
|
+
runtimeAvailability: {
|
|
131905
|
+
isAvailable: () => runtimeRef?.isAvailable() ?? Boolean(options.active)
|
|
131906
|
+
},
|
|
131907
|
+
provider: options.inferenceProvider,
|
|
131908
|
+
logger: options.logger
|
|
131909
|
+
});
|
|
131910
|
+
} else if (derivatives === null && options.derivatives === void 0) {
|
|
131911
|
+
options.logger?.warn({ baseUrl: config2.inference.baseUrl }, "Derivative compute disabled: inference.baseUrl is the direct-provider default; point it at the Vana inference relay");
|
|
131912
|
+
}
|
|
130576
131913
|
if (!syncManager && config2.sync.enabled) {
|
|
130577
131914
|
const sync = await createPsLiteSyncManager({
|
|
130578
131915
|
config: config2,
|
|
@@ -130586,12 +131923,14 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
130586
131923
|
scopeDeletions,
|
|
130587
131924
|
diagnostics,
|
|
130588
131925
|
logger: options.logger,
|
|
130589
|
-
lineageGateway
|
|
131926
|
+
lineageGateway,
|
|
131927
|
+
onDataPointIndexed: (event) => derivatives?.scheduler.markSourceChanged(event.scope, {
|
|
131928
|
+
lineageSources: event.lineageSources
|
|
131929
|
+
})
|
|
130590
131930
|
});
|
|
130591
131931
|
syncManager = sync.syncManager;
|
|
130592
131932
|
scopeDeletions = sync.scopeDeletions;
|
|
130593
131933
|
}
|
|
130594
|
-
let runtimeRef = null;
|
|
130595
131934
|
const auth = options.auth ?? createWeb3SignedPsLiteAuth({
|
|
130596
131935
|
origin: () => options.runtimeOrigin ?? config2.server.origin,
|
|
130597
131936
|
ownerAddress: serverOwner,
|
|
@@ -130621,6 +131960,7 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
130621
131960
|
scopeDeletions,
|
|
130622
131961
|
diagnostics,
|
|
130623
131962
|
lineageGateway,
|
|
131963
|
+
derivatives,
|
|
130624
131964
|
saveConfig: async (nextConfig) => {
|
|
130625
131965
|
const saved = await savePsLiteConfig(stateStore, nextConfig);
|
|
130626
131966
|
Object.assign(config2, saved);
|
|
@@ -130643,7 +131983,8 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
130643
131983
|
storage,
|
|
130644
131984
|
tokenStore,
|
|
130645
131985
|
accessLogStore,
|
|
130646
|
-
syncManager
|
|
131986
|
+
syncManager,
|
|
131987
|
+
derivatives
|
|
130647
131988
|
};
|
|
130648
131989
|
}
|
|
130649
131990
|
|