@opendatalabs/personal-server-ts-server 1.7.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 +12 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +31 -3
- package/dist/app.js.map +1 -1
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +85 -2
- package/dist/bootstrap.js.map +1 -1
- package/dist/logging/access-log.d.ts +1 -1
- package/dist/logging/access-log.d.ts.map +1 -1
- package/dist/pending-blob-deletions.d.ts +10 -0
- package/dist/pending-blob-deletions.d.ts.map +1 -0
- package/dist/pending-blob-deletions.js +38 -0
- package/dist/pending-blob-deletions.js.map +1 -0
- package/dist/routes/data.d.ts +9 -1
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +2 -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/index-manager.d.ts.map +1 -1
- package/dist/storage/index-manager.js +4 -2
- package/dist/storage/index-manager.js.map +1 -1
- package/dist/storage/index-schema.d.ts +1 -1
- package/dist/storage/index-schema.d.ts.map +1 -1
- package/dist/storage/index-schema.js +9 -2
- package/dist/storage/index-schema.js.map +1 -1
- package/dist/storage/node-data-storage.d.ts.map +1 -1
- package/dist/storage/node-data-storage.js +10 -0
- package/dist/storage/node-data-storage.js.map +1 -1
- 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 +2810 -210
- 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);
|
|
@@ -105729,7 +105734,7 @@ var LineageGatewayError = class extends ProtocolError {
|
|
|
105729
105734
|
};
|
|
105730
105735
|
var LineageCascadeUnavailableError = class extends ProtocolError {
|
|
105731
105736
|
constructor(details) {
|
|
105732
|
-
super(501, "LINEAGE_CASCADE_UNAVAILABLE", "DELETE ?cascade=lineage is specified but not implemented yet:
|
|
105737
|
+
super(501, "LINEAGE_CASCADE_UNAVAILABLE", "DELETE ?cascade=lineage is specified but not implemented yet: the lineage walk that finds every derivative is missing. Delete scopes one at a time; each single-scope delete is durable.", details);
|
|
105733
105738
|
}
|
|
105734
105739
|
};
|
|
105735
105740
|
var InvalidCascadeError = class extends ProtocolError {
|
|
@@ -105737,6 +105742,41 @@ var InvalidCascadeError = class extends ProtocolError {
|
|
|
105737
105742
|
super(400, "INVALID_CASCADE", 'Unsupported cascade mode; the only supported value is "lineage"', details);
|
|
105738
105743
|
}
|
|
105739
105744
|
};
|
|
105745
|
+
var DeleteTombstoneFailedError = class extends ProtocolError {
|
|
105746
|
+
constructor(details) {
|
|
105747
|
+
super(502, "DELETE_TOMBSTONE_FAILED", "Gateway did not acknowledge the deletion tombstone; nothing was deleted", details);
|
|
105748
|
+
}
|
|
105749
|
+
};
|
|
105750
|
+
var DataDeletedError = class extends ProtocolError {
|
|
105751
|
+
constructor(details) {
|
|
105752
|
+
super(410, "DATA_DELETED", "Data point has been deleted", details);
|
|
105753
|
+
}
|
|
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
|
+
};
|
|
105740
105780
|
|
|
105741
105781
|
// ../core/dist/sync/data-point-id.js
|
|
105742
105782
|
function computeDataPointId(ownerAddress, scope) {
|
|
@@ -109344,6 +109384,7 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
109344
109384
|
schemaId: entry.schemaId ?? null,
|
|
109345
109385
|
version: version4,
|
|
109346
109386
|
dataPointId: entry.dataPointId ?? null,
|
|
109387
|
+
afterTombstoneVersion: entry.afterTombstoneVersion ?? null,
|
|
109347
109388
|
id: state.nextId,
|
|
109348
109389
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
109349
109390
|
};
|
|
@@ -109437,25 +109478,34 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
109437
109478
|
await persist();
|
|
109438
109479
|
return deleted;
|
|
109439
109480
|
},
|
|
109481
|
+
async deleteVersion(scope, collectedAt2) {
|
|
109482
|
+
const entry = state.entries.find((e10) => e10.scope === scope && e10.collectedAt === collectedAt2);
|
|
109483
|
+
if (!entry)
|
|
109484
|
+
return false;
|
|
109485
|
+
return removeEntry(entry);
|
|
109486
|
+
},
|
|
109440
109487
|
async deleteByFileId(fileId) {
|
|
109441
109488
|
const entry = state.entries.find((e10) => e10.fileId === fileId);
|
|
109442
109489
|
if (!entry)
|
|
109443
109490
|
return false;
|
|
109444
|
-
|
|
109445
|
-
await Promise.all([
|
|
109446
|
-
fileStore.deleteEnvelope(blobPath),
|
|
109447
|
-
fallbackStore.deleteEnvelope(blobPath),
|
|
109448
|
-
fileStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve(),
|
|
109449
|
-
fallbackStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve()
|
|
109450
|
-
]);
|
|
109451
|
-
state = {
|
|
109452
|
-
...state,
|
|
109453
|
-
entries: state.entries.filter((e10) => e10 !== entry)
|
|
109454
|
-
};
|
|
109455
|
-
await persist();
|
|
109456
|
-
return true;
|
|
109491
|
+
return removeEntry(entry);
|
|
109457
109492
|
}
|
|
109458
109493
|
};
|
|
109494
|
+
async function removeEntry(entry) {
|
|
109495
|
+
const blobPath = envelopePath(entry.scope, entry.collectedAt);
|
|
109496
|
+
await Promise.all([
|
|
109497
|
+
fileStore.deleteEnvelope(blobPath),
|
|
109498
|
+
fallbackStore.deleteEnvelope(blobPath),
|
|
109499
|
+
fileStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve(),
|
|
109500
|
+
fallbackStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve()
|
|
109501
|
+
]);
|
|
109502
|
+
state = {
|
|
109503
|
+
...state,
|
|
109504
|
+
entries: state.entries.filter((e10) => e10 !== entry)
|
|
109505
|
+
};
|
|
109506
|
+
await persist();
|
|
109507
|
+
return true;
|
|
109508
|
+
}
|
|
109459
109509
|
if (fileStore.readEnvelopePreview) {
|
|
109460
109510
|
storagePort.readEnvelopePreview = async (scope, collectedAt2, { maxBytes }) => {
|
|
109461
109511
|
const path = envelopePath(scope, collectedAt2);
|
|
@@ -109699,6 +109749,17 @@ var DEFAULTS = {
|
|
|
109699
109749
|
enabled: true,
|
|
109700
109750
|
serverAddr: "frpc.server.vana.org",
|
|
109701
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
|
|
109702
109763
|
}
|
|
109703
109764
|
};
|
|
109704
109765
|
var StorageBackend = external_exports.enum([
|
|
@@ -109752,7 +109813,13 @@ var ServerConfigSchema = external_exports.object({
|
|
|
109752
109813
|
enabled: external_exports.boolean().default(DEFAULTS.tunnel.enabled),
|
|
109753
109814
|
serverAddr: external_exports.string().default(DEFAULTS.tunnel.serverAddr),
|
|
109754
109815
|
serverPort: external_exports.number().int().min(1).max(65535).default(DEFAULTS.tunnel.serverPort)
|
|
109755
|
-
}).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)
|
|
109756
109823
|
});
|
|
109757
109824
|
|
|
109758
109825
|
// ../lite/dist/state.js
|
|
@@ -110743,15 +110810,44 @@ function normalizeOffset(value) {
|
|
|
110743
110810
|
function isRecord3(value) {
|
|
110744
110811
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
110745
110812
|
}
|
|
110813
|
+
var VISIBILITY_PAGE_SIZE = 200;
|
|
110746
110814
|
async function listDataScopesContract(input) {
|
|
110747
110815
|
const limit = normalizeLimit(input.limit);
|
|
110748
110816
|
const offset = normalizeOffset(input.offset);
|
|
110749
|
-
|
|
110750
|
-
|
|
110751
|
-
|
|
110752
|
-
|
|
110753
|
-
|
|
110754
|
-
|
|
110817
|
+
let page;
|
|
110818
|
+
let total;
|
|
110819
|
+
if (input.isVisible) {
|
|
110820
|
+
const visible = [];
|
|
110821
|
+
for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
|
|
110822
|
+
const batch = input.storage.listScopes({
|
|
110823
|
+
scopePrefix: input.scopePrefix,
|
|
110824
|
+
limit: VISIBILITY_PAGE_SIZE,
|
|
110825
|
+
offset: scan
|
|
110826
|
+
});
|
|
110827
|
+
for (const summary of batch.scopes) {
|
|
110828
|
+
const latest = input.storage.findEntry({
|
|
110829
|
+
scope: summary.scope,
|
|
110830
|
+
at: summary.latestCollectedAt
|
|
110831
|
+
});
|
|
110832
|
+
if (!latest || await input.isVisible(summary.scope, latest)) {
|
|
110833
|
+
visible.push(summary);
|
|
110834
|
+
}
|
|
110835
|
+
}
|
|
110836
|
+
if (batch.scopes.length < VISIBILITY_PAGE_SIZE)
|
|
110837
|
+
break;
|
|
110838
|
+
}
|
|
110839
|
+
total = visible.length;
|
|
110840
|
+
page = visible.slice(offset, offset + limit);
|
|
110841
|
+
} else {
|
|
110842
|
+
const result = input.storage.listScopes({
|
|
110843
|
+
scopePrefix: input.scopePrefix,
|
|
110844
|
+
limit,
|
|
110845
|
+
offset
|
|
110846
|
+
});
|
|
110847
|
+
page = result.scopes;
|
|
110848
|
+
total = result.total;
|
|
110849
|
+
}
|
|
110850
|
+
const scopes = await Promise.all(page.map(async (summary) => {
|
|
110755
110851
|
const entry = input.storage.findEntry({
|
|
110756
110852
|
scope: summary.scope,
|
|
110757
110853
|
at: summary.latestCollectedAt
|
|
@@ -110759,7 +110855,7 @@ async function listDataScopesContract(input) {
|
|
|
110759
110855
|
if (!entry) {
|
|
110760
110856
|
return summary;
|
|
110761
110857
|
}
|
|
110762
|
-
const hasBlocks = typeof input.storage.
|
|
110858
|
+
const hasBlocks = typeof input.storage.hasScopeBlocks === "function" ? await input.storage.hasScopeBlocks(summary.scope, summary.latestCollectedAt) : false;
|
|
110763
110859
|
return {
|
|
110764
110860
|
...summary,
|
|
110765
110861
|
dataStatus: hasBlocks ? "ready" : "indexing",
|
|
@@ -110770,33 +110866,52 @@ async function listDataScopesContract(input) {
|
|
|
110770
110866
|
ok: true,
|
|
110771
110867
|
response: {
|
|
110772
110868
|
scopes,
|
|
110773
|
-
total
|
|
110869
|
+
total,
|
|
110774
110870
|
limit,
|
|
110775
110871
|
offset
|
|
110776
110872
|
}
|
|
110777
110873
|
};
|
|
110778
110874
|
}
|
|
110779
|
-
function listDataVersionsContract(input) {
|
|
110875
|
+
async function listDataVersionsContract(input) {
|
|
110780
110876
|
const scopeResult = parseDataScopeContract(input.scopeParam);
|
|
110781
110877
|
if (!scopeResult.ok)
|
|
110782
110878
|
return scopeResult;
|
|
110783
110879
|
const limit = normalizeLimit(input.limit);
|
|
110784
110880
|
const offset = normalizeOffset(input.offset);
|
|
110785
|
-
|
|
110786
|
-
|
|
110787
|
-
|
|
110788
|
-
|
|
110881
|
+
let page;
|
|
110882
|
+
let total;
|
|
110883
|
+
if (input.isVisible) {
|
|
110884
|
+
const visible = [];
|
|
110885
|
+
for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
|
|
110886
|
+
const batch = input.storage.listVersions(scopeResult.scope, {
|
|
110887
|
+
limit: VISIBILITY_PAGE_SIZE,
|
|
110888
|
+
offset: scan
|
|
110889
|
+
});
|
|
110890
|
+
for (const entry of batch) {
|
|
110891
|
+
if (await input.isVisible(scopeResult.scope, entry)) {
|
|
110892
|
+
visible.push(entry);
|
|
110893
|
+
}
|
|
110894
|
+
}
|
|
110895
|
+
if (batch.length < VISIBILITY_PAGE_SIZE)
|
|
110896
|
+
break;
|
|
110897
|
+
}
|
|
110898
|
+
total = visible.length;
|
|
110899
|
+
page = visible.slice(offset, offset + limit);
|
|
110900
|
+
} else {
|
|
110901
|
+
page = input.storage.listVersions(scopeResult.scope, { limit, offset });
|
|
110902
|
+
total = input.storage.countVersions(scopeResult.scope);
|
|
110903
|
+
}
|
|
110789
110904
|
return {
|
|
110790
110905
|
ok: true,
|
|
110791
110906
|
scope: scopeResult.scope,
|
|
110792
110907
|
response: {
|
|
110793
110908
|
scope: scopeResult.scope,
|
|
110794
|
-
versions:
|
|
110909
|
+
versions: page.map((entry) => ({
|
|
110795
110910
|
fileId: entry.fileId,
|
|
110796
110911
|
schemaId: entry.schemaId,
|
|
110797
110912
|
collectedAt: entry.collectedAt
|
|
110798
110913
|
})),
|
|
110799
|
-
total
|
|
110914
|
+
total,
|
|
110800
110915
|
limit,
|
|
110801
110916
|
offset
|
|
110802
110917
|
}
|
|
@@ -110873,7 +110988,8 @@ async function ingestDataContract(input) {
|
|
|
110873
110988
|
path: writeResult.relativePath,
|
|
110874
110989
|
scope: scopeResult.scope,
|
|
110875
110990
|
collectedAt: input.collectedAt,
|
|
110876
|
-
sizeBytes: writeResult.sizeBytes
|
|
110991
|
+
sizeBytes: writeResult.sizeBytes,
|
|
110992
|
+
afterTombstoneVersion: input.afterTombstoneVersion ?? null
|
|
110877
110993
|
});
|
|
110878
110994
|
return {
|
|
110879
110995
|
ok: true,
|
|
@@ -110944,7 +111060,8 @@ async function ingestBinaryDataContract(input) {
|
|
|
110944
111060
|
path: writeResult.relativePath,
|
|
110945
111061
|
scope: scopeResult.scope,
|
|
110946
111062
|
collectedAt: input.collectedAt,
|
|
110947
|
-
sizeBytes: input.bytes.length
|
|
111063
|
+
sizeBytes: input.bytes.length,
|
|
111064
|
+
afterTombstoneVersion: input.afterTombstoneVersion ?? null
|
|
110948
111065
|
});
|
|
110949
111066
|
return {
|
|
110950
111067
|
ok: true,
|
|
@@ -110954,15 +111071,6 @@ async function ingestBinaryDataContract(input) {
|
|
|
110954
111071
|
writeResult
|
|
110955
111072
|
};
|
|
110956
111073
|
}
|
|
110957
|
-
async function deleteDataScopeContract(input) {
|
|
110958
|
-
const scopeResult = parseDataScopeContract(input.scopeParam);
|
|
110959
|
-
if (!scopeResult.ok)
|
|
110960
|
-
return scopeResult;
|
|
110961
|
-
return {
|
|
110962
|
-
ok: true,
|
|
110963
|
-
deletedCount: await input.storage.deleteScope(scopeResult.scope)
|
|
110964
|
-
};
|
|
110965
|
-
}
|
|
110966
111074
|
async function writeBlockSidecars(storage, envelope) {
|
|
110967
111075
|
if (!storage.writeBlockManifest)
|
|
110968
111076
|
return;
|
|
@@ -111548,6 +111656,548 @@ async function syncFileContract(input) {
|
|
|
111548
111656
|
return contractOk({ fileId: input.fileId, status: "started" }, 202);
|
|
111549
111657
|
}
|
|
111550
111658
|
|
|
111659
|
+
// ../core/dist/sync/tombstone.js
|
|
111660
|
+
var TOMBSTONE_DATA_HASH_LABEL = "vana.data-point.tombstone.v1";
|
|
111661
|
+
var TOMBSTONE_METADATA_HASH_LABEL = "vana.data-point.tombstone.metadata.v1";
|
|
111662
|
+
var TOMBSTONE_DATA_HASH = keccak256(stringToHex(TOMBSTONE_DATA_HASH_LABEL));
|
|
111663
|
+
var TOMBSTONE_METADATA_HASH = keccak256(stringToHex(TOMBSTONE_METADATA_HASH_LABEL));
|
|
111664
|
+
function isTombstoneRecord(record2) {
|
|
111665
|
+
return record2.dataHash.toLowerCase() === TOMBSTONE_DATA_HASH && record2.metadataHash.toLowerCase() === TOMBSTONE_METADATA_HASH;
|
|
111666
|
+
}
|
|
111667
|
+
|
|
111668
|
+
// ../core/dist/sync/scope-deletions.js
|
|
111669
|
+
var DEFAULT_SCOPE_DELETION_MAX_STALENESS_MS = 12e4;
|
|
111670
|
+
var DEFAULT_SCOPE_DELETION_GATEWAY_RETRY_MS = 15e3;
|
|
111671
|
+
var DEFAULT_MAX_LIVE_ENTRIES = 1e4;
|
|
111672
|
+
function createScopeDeletionTracker(options = {}) {
|
|
111673
|
+
const maxStalenessMs = options.maxStalenessMs ?? DEFAULT_SCOPE_DELETION_MAX_STALENESS_MS;
|
|
111674
|
+
const gatewayRetryMs = options.gatewayRetryMs ?? DEFAULT_SCOPE_DELETION_GATEWAY_RETRY_MS;
|
|
111675
|
+
const maxLiveEntries = options.maxLiveEntries ?? DEFAULT_MAX_LIVE_ENTRIES;
|
|
111676
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
111677
|
+
const nowMs = () => now().getTime();
|
|
111678
|
+
const deleted = /* @__PURE__ */ new Map();
|
|
111679
|
+
const live = /* @__PURE__ */ new Map();
|
|
111680
|
+
let lastFeedSyncMs = null;
|
|
111681
|
+
let lastGatewayFailureMs = null;
|
|
111682
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
111683
|
+
function rememberLive(scope, at3) {
|
|
111684
|
+
deleted.delete(scope);
|
|
111685
|
+
live.delete(scope);
|
|
111686
|
+
live.set(scope, at3);
|
|
111687
|
+
while (live.size > maxLiveEntries) {
|
|
111688
|
+
const oldest = live.keys().next().value;
|
|
111689
|
+
if (oldest === void 0)
|
|
111690
|
+
break;
|
|
111691
|
+
live.delete(oldest);
|
|
111692
|
+
}
|
|
111693
|
+
}
|
|
111694
|
+
function rememberDeleted(scope, tombstone, source) {
|
|
111695
|
+
deleted.set(scope, {
|
|
111696
|
+
deletedAt: tombstone.deletedAt,
|
|
111697
|
+
version: normalizeVersion(tombstone.version),
|
|
111698
|
+
source,
|
|
111699
|
+
verifiedAtMs: nowMs()
|
|
111700
|
+
});
|
|
111701
|
+
live.delete(scope);
|
|
111702
|
+
}
|
|
111703
|
+
function isFresh(at3) {
|
|
111704
|
+
return at3 !== null && nowMs() - at3 <= maxStalenessMs;
|
|
111705
|
+
}
|
|
111706
|
+
function verdictFromRecord(scope, record2) {
|
|
111707
|
+
const deletedAt = deletionTimestamp(record2);
|
|
111708
|
+
if (deletedAt !== null) {
|
|
111709
|
+
const version4 = tombstoneVersion(record2);
|
|
111710
|
+
rememberDeleted(scope, { deletedAt, version: version4 }, "gateway");
|
|
111711
|
+
return {
|
|
111712
|
+
deleted: true,
|
|
111713
|
+
deletedAt,
|
|
111714
|
+
version: version4,
|
|
111715
|
+
source: "gateway",
|
|
111716
|
+
verified: true
|
|
111717
|
+
};
|
|
111718
|
+
}
|
|
111719
|
+
rememberLive(scope, nowMs());
|
|
111720
|
+
return { deleted: false, source: "gateway", verified: true };
|
|
111721
|
+
}
|
|
111722
|
+
async function lookup2(scope) {
|
|
111723
|
+
const feed = options.feed;
|
|
111724
|
+
const owner = options.serverOwner;
|
|
111725
|
+
if (!feed || !owner)
|
|
111726
|
+
return null;
|
|
111727
|
+
if (lastGatewayFailureMs !== null && nowMs() - lastGatewayFailureMs < gatewayRetryMs) {
|
|
111728
|
+
return null;
|
|
111729
|
+
}
|
|
111730
|
+
const pending = inflight.get(scope);
|
|
111731
|
+
if (pending)
|
|
111732
|
+
return pending;
|
|
111733
|
+
const request2 = (async () => {
|
|
111734
|
+
try {
|
|
111735
|
+
const record2 = await feed.getDataPoint({
|
|
111736
|
+
ownerAddress: owner,
|
|
111737
|
+
scope
|
|
111738
|
+
});
|
|
111739
|
+
lastGatewayFailureMs = null;
|
|
111740
|
+
return verdictFromRecord(scope, record2);
|
|
111741
|
+
} catch (err2) {
|
|
111742
|
+
lastGatewayFailureMs = nowMs();
|
|
111743
|
+
options.logger?.warn?.({
|
|
111744
|
+
scope,
|
|
111745
|
+
error: err2 instanceof Error ? err2.message : String(err2),
|
|
111746
|
+
retryAfterMs: gatewayRetryMs
|
|
111747
|
+
}, "Could not check gateway deletion state; serving last known state");
|
|
111748
|
+
return null;
|
|
111749
|
+
} finally {
|
|
111750
|
+
inflight.delete(scope);
|
|
111751
|
+
}
|
|
111752
|
+
})();
|
|
111753
|
+
inflight.set(scope, request2);
|
|
111754
|
+
return request2;
|
|
111755
|
+
}
|
|
111756
|
+
return {
|
|
111757
|
+
maxStalenessMs,
|
|
111758
|
+
markDeleted(scope, tombstone, source = "feed") {
|
|
111759
|
+
rememberDeleted(scope, tombstone, source);
|
|
111760
|
+
},
|
|
111761
|
+
markLive(scope) {
|
|
111762
|
+
rememberLive(scope, nowMs());
|
|
111763
|
+
},
|
|
111764
|
+
noteFeedSynced(at3, options2) {
|
|
111765
|
+
lastFeedSyncMs = (at3 ?? now()).getTime();
|
|
111766
|
+
if (!options2?.full)
|
|
111767
|
+
return;
|
|
111768
|
+
for (const tombstone of deleted.values()) {
|
|
111769
|
+
tombstone.verifiedAtMs = Math.max(tombstone.verifiedAtMs, lastFeedSyncMs);
|
|
111770
|
+
}
|
|
111771
|
+
},
|
|
111772
|
+
knownDeletion(scope) {
|
|
111773
|
+
const known = deleted.get(scope);
|
|
111774
|
+
return known === void 0 ? null : { deletedAt: known.deletedAt, version: known.version };
|
|
111775
|
+
},
|
|
111776
|
+
feedAgeMs() {
|
|
111777
|
+
return lastFeedSyncMs === null ? null : nowMs() - lastFeedSyncMs;
|
|
111778
|
+
},
|
|
111779
|
+
async resolve(scope, resolveOptions) {
|
|
111780
|
+
const known = deleted.get(scope);
|
|
111781
|
+
if (known !== void 0) {
|
|
111782
|
+
if (isFresh(known.verifiedAtMs)) {
|
|
111783
|
+
return {
|
|
111784
|
+
deleted: true,
|
|
111785
|
+
deletedAt: known.deletedAt,
|
|
111786
|
+
version: known.version,
|
|
111787
|
+
source: known.source,
|
|
111788
|
+
verified: true
|
|
111789
|
+
};
|
|
111790
|
+
}
|
|
111791
|
+
const rechecked = await lookup2(scope);
|
|
111792
|
+
if (rechecked !== null)
|
|
111793
|
+
return rechecked;
|
|
111794
|
+
return {
|
|
111795
|
+
deleted: true,
|
|
111796
|
+
deletedAt: known.deletedAt,
|
|
111797
|
+
version: known.version,
|
|
111798
|
+
source: known.source,
|
|
111799
|
+
verified: false
|
|
111800
|
+
};
|
|
111801
|
+
}
|
|
111802
|
+
if (isFresh(live.get(scope) ?? null)) {
|
|
111803
|
+
return { deleted: false, source: "gateway", verified: true };
|
|
111804
|
+
}
|
|
111805
|
+
const consult = resolveOptions?.consultGateway ?? "if-stale";
|
|
111806
|
+
if (consult === "if-stale" && isFresh(lastFeedSyncMs)) {
|
|
111807
|
+
return { deleted: false, source: "feed", verified: true };
|
|
111808
|
+
}
|
|
111809
|
+
return await lookup2(scope) ?? {
|
|
111810
|
+
deleted: false,
|
|
111811
|
+
source: "assumed-live",
|
|
111812
|
+
verified: false
|
|
111813
|
+
};
|
|
111814
|
+
}
|
|
111815
|
+
};
|
|
111816
|
+
}
|
|
111817
|
+
function deletionTimestamp(record2) {
|
|
111818
|
+
if (!record2)
|
|
111819
|
+
return null;
|
|
111820
|
+
if (record2.deletedAt)
|
|
111821
|
+
return record2.deletedAt;
|
|
111822
|
+
return isTombstoneRecord(record2) ? record2.addedAt : null;
|
|
111823
|
+
}
|
|
111824
|
+
function tombstoneVersion(record2) {
|
|
111825
|
+
return normalizeVersion(record2?.expectedVersion ?? null);
|
|
111826
|
+
}
|
|
111827
|
+
function normalizeVersion(value) {
|
|
111828
|
+
if (typeof value !== "string" || !/^\d+$/.test(value))
|
|
111829
|
+
return null;
|
|
111830
|
+
return BigInt(value) > 0n ? BigInt(value).toString() : null;
|
|
111831
|
+
}
|
|
111832
|
+
function isEntryCoveredByTombstone(entry, tombstone) {
|
|
111833
|
+
const version4 = normalizeVersion(tombstone.version);
|
|
111834
|
+
if (version4 === null)
|
|
111835
|
+
return true;
|
|
111836
|
+
const tombstoned = BigInt(version4);
|
|
111837
|
+
if (entry.dataPointId !== null)
|
|
111838
|
+
return BigInt(entry.version) <= tombstoned;
|
|
111839
|
+
const marker = entry.afterTombstoneVersion;
|
|
111840
|
+
if (marker === null || marker === void 0 || !Number.isSafeInteger(marker)) {
|
|
111841
|
+
return true;
|
|
111842
|
+
}
|
|
111843
|
+
return BigInt(marker) < tombstoned;
|
|
111844
|
+
}
|
|
111845
|
+
|
|
111846
|
+
// ../core/dist/sync/workers/delete.js
|
|
111847
|
+
var BLOB_DELETE_BATCH_SIZE = 15;
|
|
111848
|
+
function planBlobDeletions(storage, scope, tombstoneVersionValue) {
|
|
111849
|
+
const tombstone = { version: tombstoneVersionValue };
|
|
111850
|
+
const last2 = tombstoneVersionValue === null ? null : BigInt(tombstoneVersionValue);
|
|
111851
|
+
const keys = /* @__PURE__ */ new Set();
|
|
111852
|
+
const PAGE_SIZE = 500;
|
|
111853
|
+
for (let offset = 0; ; offset += PAGE_SIZE) {
|
|
111854
|
+
const entries = storage.listVersions(scope, { limit: PAGE_SIZE, offset });
|
|
111855
|
+
for (const entry of entries) {
|
|
111856
|
+
if (!isEntryCoveredByTombstone(entry, tombstone))
|
|
111857
|
+
continue;
|
|
111858
|
+
const version4 = BigInt(entry.version);
|
|
111859
|
+
if (last2 !== null && version4 >= 1n && version4 <= last2)
|
|
111860
|
+
continue;
|
|
111861
|
+
keys.add(version4.toString());
|
|
111862
|
+
}
|
|
111863
|
+
if (entries.length < PAGE_SIZE)
|
|
111864
|
+
break;
|
|
111865
|
+
}
|
|
111866
|
+
return {
|
|
111867
|
+
keys: [...keys].sort((a10, b10) => BigInt(a10) < BigInt(b10) ? -1 : 1),
|
|
111868
|
+
range: last2 === null || last2 < 1n ? null : { from: "1", to: last2.toString() }
|
|
111869
|
+
};
|
|
111870
|
+
}
|
|
111871
|
+
function takeFromRange(range, count) {
|
|
111872
|
+
const from = BigInt(range.from);
|
|
111873
|
+
const to3 = BigInt(range.to);
|
|
111874
|
+
const versions = [];
|
|
111875
|
+
let cursor = from;
|
|
111876
|
+
while (cursor <= to3 && versions.length < count) {
|
|
111877
|
+
versions.push(cursor.toString());
|
|
111878
|
+
cursor += 1n;
|
|
111879
|
+
}
|
|
111880
|
+
return {
|
|
111881
|
+
versions,
|
|
111882
|
+
rest: cursor <= to3 ? { from: cursor.toString(), to: range.to } : null
|
|
111883
|
+
};
|
|
111884
|
+
}
|
|
111885
|
+
function rangeSize(range) {
|
|
111886
|
+
return BigInt(range.to) - BigInt(range.from) + 1n;
|
|
111887
|
+
}
|
|
111888
|
+
function countPendingKeys(markers) {
|
|
111889
|
+
let total = 0n;
|
|
111890
|
+
for (const marker of markers) {
|
|
111891
|
+
if (marker.version !== null)
|
|
111892
|
+
total += 1n;
|
|
111893
|
+
else if (marker.range)
|
|
111894
|
+
total += rangeSize(marker.range);
|
|
111895
|
+
else
|
|
111896
|
+
total += 1n;
|
|
111897
|
+
}
|
|
111898
|
+
return total > BigInt(Number.MAX_SAFE_INTEGER) ? Number.MAX_SAFE_INTEGER : Number(total);
|
|
111899
|
+
}
|
|
111900
|
+
async function deleteScope(deps, scope) {
|
|
111901
|
+
const { storage, deleteData, pendingBlobDeletions, scopeDeletions, logger } = deps;
|
|
111902
|
+
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
111903
|
+
const dataPointId = deps.serverOwner ? computeDataPointId(deps.serverOwner, scope) : null;
|
|
111904
|
+
const result = {
|
|
111905
|
+
scope,
|
|
111906
|
+
dataPointId,
|
|
111907
|
+
durable: false,
|
|
111908
|
+
steps: {
|
|
111909
|
+
gateway: { status: "skipped", reason: "sync-disabled" },
|
|
111910
|
+
storage: { status: "skipped", reason: "sync-disabled" },
|
|
111911
|
+
local: { status: "skipped" }
|
|
111912
|
+
},
|
|
111913
|
+
pendingBlobDeletion: false
|
|
111914
|
+
};
|
|
111915
|
+
if (deleteData) {
|
|
111916
|
+
let tombstoneVersionValue = null;
|
|
111917
|
+
let tombstoneKnown = false;
|
|
111918
|
+
try {
|
|
111919
|
+
let outcome = await deleteData.tombstone(scope);
|
|
111920
|
+
if (outcome.status === "not-registered") {
|
|
111921
|
+
let registry2 = await registryState(deps, scope);
|
|
111922
|
+
if (registry2.status === "live") {
|
|
111923
|
+
outcome = await deleteData.tombstone(scope);
|
|
111924
|
+
registry2 = await registryState(deps, scope);
|
|
111925
|
+
}
|
|
111926
|
+
if (outcome.status === "not-registered" && registry2.status !== "deleted-or-absent") {
|
|
111927
|
+
throw registry2.status === "unknown" ? registry2.error : new Error("Scope was registered concurrently while it was being deleted; retry the delete");
|
|
111928
|
+
}
|
|
111929
|
+
}
|
|
111930
|
+
if (outcome.status === "not-registered") {
|
|
111931
|
+
result.steps.gateway = { status: "skipped", reason: "not-registered" };
|
|
111932
|
+
} else {
|
|
111933
|
+
tombstoneKnown = true;
|
|
111934
|
+
tombstoneVersionValue = outcome.version === null ? null : tombstoneVersion({ expectedVersion: outcome.version });
|
|
111935
|
+
result.steps.gateway = {
|
|
111936
|
+
status: "ok",
|
|
111937
|
+
...outcome.status === "already-deleted" && {
|
|
111938
|
+
reason: "already-deleted"
|
|
111939
|
+
},
|
|
111940
|
+
version: outcome.version,
|
|
111941
|
+
deletedAt: outcome.deletedAt
|
|
111942
|
+
};
|
|
111943
|
+
scopeDeletions?.markDeleted(scope, {
|
|
111944
|
+
deletedAt: outcome.deletedAt ?? now().toISOString(),
|
|
111945
|
+
version: outcome.version
|
|
111946
|
+
}, "local-delete");
|
|
111947
|
+
}
|
|
111948
|
+
result.durable = true;
|
|
111949
|
+
} catch (err2) {
|
|
111950
|
+
const message = errorMessage2(err2);
|
|
111951
|
+
result.steps.gateway = { status: "failed", error: message };
|
|
111952
|
+
result.steps.storage = { status: "skipped", reason: "gateway-failed" };
|
|
111953
|
+
result.steps.local = { status: "skipped", reason: "gateway-failed" };
|
|
111954
|
+
logger.error({ scope, dataPointId, error: message }, "Gateway tombstone failed; scope NOT deleted (local copy kept so sync cannot resurrect a half-deleted scope)");
|
|
111955
|
+
return result;
|
|
111956
|
+
}
|
|
111957
|
+
const plan = planBlobDeletions(storage, scope, tombstoneVersionValue);
|
|
111958
|
+
const batch = plan.keys.slice(0, BLOB_DELETE_BATCH_SIZE);
|
|
111959
|
+
const leftovers = plan.keys.slice(BLOB_DELETE_BATCH_SIZE).map((version4) => ({ scope, version: version4 }));
|
|
111960
|
+
if (plan.range) {
|
|
111961
|
+
const taken = takeFromRange(plan.range, BLOB_DELETE_BATCH_SIZE - batch.length);
|
|
111962
|
+
batch.push(...taken.versions);
|
|
111963
|
+
if (taken.rest)
|
|
111964
|
+
leftovers.push({ scope, version: null, range: taken.rest });
|
|
111965
|
+
}
|
|
111966
|
+
if (tombstoneKnown && tombstoneVersionValue === null) {
|
|
111967
|
+
leftovers.push({ scope, version: null });
|
|
111968
|
+
}
|
|
111969
|
+
const storageStep = await deleteBlobKeys({ deleteData, pendingBlobDeletions, logger }, scope, batch, leftovers);
|
|
111970
|
+
result.steps.storage = storageStep.step;
|
|
111971
|
+
result.pendingBlobDeletion = storageStep.pending > 0;
|
|
111972
|
+
}
|
|
111973
|
+
try {
|
|
111974
|
+
const deletedCount = await storage.deleteScope(scope);
|
|
111975
|
+
result.steps.local = { status: "ok", deletedCount };
|
|
111976
|
+
} catch (err2) {
|
|
111977
|
+
const message = errorMessage2(err2);
|
|
111978
|
+
result.steps.local = { status: "failed", error: message };
|
|
111979
|
+
logger.error({ scope, error: message }, "Local scope deletion failed");
|
|
111980
|
+
}
|
|
111981
|
+
logger.info({
|
|
111982
|
+
scope,
|
|
111983
|
+
dataPointId,
|
|
111984
|
+
durable: result.durable,
|
|
111985
|
+
gateway: result.steps.gateway.status,
|
|
111986
|
+
storage: result.steps.storage.status,
|
|
111987
|
+
local: result.steps.local.status
|
|
111988
|
+
}, "Scope deletion finished");
|
|
111989
|
+
return result;
|
|
111990
|
+
}
|
|
111991
|
+
async function deleteBlobKeys(deps, scope, batch, leftovers) {
|
|
111992
|
+
const { deleteData, pendingBlobDeletions, logger } = deps;
|
|
111993
|
+
let outcome;
|
|
111994
|
+
try {
|
|
111995
|
+
outcome = batch.length > 0 && deleteData ? await deleteData.deleteBlobVersions(scope, batch) : { deleted: [], missing: [], failed: [] };
|
|
111996
|
+
} catch (err2) {
|
|
111997
|
+
outcome = {
|
|
111998
|
+
deleted: [],
|
|
111999
|
+
missing: [],
|
|
112000
|
+
failed: batch.map((version4) => ({ version: version4, error: errorMessage2(err2) }))
|
|
112001
|
+
};
|
|
112002
|
+
}
|
|
112003
|
+
const completed = [...outcome.deleted, ...outcome.missing].map((version4) => ({ scope, version: version4 }));
|
|
112004
|
+
const remaining = [
|
|
112005
|
+
...outcome.failed.map(({ version: version4 }) => ({ scope, version: version4 })),
|
|
112006
|
+
...leftovers
|
|
112007
|
+
];
|
|
112008
|
+
const remainingKeys = countPendingKeys(remaining);
|
|
112009
|
+
let recorded = remainingKeys;
|
|
112010
|
+
if (pendingBlobDeletions) {
|
|
112011
|
+
try {
|
|
112012
|
+
if (completed.length > 0)
|
|
112013
|
+
await pendingBlobDeletions.remove(completed);
|
|
112014
|
+
if (remaining.length > 0)
|
|
112015
|
+
await pendingBlobDeletions.add(remaining);
|
|
112016
|
+
} catch (markerErr) {
|
|
112017
|
+
recorded = 0;
|
|
112018
|
+
logger.error({ scope, error: errorMessage2(markerErr), keys: remainingKeys }, "Could not record pending blob deletion markers");
|
|
112019
|
+
}
|
|
112020
|
+
} else if (remaining.length > 0) {
|
|
112021
|
+
recorded = 0;
|
|
112022
|
+
logger.error({ scope, keys: remainingKeys }, "Blob deletions left unfinished with no marker store to retry them");
|
|
112023
|
+
}
|
|
112024
|
+
const counts = {
|
|
112025
|
+
blobsDeleted: outcome.deleted.length,
|
|
112026
|
+
blobsMissing: outcome.missing.length,
|
|
112027
|
+
blobsPending: remainingKeys
|
|
112028
|
+
};
|
|
112029
|
+
if (outcome.failed.length > 0) {
|
|
112030
|
+
const first = outcome.failed[0];
|
|
112031
|
+
logger.warn({
|
|
112032
|
+
scope,
|
|
112033
|
+
failed: outcome.failed.length,
|
|
112034
|
+
pending: recorded,
|
|
112035
|
+
error: first.error
|
|
112036
|
+
}, "Storage blob deletion failed for some keys after gateway tombstone; will retry");
|
|
112037
|
+
return {
|
|
112038
|
+
step: {
|
|
112039
|
+
status: "failed",
|
|
112040
|
+
error: `${outcome.failed.length} blob delete(s) failed: ${first.error}`,
|
|
112041
|
+
...counts
|
|
112042
|
+
},
|
|
112043
|
+
pending: recorded
|
|
112044
|
+
};
|
|
112045
|
+
}
|
|
112046
|
+
if (remaining.length > 0) {
|
|
112047
|
+
logger.info({ scope, ...counts }, "Storage blob deletion continues on later sync cycles (rate-limited batch)");
|
|
112048
|
+
return { step: { status: "deferred", ...counts }, pending: recorded };
|
|
112049
|
+
}
|
|
112050
|
+
return { step: { status: "ok", ...counts }, pending: 0 };
|
|
112051
|
+
}
|
|
112052
|
+
async function retryPendingBlobDeletions(deps) {
|
|
112053
|
+
const { deleteData, pendingBlobDeletions, logger } = deps;
|
|
112054
|
+
const result = {
|
|
112055
|
+
completed: [],
|
|
112056
|
+
superseded: [],
|
|
112057
|
+
failed: [],
|
|
112058
|
+
remaining: 0
|
|
112059
|
+
};
|
|
112060
|
+
if (!deleteData || !pendingBlobDeletions)
|
|
112061
|
+
return result;
|
|
112062
|
+
let markers = await pendingBlobDeletions.list();
|
|
112063
|
+
if (markers.length === 0)
|
|
112064
|
+
return result;
|
|
112065
|
+
for (const marker of markers.filter((key) => key.version === null && !key.range)) {
|
|
112066
|
+
const registry2 = await registryState(deps, marker.scope);
|
|
112067
|
+
if (registry2.status === "unknown") {
|
|
112068
|
+
result.failed.push({
|
|
112069
|
+
scope: marker.scope,
|
|
112070
|
+
version: null,
|
|
112071
|
+
error: registry2.error.message
|
|
112072
|
+
});
|
|
112073
|
+
continue;
|
|
112074
|
+
}
|
|
112075
|
+
if (registry2.status === "live") {
|
|
112076
|
+
await pendingBlobDeletions.remove([marker]);
|
|
112077
|
+
result.superseded.push(marker.scope);
|
|
112078
|
+
logger.warn({
|
|
112079
|
+
scope: marker.scope,
|
|
112080
|
+
dataPointId: registry2.record.id,
|
|
112081
|
+
version: registry2.record.expectedVersion
|
|
112082
|
+
}, "Scope was re-added after its tombstone; dropping the unexpanded blob deletion marker so the live version's ciphertext survives");
|
|
112083
|
+
continue;
|
|
112084
|
+
}
|
|
112085
|
+
const plan = planBlobDeletions(deps.storage ?? { listVersions: () => [] }, marker.scope, registry2.status === "deleted" ? registry2.version : null);
|
|
112086
|
+
const expanded = plan.keys.map((version4) => ({
|
|
112087
|
+
scope: marker.scope,
|
|
112088
|
+
version: version4
|
|
112089
|
+
}));
|
|
112090
|
+
if (plan.range) {
|
|
112091
|
+
expanded.push({ scope: marker.scope, version: null, range: plan.range });
|
|
112092
|
+
}
|
|
112093
|
+
await pendingBlobDeletions.remove([marker]);
|
|
112094
|
+
await pendingBlobDeletions.add(expanded);
|
|
112095
|
+
}
|
|
112096
|
+
markers = await pendingBlobDeletions.list();
|
|
112097
|
+
let budget = BLOB_DELETE_BATCH_SIZE;
|
|
112098
|
+
const byScope = /* @__PURE__ */ new Map();
|
|
112099
|
+
const exactOrigin = /* @__PURE__ */ new Set();
|
|
112100
|
+
const advancedRanges = [];
|
|
112101
|
+
const enqueue = (scope, version4) => {
|
|
112102
|
+
const versions = byScope.get(scope) ?? [];
|
|
112103
|
+
versions.push(version4);
|
|
112104
|
+
byScope.set(scope, versions);
|
|
112105
|
+
};
|
|
112106
|
+
for (const marker of markers) {
|
|
112107
|
+
if (budget === 0)
|
|
112108
|
+
break;
|
|
112109
|
+
if (marker.version !== null) {
|
|
112110
|
+
enqueue(marker.scope, marker.version);
|
|
112111
|
+
exactOrigin.add(`${marker.scope}\0${marker.version}`);
|
|
112112
|
+
budget -= 1;
|
|
112113
|
+
}
|
|
112114
|
+
}
|
|
112115
|
+
for (const marker of markers) {
|
|
112116
|
+
if (budget === 0)
|
|
112117
|
+
break;
|
|
112118
|
+
if (marker.version === null && marker.range) {
|
|
112119
|
+
const taken = takeFromRange(marker.range, budget);
|
|
112120
|
+
for (const version4 of taken.versions)
|
|
112121
|
+
enqueue(marker.scope, version4);
|
|
112122
|
+
budget -= taken.versions.length;
|
|
112123
|
+
advancedRanges.push({
|
|
112124
|
+
old: marker,
|
|
112125
|
+
next: taken.rest ? { scope: marker.scope, version: null, range: taken.rest } : null
|
|
112126
|
+
});
|
|
112127
|
+
}
|
|
112128
|
+
}
|
|
112129
|
+
for (const [scope, versions] of byScope) {
|
|
112130
|
+
let outcome;
|
|
112131
|
+
try {
|
|
112132
|
+
outcome = await deleteData.deleteBlobVersions(scope, versions);
|
|
112133
|
+
} catch (err2) {
|
|
112134
|
+
const message = errorMessage2(err2);
|
|
112135
|
+
outcome = {
|
|
112136
|
+
deleted: [],
|
|
112137
|
+
missing: [],
|
|
112138
|
+
failed: versions.map((version4) => ({ version: version4, error: message }))
|
|
112139
|
+
};
|
|
112140
|
+
}
|
|
112141
|
+
const completed = [...outcome.deleted, ...outcome.missing].filter((version4) => exactOrigin.has(`${scope}\0${version4}`)).map((version4) => ({ scope, version: version4 }));
|
|
112142
|
+
if (completed.length > 0)
|
|
112143
|
+
await pendingBlobDeletions.remove(completed);
|
|
112144
|
+
result.completed.push(...[...outcome.deleted, ...outcome.missing].map((version4) => ({ scope, version: version4 })));
|
|
112145
|
+
const failedFromRange = outcome.failed.filter(({ version: version4 }) => !exactOrigin.has(`${scope}\0${version4}`)).map(({ version: version4 }) => ({ scope, version: version4 }));
|
|
112146
|
+
if (failedFromRange.length > 0) {
|
|
112147
|
+
await pendingBlobDeletions.add(failedFromRange);
|
|
112148
|
+
}
|
|
112149
|
+
for (const failure of outcome.failed) {
|
|
112150
|
+
result.failed.push({ scope, ...failure });
|
|
112151
|
+
}
|
|
112152
|
+
if (outcome.deleted.length + outcome.missing.length > 0) {
|
|
112153
|
+
logger.info({
|
|
112154
|
+
scope,
|
|
112155
|
+
deleted: outcome.deleted.length,
|
|
112156
|
+
missing: outcome.missing.length
|
|
112157
|
+
}, "Completed pending blob deletions");
|
|
112158
|
+
}
|
|
112159
|
+
if (outcome.failed.length > 0) {
|
|
112160
|
+
logger.warn({
|
|
112161
|
+
scope,
|
|
112162
|
+
failed: outcome.failed.length,
|
|
112163
|
+
error: outcome.failed[0].error
|
|
112164
|
+
}, "Pending blob deletion failed again");
|
|
112165
|
+
}
|
|
112166
|
+
}
|
|
112167
|
+
for (const { old, next } of advancedRanges) {
|
|
112168
|
+
await pendingBlobDeletions.remove([old]);
|
|
112169
|
+
if (next)
|
|
112170
|
+
await pendingBlobDeletions.add([next]);
|
|
112171
|
+
}
|
|
112172
|
+
result.remaining = (await pendingBlobDeletions.list()).length;
|
|
112173
|
+
return result;
|
|
112174
|
+
}
|
|
112175
|
+
async function registryState(deps, scope) {
|
|
112176
|
+
if (!deps.dataPointFeed || !deps.serverOwner) {
|
|
112177
|
+
return { status: "deleted-or-absent" };
|
|
112178
|
+
}
|
|
112179
|
+
let record2;
|
|
112180
|
+
try {
|
|
112181
|
+
record2 = await deps.dataPointFeed.getDataPoint({
|
|
112182
|
+
ownerAddress: deps.serverOwner,
|
|
112183
|
+
scope
|
|
112184
|
+
});
|
|
112185
|
+
} catch (err2) {
|
|
112186
|
+
return {
|
|
112187
|
+
status: "unknown",
|
|
112188
|
+
error: err2 instanceof Error ? err2 : new Error(String(err2))
|
|
112189
|
+
};
|
|
112190
|
+
}
|
|
112191
|
+
if (record2 === null)
|
|
112192
|
+
return { status: "deleted-or-absent" };
|
|
112193
|
+
if (deletionTimestamp(record2) === null)
|
|
112194
|
+
return { status: "live", record: record2 };
|
|
112195
|
+
return { status: "deleted", version: tombstoneVersion(record2) };
|
|
112196
|
+
}
|
|
112197
|
+
function errorMessage2(err2) {
|
|
112198
|
+
return err2 instanceof Error ? err2.message : String(err2);
|
|
112199
|
+
}
|
|
112200
|
+
|
|
111551
112201
|
// ../core/dist/payment/x402.js
|
|
111552
112202
|
function generateRecordId() {
|
|
111553
112203
|
const bytes2 = new Uint8Array(32);
|
|
@@ -112028,6 +112678,63 @@ async function handleX402Cycle(input) {
|
|
|
112028
112678
|
function collectedAt(now) {
|
|
112029
112679
|
return now().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
112030
112680
|
}
|
|
112681
|
+
async function resolveReadDeletion(deps, scope, entry) {
|
|
112682
|
+
if (!deps.scopeDeletions)
|
|
112683
|
+
return null;
|
|
112684
|
+
const verdict = await deps.scopeDeletions.resolve(scope, {
|
|
112685
|
+
consultGateway: entry ? "if-stale" : "always"
|
|
112686
|
+
});
|
|
112687
|
+
if (!verdict.deleted)
|
|
112688
|
+
return null;
|
|
112689
|
+
if (entry && !isEntryCoveredByTombstone(entry, verdict)) {
|
|
112690
|
+
return null;
|
|
112691
|
+
}
|
|
112692
|
+
return {
|
|
112693
|
+
scope,
|
|
112694
|
+
dataPointId: deps.serverOwner ? computeDataPointId(deps.serverOwner, scope) : null,
|
|
112695
|
+
deletedAt: verdict.deletedAt
|
|
112696
|
+
};
|
|
112697
|
+
}
|
|
112698
|
+
async function assertScopeNotDeleted(deps, scope, entry) {
|
|
112699
|
+
const deletion = await resolveReadDeletion(deps, scope, entry);
|
|
112700
|
+
if (deletion)
|
|
112701
|
+
throw new DataDeletedError(deletion);
|
|
112702
|
+
}
|
|
112703
|
+
function discoveryVisibility(deps) {
|
|
112704
|
+
if (!deps.scopeDeletions)
|
|
112705
|
+
return void 0;
|
|
112706
|
+
return async (scope, entry) => await resolveReadDeletion(deps, scope, entry) === null;
|
|
112707
|
+
}
|
|
112708
|
+
async function ingestTombstoneMarker(deps, scope) {
|
|
112709
|
+
if (!deps.scopeDeletions)
|
|
112710
|
+
return null;
|
|
112711
|
+
const verdict = await deps.scopeDeletions.resolve(scope);
|
|
112712
|
+
if (!verdict.deleted || verdict.version === null)
|
|
112713
|
+
return null;
|
|
112714
|
+
const version4 = Number(verdict.version);
|
|
112715
|
+
return Number.isSafeInteger(version4) ? version4 : null;
|
|
112716
|
+
}
|
|
112717
|
+
function apiLoggerAsLogger(logger) {
|
|
112718
|
+
const noop = () => void 0;
|
|
112719
|
+
return {
|
|
112720
|
+
debug: (payload, message) => (logger?.debug ?? noop)(payload, message ?? ""),
|
|
112721
|
+
info: (payload, message) => (logger?.info ?? noop)(payload, message ?? ""),
|
|
112722
|
+
warn: (payload, message) => (logger?.warn ?? noop)(payload, message ?? ""),
|
|
112723
|
+
error: (payload, message) => (logger?.error ?? noop)(payload, message ?? "")
|
|
112724
|
+
};
|
|
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
|
+
}
|
|
112031
112738
|
function notifyNewData(syncManager) {
|
|
112032
112739
|
if (!syncManager)
|
|
112033
112740
|
return;
|
|
@@ -112083,24 +112790,6 @@ function resolveLineageGrantView(authResult) {
|
|
|
112083
112790
|
}
|
|
112084
112791
|
return { grantId };
|
|
112085
112792
|
}
|
|
112086
|
-
async function deleteOneScope(deps, scope) {
|
|
112087
|
-
if (deps.syncManager?.deleteScopeRemote) {
|
|
112088
|
-
try {
|
|
112089
|
-
await deps.syncManager.deleteScopeRemote(scope);
|
|
112090
|
-
} catch (err2) {
|
|
112091
|
-
deps.logger?.info?.({ scope, error: err2.message }, "Remote scope deletion failed; proceeding with local delete");
|
|
112092
|
-
}
|
|
112093
|
-
}
|
|
112094
|
-
const result = await deleteDataScopeContract({
|
|
112095
|
-
storage: deps.storage,
|
|
112096
|
-
scopeParam: scope
|
|
112097
|
-
});
|
|
112098
|
-
if (!result.ok) {
|
|
112099
|
-
throw new ProtocolError(result.status, result.body.error, result.body.message);
|
|
112100
|
-
}
|
|
112101
|
-
deps.logger?.info?.({ scope, deletedCount: result.deletedCount }, "Scope deleted");
|
|
112102
|
-
return result.deletedCount;
|
|
112103
|
-
}
|
|
112104
112793
|
async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
112105
112794
|
return withApiErrors(async () => {
|
|
112106
112795
|
const url2 = new URL(request2.url);
|
|
@@ -112113,7 +112802,8 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112113
112802
|
storage: deps.storage,
|
|
112114
112803
|
scopePrefix: url2.searchParams.get("scopePrefix") ?? void 0,
|
|
112115
112804
|
limit: normalizeLimit2(url2.searchParams.get("limit"), 20),
|
|
112116
|
-
offset: normalizeLimit2(url2.searchParams.get("offset"), 0)
|
|
112805
|
+
offset: normalizeLimit2(url2.searchParams.get("offset"), 0),
|
|
112806
|
+
isVisible: discoveryVisibility(deps)
|
|
112117
112807
|
});
|
|
112118
112808
|
return jsonResponse(result.response);
|
|
112119
112809
|
}
|
|
@@ -112122,14 +112812,18 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112122
112812
|
if (request2.method !== "GET")
|
|
112123
112813
|
return methodNotAllowed();
|
|
112124
112814
|
await deps.auth.authorizeBuilderList(request2);
|
|
112125
|
-
const result = listDataVersionsContract({
|
|
112815
|
+
const result = await listDataVersionsContract({
|
|
112126
112816
|
storage: deps.storage,
|
|
112127
112817
|
scopeParam: decodePathPart(parts[0]),
|
|
112128
112818
|
limit: normalizeLimit2(url2.searchParams.get("limit"), 20),
|
|
112129
|
-
offset: normalizeLimit2(url2.searchParams.get("offset"), 0)
|
|
112819
|
+
offset: normalizeLimit2(url2.searchParams.get("offset"), 0),
|
|
112820
|
+
isVisible: discoveryVisibility(deps)
|
|
112130
112821
|
});
|
|
112131
112822
|
if (!result.ok)
|
|
112132
112823
|
return contractErrorResponse(result);
|
|
112824
|
+
if (result.response.total === 0) {
|
|
112825
|
+
await assertScopeNotDeleted(deps, result.scope, void 0);
|
|
112826
|
+
}
|
|
112133
112827
|
return jsonResponse(result.response);
|
|
112134
112828
|
}
|
|
112135
112829
|
if ((parts.length === 2 || parts.length === 3) && parts[1] === "lineage") {
|
|
@@ -112211,6 +112905,7 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112211
112905
|
fileId: url2.searchParams.get("fileId") ?? selectedEntry?.fileId ?? void 0,
|
|
112212
112906
|
at: url2.searchParams.get("at") ?? void 0
|
|
112213
112907
|
});
|
|
112908
|
+
await assertScopeNotDeleted(deps, scopeResult.scope, selectedEntry);
|
|
112214
112909
|
const isOwnerSignal = authResult?.grantId === "owner" || authResult?.grantId === "policy-bypass";
|
|
112215
112910
|
const builder = authResult?.builder;
|
|
112216
112911
|
const resolvedGrantId = !isOwnerSignal && authResult?.grantId ? authResult.grantId : void 0;
|
|
@@ -112265,8 +112960,12 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112265
112960
|
fileId: url2.searchParams.get("fileId") ?? void 0,
|
|
112266
112961
|
at: url2.searchParams.get("at") ?? void 0
|
|
112267
112962
|
});
|
|
112268
|
-
if (!result.ok)
|
|
112963
|
+
if (!result.ok) {
|
|
112964
|
+
if (result.status === 404) {
|
|
112965
|
+
await assertScopeNotDeleted(deps, scopeResult.scope, void 0);
|
|
112966
|
+
}
|
|
112269
112967
|
return contractErrorResponse(result);
|
|
112968
|
+
}
|
|
112270
112969
|
const logId = deps.createLogId?.() ?? crypto.randomUUID();
|
|
112271
112970
|
const timestamp = (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
112272
112971
|
const ipAddress = request2.headers.get("x-forwarded-for") ?? request2.headers.get("x-real-ip") ?? "unknown";
|
|
@@ -112346,6 +113045,7 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112346
113045
|
return failWrite(contractErrorResponse(scopeResult));
|
|
112347
113046
|
const collectedAtValue = collectedAt(deps.now ?? (() => /* @__PURE__ */ new Date()));
|
|
112348
113047
|
const status2 = deps.syncManager ? "syncing" : "stored";
|
|
113048
|
+
const afterTombstoneVersion = await ingestTombstoneMarker(deps, scopeResult.scope);
|
|
112349
113049
|
const logBuilderWrite = async () => {
|
|
112350
113050
|
if (!writeAuth)
|
|
112351
113051
|
return;
|
|
@@ -112383,7 +113083,8 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112383
113083
|
collectedAt: collectedAtValue,
|
|
112384
113084
|
status: status2,
|
|
112385
113085
|
attribution: writeAuth?.attribution,
|
|
112386
|
-
lineage: lineage2
|
|
113086
|
+
lineage: lineage2,
|
|
113087
|
+
afterTombstoneVersion
|
|
112387
113088
|
});
|
|
112388
113089
|
if (!result2.ok)
|
|
112389
113090
|
return failWrite(contractErrorResponse(result2));
|
|
@@ -112398,6 +113099,11 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112398
113099
|
}, "Binary data file ingested");
|
|
112399
113100
|
await logBuilderWrite();
|
|
112400
113101
|
notifyNewData(deps.syncManager);
|
|
113102
|
+
notifyDataWritten(deps, {
|
|
113103
|
+
scope: scopeResult.scope,
|
|
113104
|
+
collectedAt: collectedAtValue,
|
|
113105
|
+
lineageSources: lineage2?.sources
|
|
113106
|
+
});
|
|
112401
113107
|
return jsonResponse(result2.response, { status: 201 });
|
|
112402
113108
|
}
|
|
112403
113109
|
const parsed = await parseJsonObjectBody(request2, "Request body must be valid JSON");
|
|
@@ -112411,7 +113117,8 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112411
113117
|
collectedAt: collectedAtValue,
|
|
112412
113118
|
status: status2,
|
|
112413
113119
|
attribution: writeAuth?.attribution,
|
|
112414
|
-
lineage
|
|
113120
|
+
lineage,
|
|
113121
|
+
afterTombstoneVersion
|
|
112415
113122
|
});
|
|
112416
113123
|
if (!result.ok)
|
|
112417
113124
|
return failWrite(contractErrorResponse(result));
|
|
@@ -112424,6 +113131,11 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112424
113131
|
}, "Data file ingested");
|
|
112425
113132
|
await logBuilderWrite();
|
|
112426
113133
|
notifyNewData(deps.syncManager);
|
|
113134
|
+
notifyDataWritten(deps, {
|
|
113135
|
+
scope: scopeResult.scope,
|
|
113136
|
+
collectedAt: collectedAtValue,
|
|
113137
|
+
lineageSources: lineage?.sources
|
|
113138
|
+
});
|
|
112427
113139
|
return jsonResponse(result.response, { status: 201 });
|
|
112428
113140
|
} catch (err2) {
|
|
112429
113141
|
if (err2 instanceof IngestPersistedError) {
|
|
@@ -112450,8 +113162,44 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
112450
113162
|
if (cascade === "lineage") {
|
|
112451
113163
|
throw new LineageCascadeUnavailableError({ scope: parsed.scope });
|
|
112452
113164
|
}
|
|
112453
|
-
await
|
|
112454
|
-
|
|
113165
|
+
const result = deps.syncManager?.deleteScope ? await deps.syncManager.deleteScope(parsed.scope) : await deleteScope({
|
|
113166
|
+
storage: deps.storage,
|
|
113167
|
+
serverOwner: deps.serverOwner,
|
|
113168
|
+
deleteData: null,
|
|
113169
|
+
logger: apiLoggerAsLogger(deps.logger)
|
|
113170
|
+
}, parsed.scope);
|
|
113171
|
+
if (result.steps.gateway.status === "failed") {
|
|
113172
|
+
throw new DeleteTombstoneFailedError({
|
|
113173
|
+
scope: parsed.scope,
|
|
113174
|
+
result
|
|
113175
|
+
});
|
|
113176
|
+
}
|
|
113177
|
+
try {
|
|
113178
|
+
await deps.accessLogWriter.write({
|
|
113179
|
+
logId: deps.createLogId?.() ?? crypto.randomUUID(),
|
|
113180
|
+
grantId: "owner",
|
|
113181
|
+
builder: deps.serverOwner ?? "owner",
|
|
113182
|
+
action: "delete",
|
|
113183
|
+
scope: parsed.scope,
|
|
113184
|
+
timestamp: (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
|
|
113185
|
+
ipAddress: request2.headers.get("x-forwarded-for") ?? request2.headers.get("x-real-ip") ?? "unknown",
|
|
113186
|
+
userAgent: request2.headers.get("user-agent") ?? "unknown"
|
|
113187
|
+
});
|
|
113188
|
+
} catch (err2) {
|
|
113189
|
+
deps.logger?.warn?.({
|
|
113190
|
+
scope: parsed.scope,
|
|
113191
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
113192
|
+
}, "Delete access-log entry failed; scope already deleted");
|
|
113193
|
+
}
|
|
113194
|
+
deps.logger?.info?.({
|
|
113195
|
+
scope: parsed.scope,
|
|
113196
|
+
durable: result.durable,
|
|
113197
|
+
gateway: result.steps.gateway.status,
|
|
113198
|
+
storage: result.steps.storage.status,
|
|
113199
|
+
local: result.steps.local.status,
|
|
113200
|
+
deletedCount: result.steps.local.deletedCount
|
|
113201
|
+
}, "Scope deleted");
|
|
113202
|
+
return jsonResponse(result, { status: 200 });
|
|
112455
113203
|
}
|
|
112456
113204
|
return methodNotAllowed();
|
|
112457
113205
|
});
|
|
@@ -112614,6 +113362,93 @@ async function handlePersonalServerOauthTokenRequest(request2, deps) {
|
|
|
112614
113362
|
});
|
|
112615
113363
|
}
|
|
112616
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
|
+
|
|
112617
113452
|
// ../core/dist/policy/data-read.js
|
|
112618
113453
|
function parseGrantExpiresAtSeconds(value) {
|
|
112619
113454
|
if (value === null || value === void 0 || value === "0")
|
|
@@ -112703,6 +113538,1084 @@ async function verifyDataReadPolicy(input, ports) {
|
|
|
112703
113538
|
return grant;
|
|
112704
113539
|
}
|
|
112705
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
|
+
|
|
112706
114619
|
// ../core/dist/mcp/store.js
|
|
112707
114620
|
function createInMemoryMcpOAuthAuthorizationStore() {
|
|
112708
114621
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -112761,6 +114674,16 @@ var McpDataReadError = class extends Error {
|
|
|
112761
114674
|
};
|
|
112762
114675
|
function createMcpDataReadClient(options) {
|
|
112763
114676
|
const basePath = options.basePath ?? "/v1/data";
|
|
114677
|
+
async function assertScopeReadable(scope, entry) {
|
|
114678
|
+
try {
|
|
114679
|
+
await assertScopeNotDeleted(options.dataApiDeps, scope, entry);
|
|
114680
|
+
} catch (err2) {
|
|
114681
|
+
if (err2 instanceof ProtocolError) {
|
|
114682
|
+
throw new McpDataReadError(err2.code, err2.toJSON());
|
|
114683
|
+
}
|
|
114684
|
+
throw err2;
|
|
114685
|
+
}
|
|
114686
|
+
}
|
|
112764
114687
|
async function authorizeScopeRead(params) {
|
|
112765
114688
|
const safeScope = encodeURIComponent(params.scope);
|
|
112766
114689
|
const signingUri = `${basePath}/${safeScope}`;
|
|
@@ -112848,6 +114771,9 @@ function createMcpDataReadClient(options) {
|
|
|
112848
114771
|
const entry = storage.findEntry({ scope });
|
|
112849
114772
|
if (!entry)
|
|
112850
114773
|
return null;
|
|
114774
|
+
if (await resolveReadDeletion(options.dataApiDeps, scope, entry)) {
|
|
114775
|
+
return null;
|
|
114776
|
+
}
|
|
112851
114777
|
const hasBlocks = typeof storage.hasScopeBlocks === "function" ? await storage.hasScopeBlocks(scope, entry.collectedAt) : false;
|
|
112852
114778
|
return {
|
|
112853
114779
|
scope,
|
|
@@ -112876,6 +114802,7 @@ function createMcpDataReadClient(options) {
|
|
|
112876
114802
|
message: `No data found for scope "${scope}"`
|
|
112877
114803
|
});
|
|
112878
114804
|
}
|
|
114805
|
+
await assertScopeReadable(scope, selectedEntry);
|
|
112879
114806
|
const { request: request2, authResult } = await authorizeScopeRead({
|
|
112880
114807
|
scope,
|
|
112881
114808
|
grantId,
|
|
@@ -112933,6 +114860,7 @@ function createMcpDataReadClient(options) {
|
|
|
112933
114860
|
message: `No data found for scope "${scope}"`
|
|
112934
114861
|
});
|
|
112935
114862
|
}
|
|
114863
|
+
await assertScopeReadable(scope, selectedEntry);
|
|
112936
114864
|
const { request: request2, authResult } = await authorizeScopeRead({
|
|
112937
114865
|
scope,
|
|
112938
114866
|
grantId,
|
|
@@ -116596,15 +118524,15 @@ var makeIssue = (params) => {
|
|
|
116596
118524
|
message: issueData.message
|
|
116597
118525
|
};
|
|
116598
118526
|
}
|
|
116599
|
-
let
|
|
118527
|
+
let errorMessage3 = "";
|
|
116600
118528
|
const maps = errorMaps.filter((m10) => !!m10).slice().reverse();
|
|
116601
118529
|
for (const map2 of maps) {
|
|
116602
|
-
|
|
118530
|
+
errorMessage3 = map2(fullIssue, { data, defaultError: errorMessage3 }).message;
|
|
116603
118531
|
}
|
|
116604
118532
|
return {
|
|
116605
118533
|
...issueData,
|
|
116606
118534
|
path: fullPath,
|
|
116607
|
-
message:
|
|
118535
|
+
message: errorMessage3
|
|
116608
118536
|
};
|
|
116609
118537
|
};
|
|
116610
118538
|
function addIssueToContext(ctx, issueData) {
|
|
@@ -121884,19 +123812,19 @@ var getRefs = (options) => {
|
|
|
121884
123812
|
};
|
|
121885
123813
|
|
|
121886
123814
|
// ../../node_modules/zod-to-json-schema/dist/esm/errorMessages.js
|
|
121887
|
-
function addErrorMessage(res, key,
|
|
123815
|
+
function addErrorMessage(res, key, errorMessage3, refs) {
|
|
121888
123816
|
if (!refs?.errorMessages)
|
|
121889
123817
|
return;
|
|
121890
|
-
if (
|
|
123818
|
+
if (errorMessage3) {
|
|
121891
123819
|
res.errorMessage = {
|
|
121892
123820
|
...res.errorMessage,
|
|
121893
|
-
[key]:
|
|
123821
|
+
[key]: errorMessage3
|
|
121894
123822
|
};
|
|
121895
123823
|
}
|
|
121896
123824
|
}
|
|
121897
|
-
function setResponseValueAndErrors(res, key, value,
|
|
123825
|
+
function setResponseValueAndErrors(res, key, value, errorMessage3, refs) {
|
|
121898
123826
|
res[key] = value;
|
|
121899
|
-
addErrorMessage(res, key,
|
|
123827
|
+
addErrorMessage(res, key, errorMessage3, refs);
|
|
121900
123828
|
}
|
|
121901
123829
|
|
|
121902
123830
|
// ../../node_modules/zod-to-json-schema/dist/esm/getRelativePath.js
|
|
@@ -123207,8 +125135,8 @@ var Protocol = class {
|
|
|
123207
125135
|
if (queuedMessage.type === "response") {
|
|
123208
125136
|
resolver(message);
|
|
123209
125137
|
} else {
|
|
123210
|
-
const
|
|
123211
|
-
const error51 = new McpError(
|
|
125138
|
+
const errorMessage3 = message;
|
|
125139
|
+
const error51 = new McpError(errorMessage3.error.code, errorMessage3.error.message, errorMessage3.error.data);
|
|
123212
125140
|
resolver(error51);
|
|
123213
125141
|
}
|
|
123214
125142
|
} else {
|
|
@@ -123396,7 +125324,7 @@ var Protocol = class {
|
|
|
123396
125324
|
const capturedTransport = this._transport;
|
|
123397
125325
|
const relatedTaskId = request2.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
123398
125326
|
if (handler === void 0) {
|
|
123399
|
-
const
|
|
125327
|
+
const errorResponse4 = {
|
|
123400
125328
|
jsonrpc: "2.0",
|
|
123401
125329
|
id: request2.id,
|
|
123402
125330
|
error: {
|
|
@@ -123407,11 +125335,11 @@ var Protocol = class {
|
|
|
123407
125335
|
if (relatedTaskId && this._taskMessageQueue) {
|
|
123408
125336
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
123409
125337
|
type: "error",
|
|
123410
|
-
message:
|
|
125338
|
+
message: errorResponse4,
|
|
123411
125339
|
timestamp: Date.now()
|
|
123412
125340
|
}, capturedTransport?.sessionId).catch((error51) => this._onerror(new Error(`Failed to enqueue error response: ${error51}`)));
|
|
123413
125341
|
} else {
|
|
123414
|
-
capturedTransport?.send(
|
|
125342
|
+
capturedTransport?.send(errorResponse4).catch((error51) => this._onerror(new Error(`Failed to send an error response: ${error51}`)));
|
|
123415
125343
|
}
|
|
123416
125344
|
return;
|
|
123417
125345
|
}
|
|
@@ -123481,7 +125409,7 @@ var Protocol = class {
|
|
|
123481
125409
|
if (abortController.signal.aborted) {
|
|
123482
125410
|
return;
|
|
123483
125411
|
}
|
|
123484
|
-
const
|
|
125412
|
+
const errorResponse4 = {
|
|
123485
125413
|
jsonrpc: "2.0",
|
|
123486
125414
|
id: request2.id,
|
|
123487
125415
|
error: {
|
|
@@ -123493,11 +125421,11 @@ var Protocol = class {
|
|
|
123493
125421
|
if (relatedTaskId && this._taskMessageQueue) {
|
|
123494
125422
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
123495
125423
|
type: "error",
|
|
123496
|
-
message:
|
|
125424
|
+
message: errorResponse4,
|
|
123497
125425
|
timestamp: Date.now()
|
|
123498
125426
|
}, capturedTransport?.sessionId);
|
|
123499
125427
|
} else {
|
|
123500
|
-
await capturedTransport?.send(
|
|
125428
|
+
await capturedTransport?.send(errorResponse4);
|
|
123501
125429
|
}
|
|
123502
125430
|
}).catch((error51) => this._onerror(new Error(`Failed to send response: ${error51}`))).finally(() => {
|
|
123503
125431
|
if (this._requestHandlerAbortControllers.get(request2.id) === abortController) {
|
|
@@ -124508,23 +126436,23 @@ var Server = class extends Protocol {
|
|
|
124508
126436
|
const wrappedHandler = async (request2, extra) => {
|
|
124509
126437
|
const validatedRequest = safeParse3(CallToolRequestSchema, request2);
|
|
124510
126438
|
if (!validatedRequest.success) {
|
|
124511
|
-
const
|
|
124512
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${
|
|
126439
|
+
const errorMessage3 = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
126440
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage3}`);
|
|
124513
126441
|
}
|
|
124514
126442
|
const { params } = validatedRequest.data;
|
|
124515
126443
|
const result = await Promise.resolve(handler(request2, extra));
|
|
124516
126444
|
if (params.task) {
|
|
124517
126445
|
const taskValidationResult = safeParse3(CreateTaskResultSchema, result);
|
|
124518
126446
|
if (!taskValidationResult.success) {
|
|
124519
|
-
const
|
|
124520
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${
|
|
126447
|
+
const errorMessage3 = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
126448
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage3}`);
|
|
124521
126449
|
}
|
|
124522
126450
|
return taskValidationResult.data;
|
|
124523
126451
|
}
|
|
124524
126452
|
const validationResult = safeParse3(CallToolResultSchema, result);
|
|
124525
126453
|
if (!validationResult.success) {
|
|
124526
|
-
const
|
|
124527
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${
|
|
126454
|
+
const errorMessage3 = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
126455
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage3}`);
|
|
124528
126456
|
}
|
|
124529
126457
|
return validationResult.data;
|
|
124530
126458
|
};
|
|
@@ -125240,12 +127168,12 @@ var McpServer = class {
|
|
|
125240
127168
|
* @param errorMessage - The error message.
|
|
125241
127169
|
* @returns The tool error result.
|
|
125242
127170
|
*/
|
|
125243
|
-
createToolError(
|
|
127171
|
+
createToolError(errorMessage3) {
|
|
125244
127172
|
return {
|
|
125245
127173
|
content: [
|
|
125246
127174
|
{
|
|
125247
127175
|
type: "text",
|
|
125248
|
-
text:
|
|
127176
|
+
text: errorMessage3
|
|
125249
127177
|
}
|
|
125250
127178
|
],
|
|
125251
127179
|
isError: true
|
|
@@ -125263,8 +127191,8 @@ var McpServer = class {
|
|
|
125263
127191
|
const parseResult = await safeParseAsync3(schemaToParse, args);
|
|
125264
127192
|
if (!parseResult.success) {
|
|
125265
127193
|
const error51 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
125266
|
-
const
|
|
125267
|
-
throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${
|
|
127194
|
+
const errorMessage3 = getParseErrorMessage(error51);
|
|
127195
|
+
throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage3}`);
|
|
125268
127196
|
}
|
|
125269
127197
|
return parseResult.data;
|
|
125270
127198
|
}
|
|
@@ -125288,8 +127216,8 @@ var McpServer = class {
|
|
|
125288
127216
|
const parseResult = await safeParseAsync3(outputObj, result.structuredContent);
|
|
125289
127217
|
if (!parseResult.success) {
|
|
125290
127218
|
const error51 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
125291
|
-
const
|
|
125292
|
-
throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${
|
|
127219
|
+
const errorMessage3 = getParseErrorMessage(error51);
|
|
127220
|
+
throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage3}`);
|
|
125293
127221
|
}
|
|
125294
127222
|
}
|
|
125295
127223
|
/**
|
|
@@ -125501,8 +127429,8 @@ var McpServer = class {
|
|
|
125501
127429
|
const parseResult = await safeParseAsync3(argsObj, request2.params.arguments);
|
|
125502
127430
|
if (!parseResult.success) {
|
|
125503
127431
|
const error51 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
125504
|
-
const
|
|
125505
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request2.params.name}: ${
|
|
127432
|
+
const errorMessage3 = getParseErrorMessage(error51);
|
|
127433
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request2.params.name}: ${errorMessage3}`);
|
|
125506
127434
|
}
|
|
125507
127435
|
const args = parseResult.data;
|
|
125508
127436
|
const cb2 = prompt.callback;
|
|
@@ -127120,16 +129048,16 @@ async function collectDiagnosticsWithTimeout(recorder, options, timeoutMs = DIAG
|
|
|
127120
129048
|
}
|
|
127121
129049
|
|
|
127122
129050
|
// ../lite/dist/runtime.js
|
|
127123
|
-
function
|
|
129051
|
+
function jsonResponse3(body, init) {
|
|
127124
129052
|
const headers = new Headers(init?.headers);
|
|
127125
129053
|
headers.set("Content-Type", "application/json");
|
|
127126
129054
|
return new Response(JSON.stringify(body), { ...init, headers });
|
|
127127
129055
|
}
|
|
127128
129056
|
function protocolErrorResponse2(err2) {
|
|
127129
|
-
return
|
|
129057
|
+
return jsonResponse3(err2.toJSON(), { status: err2.code });
|
|
127130
129058
|
}
|
|
127131
|
-
function
|
|
127132
|
-
return
|
|
129059
|
+
function errorResponse3(status2, errorCode, message) {
|
|
129060
|
+
return jsonResponse3({
|
|
127133
129061
|
error: {
|
|
127134
129062
|
code: status2,
|
|
127135
129063
|
errorCode,
|
|
@@ -127138,7 +129066,7 @@ function errorResponse2(status2, errorCode, message) {
|
|
|
127138
129066
|
}, { status: status2 });
|
|
127139
129067
|
}
|
|
127140
129068
|
function mcpUnauthorized(origin, message = "MCP authorization required") {
|
|
127141
|
-
return
|
|
129069
|
+
return jsonResponse3({
|
|
127142
129070
|
error: {
|
|
127143
129071
|
code: 401,
|
|
127144
129072
|
errorCode: "MCP_AUTH_REQUIRED",
|
|
@@ -127187,7 +129115,7 @@ function redirectWithOAuthError(redirectUri, error51, description, state) {
|
|
|
127187
129115
|
url2.searchParams.set("state", state);
|
|
127188
129116
|
return Response.redirect(url2.toString(), 302);
|
|
127189
129117
|
} catch {
|
|
127190
|
-
return
|
|
129118
|
+
return jsonResponse3({
|
|
127191
129119
|
error: error51,
|
|
127192
129120
|
error_description: description,
|
|
127193
129121
|
...state ? { state } : {}
|
|
@@ -127393,11 +129321,11 @@ function createPsLiteRuntime(options) {
|
|
|
127393
129321
|
if (err2 instanceof ProtocolError) {
|
|
127394
129322
|
return protocolErrorResponse2(err2);
|
|
127395
129323
|
}
|
|
127396
|
-
return
|
|
129324
|
+
return errorResponse3(500, "INTERNAL_ERROR", "Internal server error");
|
|
127397
129325
|
}
|
|
127398
129326
|
}
|
|
127399
129327
|
function sendContractResult(result) {
|
|
127400
|
-
return
|
|
129328
|
+
return jsonResponse3(result.body, { status: result.status });
|
|
127401
129329
|
}
|
|
127402
129330
|
function ownerAddress() {
|
|
127403
129331
|
return options.serverOwner ?? options.identity?.address;
|
|
@@ -127405,7 +129333,7 @@ function createPsLiteRuntime(options) {
|
|
|
127405
129333
|
async function handleAuthDevice(request2, url2) {
|
|
127406
129334
|
if (url2.pathname === "/auth/device") {
|
|
127407
129335
|
if (request2.method !== "POST") {
|
|
127408
|
-
return
|
|
129336
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127409
129337
|
}
|
|
127410
129338
|
return sendContractResult(initiateDeviceSessionContract({
|
|
127411
129339
|
sessionStore: deviceSessions,
|
|
@@ -127419,7 +129347,7 @@ function createPsLiteRuntime(options) {
|
|
|
127419
129347
|
}
|
|
127420
129348
|
if (url2.pathname === "/auth/device/poll") {
|
|
127421
129349
|
if (request2.method !== "GET") {
|
|
127422
|
-
return
|
|
129350
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127423
129351
|
}
|
|
127424
129352
|
return sendContractResult(pollDeviceSessionContract({
|
|
127425
129353
|
sessionStore: deviceSessions,
|
|
@@ -127431,11 +129359,11 @@ function createPsLiteRuntime(options) {
|
|
|
127431
129359
|
if (url2.pathname === "/auth/device/approve") {
|
|
127432
129360
|
const sessionId = url2.searchParams.get("session");
|
|
127433
129361
|
if (!sessionId) {
|
|
127434
|
-
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 });
|
|
127435
129363
|
}
|
|
127436
129364
|
const session = deviceSessions.get(sessionId);
|
|
127437
129365
|
if (!session) {
|
|
127438
|
-
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 });
|
|
127439
129367
|
}
|
|
127440
129368
|
if (request2.method === "GET") {
|
|
127441
129369
|
return new Response("Device authorization pending", {
|
|
@@ -127443,10 +129371,10 @@ function createPsLiteRuntime(options) {
|
|
|
127443
129371
|
});
|
|
127444
129372
|
}
|
|
127445
129373
|
if (request2.method !== "POST") {
|
|
127446
|
-
return
|
|
129374
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127447
129375
|
}
|
|
127448
129376
|
if (session.status === "approved") {
|
|
127449
|
-
return
|
|
129377
|
+
return jsonResponse3({ status: "already_approved" });
|
|
127450
129378
|
}
|
|
127451
129379
|
await auth.authorizeOwner(request2);
|
|
127452
129380
|
return sendContractResult(await approveDeviceSessionContract({
|
|
@@ -127462,7 +129390,7 @@ function createPsLiteRuntime(options) {
|
|
|
127462
129390
|
if (request2.method === "DELETE") {
|
|
127463
129391
|
const token2 = bearerToken(request2);
|
|
127464
129392
|
if (!token2) {
|
|
127465
|
-
return
|
|
129393
|
+
return jsonResponse3({ error: { code: 401, message: "Missing Bearer token" } }, { status: 401 });
|
|
127466
129394
|
}
|
|
127467
129395
|
return sendContractResult(await revokeDeviceTokenContract({
|
|
127468
129396
|
tokenStore,
|
|
@@ -127470,11 +129398,11 @@ function createPsLiteRuntime(options) {
|
|
|
127470
129398
|
}));
|
|
127471
129399
|
}
|
|
127472
129400
|
if (request2.method !== "POST") {
|
|
127473
|
-
return
|
|
129401
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127474
129402
|
}
|
|
127475
129403
|
const token = bearerToken(request2);
|
|
127476
129404
|
if (!options.accessToken || token !== options.accessToken) {
|
|
127477
|
-
return
|
|
129405
|
+
return jsonResponse3({
|
|
127478
129406
|
error: {
|
|
127479
129407
|
code: 403,
|
|
127480
129408
|
message: "Only control-plane tokens can provision Personal Server session tokens"
|
|
@@ -127485,10 +129413,10 @@ function createPsLiteRuntime(options) {
|
|
|
127485
129413
|
try {
|
|
127486
129414
|
body = await request2.json();
|
|
127487
129415
|
} catch {
|
|
127488
|
-
return
|
|
129416
|
+
return jsonResponse3({ error: { code: 400, message: "Request body must be valid JSON" } }, { status: 400 });
|
|
127489
129417
|
}
|
|
127490
129418
|
if (!body.token || typeof body.token !== "string") {
|
|
127491
|
-
return
|
|
129419
|
+
return jsonResponse3({ error: { code: 400, message: "Missing token" } }, { status: 400 });
|
|
127492
129420
|
}
|
|
127493
129421
|
return sendContractResult(await provisionDeviceTokenContract({
|
|
127494
129422
|
tokenStore,
|
|
@@ -127504,10 +129432,12 @@ function createPsLiteRuntime(options) {
|
|
|
127504
129432
|
activate() {
|
|
127505
129433
|
active = true;
|
|
127506
129434
|
options.syncManager?.start?.();
|
|
129435
|
+
options.derivatives?.scheduler.start();
|
|
127507
129436
|
},
|
|
127508
129437
|
deactivate() {
|
|
127509
129438
|
active = false;
|
|
127510
129439
|
void options.syncManager?.stop?.();
|
|
129440
|
+
options.derivatives?.scheduler.stop();
|
|
127511
129441
|
},
|
|
127512
129442
|
isAvailable() {
|
|
127513
129443
|
return active;
|
|
@@ -127541,7 +129471,7 @@ function createPsLiteRuntime(options) {
|
|
|
127541
129471
|
accessLogs: accessLogReader.capabilities?.accessLogs ?? "custom",
|
|
127542
129472
|
config: options.stateCapabilities?.config ?? (options.saveConfig ? "custom" : "indexeddb")
|
|
127543
129473
|
};
|
|
127544
|
-
return
|
|
129474
|
+
return jsonResponse3({
|
|
127545
129475
|
status: active ? "healthy" : "unavailable",
|
|
127546
129476
|
runtime: "ps-lite",
|
|
127547
129477
|
storage: options.storage.kind,
|
|
@@ -127559,7 +129489,7 @@ function createPsLiteRuntime(options) {
|
|
|
127559
129489
|
}
|
|
127560
129490
|
if (url2.pathname === "/v1/diagnostics") {
|
|
127561
129491
|
if (request2.method !== "GET") {
|
|
127562
|
-
return
|
|
129492
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127563
129493
|
}
|
|
127564
129494
|
try {
|
|
127565
129495
|
await auth.authorizeOwner(request2);
|
|
@@ -127570,7 +129500,7 @@ function createPsLiteRuntime(options) {
|
|
|
127570
129500
|
throw err2;
|
|
127571
129501
|
}
|
|
127572
129502
|
if (!options.diagnostics) {
|
|
127573
|
-
return
|
|
129503
|
+
return jsonResponse3({
|
|
127574
129504
|
error: {
|
|
127575
129505
|
code: 404,
|
|
127576
129506
|
errorCode: "DIAGNOSTICS_NOT_CONFIGURED",
|
|
@@ -127584,7 +129514,7 @@ function createPsLiteRuntime(options) {
|
|
|
127584
129514
|
syncStatus: syncStatus2,
|
|
127585
129515
|
storage: dataStorage
|
|
127586
129516
|
});
|
|
127587
|
-
return
|
|
129517
|
+
return jsonResponse3(snapshot);
|
|
127588
129518
|
}
|
|
127589
129519
|
if (!active) {
|
|
127590
129520
|
return unavailableResponse();
|
|
@@ -127598,6 +129528,7 @@ function createPsLiteRuntime(options) {
|
|
|
127598
129528
|
accessLogWriter,
|
|
127599
129529
|
readFulfillmentReporter: options.readFulfillmentReporter,
|
|
127600
129530
|
syncManager: options.syncManager ?? null,
|
|
129531
|
+
scopeDeletions: options.scopeDeletions,
|
|
127601
129532
|
now,
|
|
127602
129533
|
createLogId,
|
|
127603
129534
|
// x402 payment enforcement for builder reads. Only engages with a
|
|
@@ -127618,9 +129549,16 @@ function createPsLiteRuntime(options) {
|
|
|
127618
129549
|
// serverOwner is absent the accessRecord is safely omitted.
|
|
127619
129550
|
serverOwner: options.serverOwner,
|
|
127620
129551
|
serverSigner: x402ServerSigner,
|
|
127621
|
-
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
|
|
127622
129556
|
}, { basePath: dataPrefix });
|
|
127623
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
|
+
}
|
|
127624
129562
|
if (url2.pathname.startsWith("/auth/device")) {
|
|
127625
129563
|
const response = await handleAuthDevice(request2, url2);
|
|
127626
129564
|
if (response)
|
|
@@ -127709,7 +129647,7 @@ function createPsLiteRuntime(options) {
|
|
|
127709
129647
|
if (mcpResponse)
|
|
127710
129648
|
return mcpResponse;
|
|
127711
129649
|
}
|
|
127712
|
-
return
|
|
129650
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
127713
129651
|
});
|
|
127714
129652
|
}
|
|
127715
129653
|
};
|
|
@@ -127720,22 +129658,22 @@ async function handleMcpRoute(input) {
|
|
|
127720
129658
|
const ownerAuthorizationPrefix = "/v1/mcp/oauth/authorizations";
|
|
127721
129659
|
if (pathname === "/.well-known/oauth-protected-resource/mcp") {
|
|
127722
129660
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
127723
|
-
return
|
|
129661
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
127724
129662
|
}
|
|
127725
|
-
return
|
|
129663
|
+
return jsonResponse3(protectedResourceMetadata(input.serverOrigin));
|
|
127726
129664
|
}
|
|
127727
129665
|
if (pathname === "/.well-known/oauth-authorization-server") {
|
|
127728
129666
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
127729
|
-
return
|
|
129667
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
127730
129668
|
}
|
|
127731
|
-
return
|
|
129669
|
+
return jsonResponse3(authorizationServerMetadata(input.serverOrigin));
|
|
127732
129670
|
}
|
|
127733
129671
|
if (pathname === "/mcp/oauth/register") {
|
|
127734
129672
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
127735
|
-
return
|
|
129673
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
127736
129674
|
}
|
|
127737
129675
|
if (input.request.method !== "POST") {
|
|
127738
|
-
return
|
|
129676
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127739
129677
|
}
|
|
127740
129678
|
let body = {};
|
|
127741
129679
|
try {
|
|
@@ -127743,7 +129681,7 @@ async function handleMcpRoute(input) {
|
|
|
127743
129681
|
} catch {
|
|
127744
129682
|
body = {};
|
|
127745
129683
|
}
|
|
127746
|
-
return
|
|
129684
|
+
return jsonResponse3({
|
|
127747
129685
|
client_id: `mcp-client-${crypto.randomUUID()}`,
|
|
127748
129686
|
client_name: body.client_name ?? "Claude",
|
|
127749
129687
|
redirect_uris: Array.isArray(body.redirect_uris) ? body.redirect_uris : [],
|
|
@@ -127754,10 +129692,10 @@ async function handleMcpRoute(input) {
|
|
|
127754
129692
|
}
|
|
127755
129693
|
if (pathname === "/mcp/oauth/authorize") {
|
|
127756
129694
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
127757
|
-
return
|
|
129695
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
127758
129696
|
}
|
|
127759
129697
|
if (input.request.method !== "GET") {
|
|
127760
|
-
return
|
|
129698
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127761
129699
|
}
|
|
127762
129700
|
const responseType = input.url.searchParams.get("response_type");
|
|
127763
129701
|
const clientId = input.url.searchParams.get("client_id") ?? "";
|
|
@@ -127785,7 +129723,7 @@ async function handleMcpRoute(input) {
|
|
|
127785
129723
|
});
|
|
127786
129724
|
const approvalUrl = resolveMcpApprovalUrl(input.approvalUrl);
|
|
127787
129725
|
if (!approvalUrl) {
|
|
127788
|
-
return
|
|
129726
|
+
return errorResponse3(500, "MCP_APPROVAL_URL_MISSING", "MCP OAuth approval URL is not configured");
|
|
127789
129727
|
}
|
|
127790
129728
|
const approve = new URL(approvalUrl);
|
|
127791
129729
|
approve.searchParams.set("mcp_authorization", created.authorizationId);
|
|
@@ -127798,14 +129736,14 @@ async function handleMcpRoute(input) {
|
|
|
127798
129736
|
}
|
|
127799
129737
|
if (pathname === "/mcp/oauth/token") {
|
|
127800
129738
|
if (!resolveMcpApprovalUrl(input.approvalUrl)) {
|
|
127801
|
-
return
|
|
129739
|
+
return errorResponse3(404, "MCP_OAUTH_NOT_CONFIGURED", "MCP OAuth is not configured");
|
|
127802
129740
|
}
|
|
127803
129741
|
if (input.request.method !== "POST") {
|
|
127804
|
-
return
|
|
129742
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127805
129743
|
}
|
|
127806
129744
|
const body = await parseFormBody(input.request);
|
|
127807
129745
|
if (body.get("grant_type") !== "authorization_code") {
|
|
127808
|
-
return
|
|
129746
|
+
return jsonResponse3({
|
|
127809
129747
|
error: "unsupported_grant_type",
|
|
127810
129748
|
error_description: "Only authorization_code is supported"
|
|
127811
129749
|
}, { status: 400 });
|
|
@@ -127821,13 +129759,13 @@ async function handleMcpRoute(input) {
|
|
|
127821
129759
|
connectionStore: input.store,
|
|
127822
129760
|
now: input.now
|
|
127823
129761
|
});
|
|
127824
|
-
return
|
|
129762
|
+
return jsonResponse3({
|
|
127825
129763
|
access_token: token.accessToken,
|
|
127826
129764
|
token_type: "Bearer",
|
|
127827
129765
|
...token.scope ? { scope: token.scope } : {}
|
|
127828
129766
|
});
|
|
127829
129767
|
} catch (err2) {
|
|
127830
|
-
return
|
|
129768
|
+
return jsonResponse3({
|
|
127831
129769
|
error: err2 instanceof McpOAuthAuthorizationError ? err2.code : "invalid_grant",
|
|
127832
129770
|
error_description: err2 instanceof Error ? err2.message : String(err2)
|
|
127833
129771
|
}, { status: 400 });
|
|
@@ -127845,28 +129783,28 @@ async function handleMcpRoute(input) {
|
|
|
127845
129783
|
const tail = pathname.slice(ownerAuthorizationPrefix.length + 1);
|
|
127846
129784
|
const [id2, action] = tail.split("/");
|
|
127847
129785
|
if (!id2) {
|
|
127848
|
-
return
|
|
129786
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
127849
129787
|
}
|
|
127850
129788
|
if (!action && input.request.method === "GET") {
|
|
127851
129789
|
const record2 = await input.authorizationStore.getById(id2);
|
|
127852
129790
|
if (!record2) {
|
|
127853
|
-
return
|
|
129791
|
+
return errorResponse3(404, "NOT_FOUND", "Authorization not found");
|
|
127854
129792
|
}
|
|
127855
|
-
return
|
|
129793
|
+
return jsonResponse3(toMcpOAuthAuthorizationView(record2));
|
|
127856
129794
|
}
|
|
127857
129795
|
if (action === "approve") {
|
|
127858
129796
|
if (input.request.method !== "POST") {
|
|
127859
|
-
return
|
|
129797
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127860
129798
|
}
|
|
127861
129799
|
let body = {};
|
|
127862
129800
|
try {
|
|
127863
129801
|
body = await input.request.json();
|
|
127864
129802
|
} catch {
|
|
127865
|
-
return
|
|
129803
|
+
return errorResponse3(400, "INVALID_BODY", "Body must be JSON");
|
|
127866
129804
|
}
|
|
127867
129805
|
if (Array.isArray(body.scopes) && body.scopes.length > 0) {
|
|
127868
129806
|
if (!input.gateway || !input.gatewayConfig?.url) {
|
|
127869
|
-
return
|
|
129807
|
+
return errorResponse3(500, "SERVER_NOT_CONFIGURED", "Gateway config is not configured");
|
|
127870
129808
|
}
|
|
127871
129809
|
try {
|
|
127872
129810
|
const approved = await approveMcpOAuthAuthorizationWithScopes({
|
|
@@ -127884,16 +129822,16 @@ async function handleMcpRoute(input) {
|
|
|
127884
129822
|
serverSigner: input.serverSigner,
|
|
127885
129823
|
now: input.now
|
|
127886
129824
|
});
|
|
127887
|
-
return
|
|
129825
|
+
return jsonResponse3({ redirectTo: approved.redirectTo });
|
|
127888
129826
|
} catch (err2) {
|
|
127889
129827
|
if (err2 instanceof McpOAuthAuthorizationError) {
|
|
127890
|
-
return
|
|
129828
|
+
return errorResponse3(err2.status, err2.code, err2.message);
|
|
127891
129829
|
}
|
|
127892
129830
|
throw err2;
|
|
127893
129831
|
}
|
|
127894
129832
|
}
|
|
127895
129833
|
if (!Array.isArray(body.grants) || body.grants.length === 0) {
|
|
127896
|
-
return
|
|
129834
|
+
return errorResponse3(400, "GRANTS_REQUIRED", "Approve requires grants or scopes");
|
|
127897
129835
|
}
|
|
127898
129836
|
try {
|
|
127899
129837
|
const approved = await approveMcpOAuthAuthorization({ authorizationId: id2, grants: body.grants }, {
|
|
@@ -127901,15 +129839,15 @@ async function handleMcpRoute(input) {
|
|
|
127901
129839
|
authorizationStore: input.authorizationStore,
|
|
127902
129840
|
now: input.now
|
|
127903
129841
|
});
|
|
127904
|
-
return
|
|
129842
|
+
return jsonResponse3({ redirectTo: approved.redirectTo });
|
|
127905
129843
|
} catch (err2) {
|
|
127906
129844
|
if (err2 instanceof McpOAuthAuthorizationError) {
|
|
127907
|
-
return
|
|
129845
|
+
return errorResponse3(err2.status, err2.code, err2.message);
|
|
127908
129846
|
}
|
|
127909
129847
|
throw err2;
|
|
127910
129848
|
}
|
|
127911
129849
|
}
|
|
127912
|
-
return
|
|
129850
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
127913
129851
|
}
|
|
127914
129852
|
if (pathname === ownerPrefix || pathname.startsWith(`${ownerPrefix}/`)) {
|
|
127915
129853
|
try {
|
|
@@ -127933,41 +129871,41 @@ async function handleMcpRoute(input) {
|
|
|
127933
129871
|
publicOrigin: input.serverOrigin,
|
|
127934
129872
|
now: input.now
|
|
127935
129873
|
});
|
|
127936
|
-
return
|
|
129874
|
+
return jsonResponse3(created, { status: 201 });
|
|
127937
129875
|
}
|
|
127938
129876
|
if (input.request.method === "GET") {
|
|
127939
129877
|
const records = await listMcpConnectionViews(input.store);
|
|
127940
|
-
return
|
|
129878
|
+
return jsonResponse3({ connections: records });
|
|
127941
129879
|
}
|
|
127942
|
-
return
|
|
129880
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127943
129881
|
}
|
|
127944
129882
|
const tail = pathname.slice(ownerPrefix.length + 1);
|
|
127945
129883
|
const [id2, action] = tail.split("/");
|
|
127946
129884
|
if (!id2) {
|
|
127947
|
-
return
|
|
129885
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
127948
129886
|
}
|
|
127949
129887
|
if (action === "approve") {
|
|
127950
129888
|
if (input.request.method !== "POST") {
|
|
127951
|
-
return
|
|
129889
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127952
129890
|
}
|
|
127953
129891
|
let body = {};
|
|
127954
129892
|
try {
|
|
127955
129893
|
body = await input.request.json();
|
|
127956
129894
|
} catch {
|
|
127957
|
-
return
|
|
129895
|
+
return errorResponse3(400, "INVALID_BODY", "Body must be JSON");
|
|
127958
129896
|
}
|
|
127959
129897
|
if (!Array.isArray(body.grants) || body.grants.length === 0) {
|
|
127960
|
-
return
|
|
129898
|
+
return errorResponse3(400, "GRANTS_REQUIRED", "Approve requires at least one grant \u2014 mint grants in the consent flow first");
|
|
127961
129899
|
}
|
|
127962
129900
|
try {
|
|
127963
129901
|
const updated = await approveMcpConnection({ connectionId: id2, grants: body.grants }, { store: input.store, now: input.now });
|
|
127964
|
-
return
|
|
129902
|
+
return jsonResponse3(toMcpConnectionView(updated));
|
|
127965
129903
|
} catch (err2) {
|
|
127966
129904
|
if (err2 instanceof McpConnectionNotFoundError) {
|
|
127967
|
-
return
|
|
129905
|
+
return errorResponse3(404, "NOT_FOUND", err2.message);
|
|
127968
129906
|
}
|
|
127969
129907
|
if (err2 instanceof McpConnectionStateError) {
|
|
127970
|
-
return
|
|
129908
|
+
return errorResponse3(409, "INVALID_STATE", err2.message);
|
|
127971
129909
|
}
|
|
127972
129910
|
throw err2;
|
|
127973
129911
|
}
|
|
@@ -127979,22 +129917,22 @@ async function handleMcpRoute(input) {
|
|
|
127979
129917
|
store: input.store,
|
|
127980
129918
|
now: input.now
|
|
127981
129919
|
});
|
|
127982
|
-
return
|
|
129920
|
+
return jsonResponse3(toMcpConnectionView(updated));
|
|
127983
129921
|
} catch (err2) {
|
|
127984
129922
|
if (err2 instanceof McpConnectionNotFoundError) {
|
|
127985
|
-
return
|
|
129923
|
+
return errorResponse3(404, "NOT_FOUND", err2.message);
|
|
127986
129924
|
}
|
|
127987
129925
|
throw err2;
|
|
127988
129926
|
}
|
|
127989
129927
|
}
|
|
127990
|
-
return
|
|
129928
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
127991
129929
|
}
|
|
127992
|
-
return
|
|
129930
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
127993
129931
|
}
|
|
127994
129932
|
async function handleMcpToken(rawToken, options) {
|
|
127995
129933
|
if (!rawToken) {
|
|
127996
129934
|
if (!options.oauthChallenge) {
|
|
127997
|
-
return
|
|
129935
|
+
return errorResponse3(401, "INVALID_TOKEN", "Missing MCP connection token");
|
|
127998
129936
|
}
|
|
127999
129937
|
return mcpUnauthorized(input.serverOrigin);
|
|
128000
129938
|
}
|
|
@@ -128002,7 +129940,7 @@ async function handleMcpRoute(input) {
|
|
|
128002
129940
|
const record2 = await input.store.getByTokenHash(tokenHash);
|
|
128003
129941
|
if (!record2) {
|
|
128004
129942
|
if (!options.oauthChallenge) {
|
|
128005
|
-
return
|
|
129943
|
+
return errorResponse3(401, "INVALID_TOKEN", "Unknown or revoked MCP connection");
|
|
128006
129944
|
}
|
|
128007
129945
|
return mcpUnauthorized(input.serverOrigin, "Unknown or revoked MCP connection");
|
|
128008
129946
|
}
|
|
@@ -128046,10 +129984,10 @@ async function handleMcpRoute(input) {
|
|
|
128046
129984
|
throw err2;
|
|
128047
129985
|
}
|
|
128048
129986
|
if (input.request.method !== "GET") {
|
|
128049
|
-
return
|
|
129987
|
+
return errorResponse3(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
128050
129988
|
}
|
|
128051
129989
|
const snapshot = input.activityRecorder ? input.activityRecorder.snapshot() : { events: [], running: 0, total: 0 };
|
|
128052
|
-
return
|
|
129990
|
+
return jsonResponse3(snapshot);
|
|
128053
129991
|
}
|
|
128054
129992
|
if (pathname === "/mcp") {
|
|
128055
129993
|
return handleMcpToken(bearerToken(input.request), {
|
|
@@ -128060,7 +129998,7 @@ async function handleMcpRoute(input) {
|
|
|
128060
129998
|
if (pathname.startsWith(mcpPrefix)) {
|
|
128061
129999
|
const rawToken = decodeURIComponent(pathname.slice(mcpPrefix.length));
|
|
128062
130000
|
if (!rawToken || rawToken.includes("/")) {
|
|
128063
|
-
return
|
|
130001
|
+
return errorResponse3(404, "NOT_FOUND", "Not found");
|
|
128064
130002
|
}
|
|
128065
130003
|
return handleMcpToken(rawToken, { oauthChallenge: false });
|
|
128066
130004
|
}
|
|
@@ -128074,6 +130012,45 @@ var OrphanedEntryError = class extends Error {
|
|
|
128074
130012
|
this.name = "OrphanedEntryError";
|
|
128075
130013
|
}
|
|
128076
130014
|
};
|
|
130015
|
+
var DeletedScopeEntryError = class extends Error {
|
|
130016
|
+
constructor(path, deletedAt) {
|
|
130017
|
+
super(`Dropped local entry for a scope deleted at ${deletedAt}: ${path}`);
|
|
130018
|
+
this.name = "DeletedScopeEntryError";
|
|
130019
|
+
}
|
|
130020
|
+
};
|
|
130021
|
+
async function dropIfCoveredByDeletion(deps, entry, tombstone, deletedAt, uploaded) {
|
|
130022
|
+
const version4 = tombstoneVersion(tombstone);
|
|
130023
|
+
if (!isEntryCoveredByTombstone(entry, { version: version4 }))
|
|
130024
|
+
return;
|
|
130025
|
+
if (uploaded) {
|
|
130026
|
+
try {
|
|
130027
|
+
await deps.storageAdapter.delete(uploaded.url);
|
|
130028
|
+
} catch (err2) {
|
|
130029
|
+
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
130030
|
+
if (deps.pendingBlobDeletions) {
|
|
130031
|
+
await deps.pendingBlobDeletions.add([
|
|
130032
|
+
{ scope: entry.scope, version: String(entry.version) }
|
|
130033
|
+
]);
|
|
130034
|
+
}
|
|
130035
|
+
deps.logger.warn({
|
|
130036
|
+
scope: entry.scope,
|
|
130037
|
+
url: uploaded.url,
|
|
130038
|
+
error: message,
|
|
130039
|
+
queuedForCleanup: Boolean(deps.pendingBlobDeletions)
|
|
130040
|
+
}, "Could not delete the ciphertext uploaded for an entry the tombstone covers");
|
|
130041
|
+
}
|
|
130042
|
+
}
|
|
130043
|
+
await deps.storage.deleteVersion(entry.scope, entry.collectedAt);
|
|
130044
|
+
deps.logger.warn({
|
|
130045
|
+
path: entry.path,
|
|
130046
|
+
scope: entry.scope,
|
|
130047
|
+
deletedAt,
|
|
130048
|
+
tombstoneVersion: version4,
|
|
130049
|
+
entryVersion: entry.version,
|
|
130050
|
+
afterTombstoneVersion: entry.afterTombstoneVersion ?? null
|
|
130051
|
+
}, "Dropped unsynced local entry: the gateway reports its scope as deleted");
|
|
130052
|
+
throw new DeletedScopeEntryError(entry.path, deletedAt);
|
|
130053
|
+
}
|
|
128077
130054
|
function isMissingPayloadError(err2) {
|
|
128078
130055
|
return err2 instanceof Error && err2.code === "ENOENT";
|
|
128079
130056
|
}
|
|
@@ -128092,6 +130069,20 @@ async function uploadOne(deps, entry) {
|
|
|
128092
130069
|
}
|
|
128093
130070
|
throw err2;
|
|
128094
130071
|
}
|
|
130072
|
+
let registerVersion = BigInt(entry.version);
|
|
130073
|
+
if (!entry.dataPointId && deps.dataPointFeed) {
|
|
130074
|
+
const remote = await deps.dataPointFeed.getDataPoint({
|
|
130075
|
+
ownerAddress: serverOwner,
|
|
130076
|
+
scope: entry.scope
|
|
130077
|
+
});
|
|
130078
|
+
const deletedAt = deletionTimestamp(remote);
|
|
130079
|
+
if (remote && deletedAt !== null) {
|
|
130080
|
+
await dropIfCoveredByDeletion(deps, entry, remote, deletedAt);
|
|
130081
|
+
const afterTombstone = BigInt(remote.expectedVersion) + 1n;
|
|
130082
|
+
if (afterTombstone > registerVersion)
|
|
130083
|
+
registerVersion = afterTombstone;
|
|
130084
|
+
}
|
|
130085
|
+
}
|
|
128095
130086
|
const scopeKey = deriveScopeKey(masterKey, entry.scope);
|
|
128096
130087
|
const scopeKeyHex = uint8ToHex(scopeKey);
|
|
128097
130088
|
const plaintext = new TextEncoder().encode(JSON.stringify(envelope));
|
|
@@ -128102,7 +130093,7 @@ async function uploadOne(deps, entry) {
|
|
|
128102
130093
|
collectedAt: entry.collectedAt,
|
|
128103
130094
|
sizeBytes: encrypted.byteLength
|
|
128104
130095
|
})));
|
|
128105
|
-
const storageKey = `${entry.scope}/${
|
|
130096
|
+
const storageKey = `${entry.scope}/${registerVersion}`;
|
|
128106
130097
|
let url2 = await storageAdapter.upload(storageKey, encrypted);
|
|
128107
130098
|
let dataPointId;
|
|
128108
130099
|
if (entry.dataPointId) {
|
|
@@ -128152,11 +130143,23 @@ async function uploadOne(deps, entry) {
|
|
|
128152
130143
|
return id2;
|
|
128153
130144
|
};
|
|
128154
130145
|
try {
|
|
128155
|
-
dataPointId = await registerAt(
|
|
130146
|
+
dataPointId = await registerAt(registerVersion);
|
|
130147
|
+
if (registerVersion !== BigInt(entry.version)) {
|
|
130148
|
+
await storage.updateEntryVersion(entry.path, Number(registerVersion));
|
|
130149
|
+
}
|
|
128156
130150
|
} catch (err2) {
|
|
128157
130151
|
if (!isStaleVersionConflict(err2))
|
|
128158
130152
|
throw err2;
|
|
128159
|
-
const record2 = await
|
|
130153
|
+
const record2 = deps.dataPointFeed ? await deps.dataPointFeed.getDataPoint({
|
|
130154
|
+
ownerAddress: serverOwner,
|
|
130155
|
+
scope: entry.scope
|
|
130156
|
+
}) : await gateway.getDataPoint(computeDataPointId(serverOwner, entry.scope));
|
|
130157
|
+
const conflictDeletedAt = record2 ? deletionTimestamp(record2) : null;
|
|
130158
|
+
if (record2 && conflictDeletedAt !== null) {
|
|
130159
|
+
await dropIfCoveredByDeletion(deps, entry, record2, conflictDeletedAt, {
|
|
130160
|
+
url: url2
|
|
130161
|
+
});
|
|
130162
|
+
}
|
|
128160
130163
|
if (record2 && record2.dataHash.toLowerCase() === dataHash.toLowerCase()) {
|
|
128161
130164
|
dataPointId = record2.id;
|
|
128162
130165
|
const adoptedVersion = Number(record2.expectedVersion);
|
|
@@ -128182,6 +130185,7 @@ async function uploadOne(deps, entry) {
|
|
|
128182
130185
|
}
|
|
128183
130186
|
}
|
|
128184
130187
|
await storage.updateDataPointId(entry.path, dataPointId);
|
|
130188
|
+
deps.scopeDeletions?.markLive(entry.scope);
|
|
128185
130189
|
}
|
|
128186
130190
|
logger.info({
|
|
128187
130191
|
path: entry.path,
|
|
@@ -128201,7 +130205,7 @@ async function uploadAll(deps, options) {
|
|
|
128201
130205
|
const result = await uploadOne(deps, entry);
|
|
128202
130206
|
results.push(result);
|
|
128203
130207
|
} catch (err2) {
|
|
128204
|
-
if (err2 instanceof OrphanedEntryError) {
|
|
130208
|
+
if (err2 instanceof OrphanedEntryError || err2 instanceof DeletedScopeEntryError) {
|
|
128205
130209
|
continue;
|
|
128206
130210
|
}
|
|
128207
130211
|
const error51 = err2;
|
|
@@ -128230,6 +130234,101 @@ function parseGatewayNextVersion(message) {
|
|
|
128230
130234
|
return null;
|
|
128231
130235
|
}
|
|
128232
130236
|
|
|
130237
|
+
// ../core/dist/sync/data-point-feed.js
|
|
130238
|
+
function createGatewayDataPointFeed(options) {
|
|
130239
|
+
const base = options.gatewayUrl.replace(/\/+$/, "");
|
|
130240
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
130241
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
130242
|
+
return {
|
|
130243
|
+
async listDataPointsByOwner(owner, cursor, listOptions) {
|
|
130244
|
+
const params = new URLSearchParams({ user: owner });
|
|
130245
|
+
if (cursor !== null)
|
|
130246
|
+
params.set("cursor", cursor);
|
|
130247
|
+
if (listOptions?.since)
|
|
130248
|
+
params.set("since", listOptions.since);
|
|
130249
|
+
if (listOptions?.limit !== void 0) {
|
|
130250
|
+
params.set("limit", String(listOptions.limit));
|
|
130251
|
+
}
|
|
130252
|
+
if (listOptions?.includeDeleted)
|
|
130253
|
+
params.set("includeDeleted", "true");
|
|
130254
|
+
const res = await fetchImpl(`${base}/v1/data?${params.toString()}`);
|
|
130255
|
+
if (!res.ok) {
|
|
130256
|
+
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
130257
|
+
}
|
|
130258
|
+
const envelope = await res.json();
|
|
130259
|
+
const nextCursor = envelope.pagination?.hasMore === false ? null : envelope.pagination?.nextCursor ?? null;
|
|
130260
|
+
const rows = envelope.data?.dataPoints ?? [];
|
|
130261
|
+
return {
|
|
130262
|
+
dataPoints: rows.map((row) => normalizeRecord(row)),
|
|
130263
|
+
cursor: nextCursor
|
|
130264
|
+
};
|
|
130265
|
+
},
|
|
130266
|
+
async getDataPoint(input) {
|
|
130267
|
+
const dataPointId = computeDataPointId(input.ownerAddress, input.scope);
|
|
130268
|
+
const res = await fetchImpl(`${base}/v1/data/${dataPointId}?includeDeleted=true`);
|
|
130269
|
+
if (res.status === 404)
|
|
130270
|
+
return null;
|
|
130271
|
+
if (res.status === 410) {
|
|
130272
|
+
const body2 = await res.json().catch(() => null);
|
|
130273
|
+
const echoed = unwrap(body2);
|
|
130274
|
+
const deletedAt = stringField(echoed, "deletedAt") ?? now().toISOString();
|
|
130275
|
+
return {
|
|
130276
|
+
id: dataPointId,
|
|
130277
|
+
ownerAddress: input.ownerAddress,
|
|
130278
|
+
scope: input.scope,
|
|
130279
|
+
dataHash: stringField(echoed, "dataHash") ?? TOMBSTONE_DATA_HASH,
|
|
130280
|
+
metadataHash: stringField(echoed, "metadataHash") ?? TOMBSTONE_METADATA_HASH,
|
|
130281
|
+
expectedVersion: stringField(echoed, "expectedVersion") ?? "0",
|
|
130282
|
+
addedAt: stringField(echoed, "addedAt") ?? deletedAt,
|
|
130283
|
+
deletedAt
|
|
130284
|
+
};
|
|
130285
|
+
}
|
|
130286
|
+
if (!res.ok) {
|
|
130287
|
+
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
130288
|
+
}
|
|
130289
|
+
const body = await res.json();
|
|
130290
|
+
return normalizeRecord(unwrap(body));
|
|
130291
|
+
}
|
|
130292
|
+
};
|
|
130293
|
+
}
|
|
130294
|
+
function unwrap(body) {
|
|
130295
|
+
if (typeof body !== "object" || body === null)
|
|
130296
|
+
return null;
|
|
130297
|
+
const record2 = body;
|
|
130298
|
+
if (typeof record2.data === "object" && record2.data !== null) {
|
|
130299
|
+
return record2.data;
|
|
130300
|
+
}
|
|
130301
|
+
return record2;
|
|
130302
|
+
}
|
|
130303
|
+
function stringField(record2, key) {
|
|
130304
|
+
const value = record2?.[key];
|
|
130305
|
+
return typeof value === "string" ? value : void 0;
|
|
130306
|
+
}
|
|
130307
|
+
function normalizeRecord(row) {
|
|
130308
|
+
const record2 = row ?? {};
|
|
130309
|
+
const deletedAt = record2.deletedAt;
|
|
130310
|
+
return {
|
|
130311
|
+
...record2,
|
|
130312
|
+
deletedAt: typeof deletedAt === "string" ? deletedAt : null
|
|
130313
|
+
};
|
|
130314
|
+
}
|
|
130315
|
+
function feedFromGatewayClient(gateway) {
|
|
130316
|
+
return {
|
|
130317
|
+
async listDataPointsByOwner(owner, cursor, listOptions) {
|
|
130318
|
+
const { includeDeleted: _includeDeleted, ...sdkOptions } = listOptions ?? {};
|
|
130319
|
+
const result = Object.keys(sdkOptions).length > 0 ? await gateway.listDataPointsByOwner(owner, cursor, sdkOptions) : await gateway.listDataPointsByOwner(owner, cursor);
|
|
130320
|
+
return {
|
|
130321
|
+
dataPoints: result.dataPoints.map((row) => normalizeRecord(row)),
|
|
130322
|
+
cursor: result.cursor
|
|
130323
|
+
};
|
|
130324
|
+
},
|
|
130325
|
+
async getDataPoint(input) {
|
|
130326
|
+
const row = await gateway.getDataPoint(computeDataPointId(input.ownerAddress, input.scope));
|
|
130327
|
+
return row === null ? null : normalizeRecord(row);
|
|
130328
|
+
}
|
|
130329
|
+
};
|
|
130330
|
+
}
|
|
130331
|
+
|
|
128233
130332
|
// ../core/dist/sync/issues.js
|
|
128234
130333
|
var DETERMINISTIC_STAGES = /* @__PURE__ */ new Set([
|
|
128235
130334
|
"openpgp_parse",
|
|
@@ -128546,6 +130645,24 @@ async function downloadOne(deps, record2) {
|
|
|
128546
130645
|
}
|
|
128547
130646
|
diagnostics?.onIndexEnd(record2.id, envelope.scope);
|
|
128548
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
|
+
}
|
|
128549
130666
|
return {
|
|
128550
130667
|
dataPointId: record2.id,
|
|
128551
130668
|
scope: envelope.scope,
|
|
@@ -128567,10 +130684,43 @@ async function downloadAll(deps, options = {}) {
|
|
|
128567
130684
|
if (options.fullReconcile || repairSummary.missingEnvelopeEntries > 0) {
|
|
128568
130685
|
options.retryMemory?.onListingReset();
|
|
128569
130686
|
}
|
|
128570
|
-
const
|
|
130687
|
+
const feed = deps.dataPointFeed ?? feedFromGatewayClient(gateway);
|
|
130688
|
+
const { dataPoints, cursor: nextCursor } = await feed.listDataPointsByOwner(serverOwner, lastCursor, { includeDeleted: true });
|
|
130689
|
+
if (deps.scopeDeletions) {
|
|
130690
|
+
for (const dataPoint of dataPoints) {
|
|
130691
|
+
const deletedAt = deletionTimestamp(dataPoint);
|
|
130692
|
+
if (deletedAt !== null) {
|
|
130693
|
+
deps.scopeDeletions.markDeleted(dataPoint.scope, {
|
|
130694
|
+
deletedAt,
|
|
130695
|
+
version: tombstoneVersion(dataPoint)
|
|
130696
|
+
});
|
|
130697
|
+
} else {
|
|
130698
|
+
deps.scopeDeletions.markLive(dataPoint.scope);
|
|
130699
|
+
}
|
|
130700
|
+
}
|
|
130701
|
+
if (nextCursor === null) {
|
|
130702
|
+
deps.scopeDeletions.noteFeedSynced(void 0, {
|
|
130703
|
+
full: lastCursor === null
|
|
130704
|
+
});
|
|
130705
|
+
}
|
|
130706
|
+
}
|
|
128571
130707
|
const results = [];
|
|
128572
130708
|
let failed = false;
|
|
128573
130709
|
for (const dataPoint of dataPoints) {
|
|
130710
|
+
const deletedAt = deletionTimestamp(dataPoint);
|
|
130711
|
+
if (deletedAt !== null) {
|
|
130712
|
+
try {
|
|
130713
|
+
await reconcileDeletedDataPoint(deps, dataPoint, deletedAt);
|
|
130714
|
+
} catch (err2) {
|
|
130715
|
+
logger.error({
|
|
130716
|
+
dataPointId: dataPoint.id,
|
|
130717
|
+
scope: dataPoint.scope,
|
|
130718
|
+
error: err2.message
|
|
130719
|
+
}, "Failed to reconcile deleted data point locally");
|
|
130720
|
+
failed = true;
|
|
130721
|
+
}
|
|
130722
|
+
continue;
|
|
130723
|
+
}
|
|
128574
130724
|
const retryKey = downloadRetryKey(dataPoint);
|
|
128575
130725
|
const decision = options.retryMemory?.decide(retryKey) ?? "attempt";
|
|
128576
130726
|
if (decision === "give-up") {
|
|
@@ -128626,6 +130776,49 @@ async function downloadAll(deps, options = {}) {
|
|
|
128626
130776
|
}
|
|
128627
130777
|
return results;
|
|
128628
130778
|
}
|
|
130779
|
+
async function reconcileDeletedDataPoint(deps, record2, deletedAt) {
|
|
130780
|
+
const tombstone = { version: tombstoneVersion(record2) };
|
|
130781
|
+
const tombstoned = tombstone.version === null ? null : BigInt(tombstone.version);
|
|
130782
|
+
const orphanKeys = [];
|
|
130783
|
+
const { storage, logger } = deps;
|
|
130784
|
+
const PAGE_SIZE = 500;
|
|
130785
|
+
const stale = [];
|
|
130786
|
+
let kept = 0;
|
|
130787
|
+
for (let offset = 0; ; offset += PAGE_SIZE) {
|
|
130788
|
+
const entries = storage.listVersions(record2.scope, {
|
|
130789
|
+
limit: PAGE_SIZE,
|
|
130790
|
+
offset
|
|
130791
|
+
});
|
|
130792
|
+
for (const entry of entries) {
|
|
130793
|
+
if (isEntryCoveredByTombstone(entry, tombstone)) {
|
|
130794
|
+
stale.push({ scope: entry.scope, collectedAt: entry.collectedAt });
|
|
130795
|
+
if (entry.dataPointId === null && (tombstoned === null || BigInt(entry.version) > tombstoned)) {
|
|
130796
|
+
orphanKeys.push({
|
|
130797
|
+
scope: entry.scope,
|
|
130798
|
+
version: String(entry.version)
|
|
130799
|
+
});
|
|
130800
|
+
}
|
|
130801
|
+
} else {
|
|
130802
|
+
kept += 1;
|
|
130803
|
+
}
|
|
130804
|
+
}
|
|
130805
|
+
if (entries.length < PAGE_SIZE)
|
|
130806
|
+
break;
|
|
130807
|
+
}
|
|
130808
|
+
let removed = 0;
|
|
130809
|
+
for (const version4 of stale) {
|
|
130810
|
+
if (await storage.deleteVersion(version4.scope, version4.collectedAt)) {
|
|
130811
|
+
removed += 1;
|
|
130812
|
+
}
|
|
130813
|
+
}
|
|
130814
|
+
if (orphanKeys.length > 0 && deps.pendingBlobDeletions) {
|
|
130815
|
+
await deps.pendingBlobDeletions.add(orphanKeys);
|
|
130816
|
+
}
|
|
130817
|
+
if (removed > 0 || kept > 0) {
|
|
130818
|
+
logger.info({ dataPointId: record2.id, scope: record2.scope, deletedAt, removed, kept }, "Reconciled gateway deletion against local index");
|
|
130819
|
+
}
|
|
130820
|
+
return { scope: record2.scope, deletedAt, removed, kept };
|
|
130821
|
+
}
|
|
128629
130822
|
async function repairLocalMissingBlockSidecars(deps) {
|
|
128630
130823
|
const { storage, logger, diagnostics } = deps;
|
|
128631
130824
|
if (!storage.writeBlockManifest || !storage.hasScopeBlocks) {
|
|
@@ -128784,28 +130977,6 @@ async function repairMissingBlockSidecars(storage, logger, ctx, entry, diagnosti
|
|
|
128784
130977
|
}
|
|
128785
130978
|
}
|
|
128786
130979
|
|
|
128787
|
-
// ../core/dist/sync/workers/delete.js
|
|
128788
|
-
async function deleteScopeRemote(deps, scope) {
|
|
128789
|
-
const { storage, logger } = deps;
|
|
128790
|
-
let syncedVersions = 0;
|
|
128791
|
-
const PAGE_SIZE = 1e3;
|
|
128792
|
-
for (let offset = 0; ; offset += PAGE_SIZE) {
|
|
128793
|
-
const entries = storage.listVersions(scope, { limit: PAGE_SIZE, offset });
|
|
128794
|
-
syncedVersions += entries.filter((e10) => e10.dataPointId !== null).length;
|
|
128795
|
-
if (entries.length < PAGE_SIZE)
|
|
128796
|
-
break;
|
|
128797
|
-
}
|
|
128798
|
-
if (syncedVersions > 0) {
|
|
128799
|
-
logger.warn({ scope, syncedVersions }, "Remote scope deletion is not supported on the DPv2 gateway (no de-registration endpoint); local data was removed but the remote data point(s) and ciphertext blob(s) remain");
|
|
128800
|
-
}
|
|
128801
|
-
return {
|
|
128802
|
-
scope,
|
|
128803
|
-
filesDeregistered: 0,
|
|
128804
|
-
blobsDeleted: 0,
|
|
128805
|
-
errors: []
|
|
128806
|
-
};
|
|
128807
|
-
}
|
|
128808
|
-
|
|
128809
130980
|
// ../core/dist/sync/engine/sync-manager.js
|
|
128810
130981
|
var MAX_ERRORS = 10;
|
|
128811
130982
|
function createSyncManager(uploadDeps, downloadDeps, options) {
|
|
@@ -128823,12 +130994,28 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
|
|
|
128823
130994
|
let rerunRequested = false;
|
|
128824
130995
|
let needsFullReconcile = true;
|
|
128825
130996
|
const downloadRetryMemory = createDownloadRetryMemory();
|
|
130997
|
+
const dataPointFeed = downloadDeps.dataPointFeed ?? uploadDeps.dataPointFeed;
|
|
130998
|
+
const scopeDeletions = uploadDeps.scopeDeletions ?? downloadDeps.scopeDeletions;
|
|
130999
|
+
const workerUploadDeps = {
|
|
131000
|
+
...uploadDeps,
|
|
131001
|
+
pendingBlobDeletions: uploadDeps.pendingBlobDeletions ?? options?.pendingBlobDeletions
|
|
131002
|
+
};
|
|
131003
|
+
const workerDownloadDeps = {
|
|
131004
|
+
...downloadDeps,
|
|
131005
|
+
pendingBlobDeletions: downloadDeps.pendingBlobDeletions ?? options?.pendingBlobDeletions
|
|
131006
|
+
};
|
|
131007
|
+
let mutationQueue = Promise.resolve();
|
|
131008
|
+
function exclusive(operation) {
|
|
131009
|
+
const run = mutationQueue.then(operation, operation);
|
|
131010
|
+
mutationQueue = run.catch(() => void 0);
|
|
131011
|
+
return run;
|
|
131012
|
+
}
|
|
128826
131013
|
async function runCycle() {
|
|
128827
131014
|
if (cycleInFlight) {
|
|
128828
131015
|
rerunRequested = true;
|
|
128829
131016
|
return cycleInFlight;
|
|
128830
131017
|
}
|
|
128831
|
-
cycleInFlight = (async () => {
|
|
131018
|
+
cycleInFlight = exclusive(async () => {
|
|
128832
131019
|
do {
|
|
128833
131020
|
rerunRequested = false;
|
|
128834
131021
|
const canRun = await (options?.canSync?.() ?? { ok: true });
|
|
@@ -128839,7 +131026,19 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
|
|
|
128839
131026
|
}
|
|
128840
131027
|
blocked = null;
|
|
128841
131028
|
try {
|
|
128842
|
-
|
|
131029
|
+
await retryPendingBlobDeletions({
|
|
131030
|
+
deleteData: options?.deleteData,
|
|
131031
|
+
pendingBlobDeletions: options?.pendingBlobDeletions,
|
|
131032
|
+
dataPointFeed,
|
|
131033
|
+
serverOwner: uploadDeps.serverOwner,
|
|
131034
|
+
storage: uploadDeps.storage,
|
|
131035
|
+
logger: uploadDeps.logger
|
|
131036
|
+
});
|
|
131037
|
+
} catch (err2) {
|
|
131038
|
+
uploadDeps.logger.warn({ error: err2.message }, "Pending blob deletion retry failed");
|
|
131039
|
+
}
|
|
131040
|
+
try {
|
|
131041
|
+
const uploadResults = await uploadAll(workerUploadDeps, {
|
|
128843
131042
|
batchSize: uploadBatchSize,
|
|
128844
131043
|
onError(entry, error51) {
|
|
128845
131044
|
pushError({
|
|
@@ -128863,7 +131062,7 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
|
|
|
128863
131062
|
}
|
|
128864
131063
|
try {
|
|
128865
131064
|
const fullReconcile = needsFullReconcile;
|
|
128866
|
-
const downloadResults = await downloadAll(
|
|
131065
|
+
const downloadResults = await downloadAll(workerDownloadDeps, {
|
|
128867
131066
|
fullReconcile,
|
|
128868
131067
|
retryMemory: downloadRetryMemory
|
|
128869
131068
|
});
|
|
@@ -128885,7 +131084,7 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
|
|
|
128885
131084
|
}
|
|
128886
131085
|
lastSync = (/* @__PURE__ */ new Date()).toISOString();
|
|
128887
131086
|
} while (rerunRequested && isRunning);
|
|
128888
|
-
})
|
|
131087
|
+
});
|
|
128889
131088
|
try {
|
|
128890
131089
|
await cycleInFlight;
|
|
128891
131090
|
} finally {
|
|
@@ -128974,13 +131173,291 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
|
|
|
128974
131173
|
uploadDeps.logger.debug("New data notification received");
|
|
128975
131174
|
scheduleNotifiedCycle();
|
|
128976
131175
|
},
|
|
128977
|
-
|
|
128978
|
-
|
|
131176
|
+
deleteScope(scope) {
|
|
131177
|
+
return exclusive(() => deleteScope({
|
|
131178
|
+
storage: uploadDeps.storage,
|
|
131179
|
+
serverOwner: uploadDeps.serverOwner,
|
|
131180
|
+
deleteData: options?.deleteData,
|
|
131181
|
+
pendingBlobDeletions: options?.pendingBlobDeletions,
|
|
131182
|
+
scopeDeletions,
|
|
131183
|
+
dataPointFeed,
|
|
131184
|
+
logger: uploadDeps.logger
|
|
131185
|
+
}, scope));
|
|
128979
131186
|
}
|
|
128980
131187
|
};
|
|
128981
131188
|
return manager;
|
|
128982
131189
|
}
|
|
128983
131190
|
|
|
131191
|
+
// ../core/dist/sync/delete-data-port.js
|
|
131192
|
+
function createGatewayDeleteDataPort(options) {
|
|
131193
|
+
const gatewayBase = options.gatewayUrl.replace(/\/+$/, "");
|
|
131194
|
+
const storageBase = options.storage.endpoint.replace(/\/+$/, "");
|
|
131195
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
131196
|
+
const owner = options.serverOwner.toLowerCase();
|
|
131197
|
+
async function sendTombstone(scope, dataPointId, version4) {
|
|
131198
|
+
const signature = await options.signer.signAddData({
|
|
131199
|
+
ownerAddress: options.serverOwner,
|
|
131200
|
+
scope,
|
|
131201
|
+
dataHash: TOMBSTONE_DATA_HASH,
|
|
131202
|
+
metadataHash: TOMBSTONE_METADATA_HASH,
|
|
131203
|
+
expectedVersion: version4
|
|
131204
|
+
});
|
|
131205
|
+
return fetchImpl(`${gatewayBase}/v1/data/${dataPointId}`, {
|
|
131206
|
+
method: "DELETE",
|
|
131207
|
+
headers: {
|
|
131208
|
+
"Content-Type": "application/json",
|
|
131209
|
+
Authorization: `Web3Signed ${signature}`
|
|
131210
|
+
},
|
|
131211
|
+
body: JSON.stringify({
|
|
131212
|
+
ownerAddress: options.serverOwner,
|
|
131213
|
+
scope,
|
|
131214
|
+
expectedVersion: String(version4),
|
|
131215
|
+
signature
|
|
131216
|
+
})
|
|
131217
|
+
});
|
|
131218
|
+
}
|
|
131219
|
+
return {
|
|
131220
|
+
async tombstone(scope) {
|
|
131221
|
+
const dataPointId = computeDataPointId(options.serverOwner, scope);
|
|
131222
|
+
const current = await options.dataPointFeed.getDataPoint({
|
|
131223
|
+
ownerAddress: options.serverOwner,
|
|
131224
|
+
scope
|
|
131225
|
+
});
|
|
131226
|
+
if (current === null) {
|
|
131227
|
+
return { status: "not-registered", dataPointId };
|
|
131228
|
+
}
|
|
131229
|
+
if (current.deletedAt !== null) {
|
|
131230
|
+
return {
|
|
131231
|
+
status: "already-deleted",
|
|
131232
|
+
dataPointId,
|
|
131233
|
+
version: current.expectedVersion,
|
|
131234
|
+
deletedAt: current.deletedAt
|
|
131235
|
+
};
|
|
131236
|
+
}
|
|
131237
|
+
let version4 = BigInt(current.expectedVersion) + 1n;
|
|
131238
|
+
let res = await sendTombstone(scope, dataPointId, version4);
|
|
131239
|
+
if (res.status === 409) {
|
|
131240
|
+
const body2 = await res.json().catch(() => null);
|
|
131241
|
+
const conflict = unwrap2(body2);
|
|
131242
|
+
const nextExplicit = integerField(conflict, "nextExpectedVersion") ?? integerField(body2, "nextExpectedVersion");
|
|
131243
|
+
const currentExpected = integerField(conflict, "currentExpectedVersion") ?? integerField(body2, "currentExpectedVersion");
|
|
131244
|
+
const legacyNext = parseGatewayNextVersion(detailFromBody(body2, res.statusText));
|
|
131245
|
+
const next = nextExplicit !== null ? nextExplicit : currentExpected !== null ? currentExpected + 1n : legacyNext !== null ? BigInt(legacyNext) : null;
|
|
131246
|
+
if (next === null) {
|
|
131247
|
+
throw new Error(`Gateway error: 409 ${detailFromBody(body2, res.statusText)}`);
|
|
131248
|
+
}
|
|
131249
|
+
version4 = next;
|
|
131250
|
+
res = await sendTombstone(scope, dataPointId, version4);
|
|
131251
|
+
}
|
|
131252
|
+
if (res.status === 404) {
|
|
131253
|
+
return { status: "not-registered", dataPointId };
|
|
131254
|
+
}
|
|
131255
|
+
if (res.status === 410) {
|
|
131256
|
+
const body2 = await res.json().catch(() => null);
|
|
131257
|
+
const echoed = unwrap2(body2);
|
|
131258
|
+
let winning = normalizeVersionString(stringField2(echoed, "expectedVersion"));
|
|
131259
|
+
let deletedAt = stringField2(echoed, "deletedAt");
|
|
131260
|
+
if (winning === null) {
|
|
131261
|
+
const reread = await options.dataPointFeed.getDataPoint({ ownerAddress: options.serverOwner, scope }).catch(() => null);
|
|
131262
|
+
if (reread && reread.deletedAt !== null) {
|
|
131263
|
+
winning = normalizeVersionString(reread.expectedVersion);
|
|
131264
|
+
deletedAt = deletedAt ?? reread.deletedAt;
|
|
131265
|
+
}
|
|
131266
|
+
}
|
|
131267
|
+
return {
|
|
131268
|
+
status: "already-deleted",
|
|
131269
|
+
dataPointId,
|
|
131270
|
+
version: winning,
|
|
131271
|
+
deletedAt
|
|
131272
|
+
};
|
|
131273
|
+
}
|
|
131274
|
+
if (!res.ok) {
|
|
131275
|
+
throw new Error(`Gateway error: ${res.status} ${await errorDetail(res)}`);
|
|
131276
|
+
}
|
|
131277
|
+
const body = await res.json().catch(() => null);
|
|
131278
|
+
const row = unwrap2(body);
|
|
131279
|
+
return {
|
|
131280
|
+
status: "tombstoned",
|
|
131281
|
+
dataPointId: stringField2(row, "dataPointId") ?? dataPointId,
|
|
131282
|
+
version: stringField2(row, "expectedVersion") ?? String(version4),
|
|
131283
|
+
deletedAt: stringField2(row, "deletedAt")
|
|
131284
|
+
};
|
|
131285
|
+
},
|
|
131286
|
+
async deleteBlobVersions(scope, versions) {
|
|
131287
|
+
const outcome = {
|
|
131288
|
+
deleted: [],
|
|
131289
|
+
missing: [],
|
|
131290
|
+
failed: []
|
|
131291
|
+
};
|
|
131292
|
+
for (const version4 of versions) {
|
|
131293
|
+
const path = `/v1/chains/${options.storage.chainId}/blobs/${owner}/${encodeURIComponent(scope)}/${encodeURIComponent(version4)}`;
|
|
131294
|
+
try {
|
|
131295
|
+
const authorization = await buildWeb3SignedHeader({
|
|
131296
|
+
signMessage: (message) => options.storage.signMessage(message),
|
|
131297
|
+
aud: storageBase,
|
|
131298
|
+
method: "DELETE",
|
|
131299
|
+
uri: path
|
|
131300
|
+
});
|
|
131301
|
+
const res = await fetchImpl(`${storageBase}${path}`, {
|
|
131302
|
+
method: "DELETE",
|
|
131303
|
+
headers: { authorization }
|
|
131304
|
+
});
|
|
131305
|
+
if (res.status === 404) {
|
|
131306
|
+
outcome.missing.push(version4);
|
|
131307
|
+
} else if (res.ok) {
|
|
131308
|
+
outcome.deleted.push(version4);
|
|
131309
|
+
} else {
|
|
131310
|
+
outcome.failed.push({
|
|
131311
|
+
version: version4,
|
|
131312
|
+
error: `vana-storage delete failed: ${res.status} ${res.statusText}`
|
|
131313
|
+
});
|
|
131314
|
+
}
|
|
131315
|
+
} catch (err2) {
|
|
131316
|
+
outcome.failed.push({
|
|
131317
|
+
version: version4,
|
|
131318
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
131319
|
+
});
|
|
131320
|
+
}
|
|
131321
|
+
}
|
|
131322
|
+
return outcome;
|
|
131323
|
+
}
|
|
131324
|
+
};
|
|
131325
|
+
}
|
|
131326
|
+
async function errorDetail(res) {
|
|
131327
|
+
const body = await res.json().catch(() => null);
|
|
131328
|
+
return detailFromBody(body, res.statusText);
|
|
131329
|
+
}
|
|
131330
|
+
function detailFromBody(body, fallback) {
|
|
131331
|
+
if (typeof body === "object" && body !== null) {
|
|
131332
|
+
const record2 = body;
|
|
131333
|
+
if (typeof record2.error === "string")
|
|
131334
|
+
return record2.error;
|
|
131335
|
+
if (typeof record2.message === "string")
|
|
131336
|
+
return record2.message;
|
|
131337
|
+
if (typeof record2.error === "object" && record2.error !== null) {
|
|
131338
|
+
const nested = record2.error;
|
|
131339
|
+
if (typeof nested.message === "string")
|
|
131340
|
+
return nested.message;
|
|
131341
|
+
}
|
|
131342
|
+
}
|
|
131343
|
+
return fallback;
|
|
131344
|
+
}
|
|
131345
|
+
function normalizeVersionString(value) {
|
|
131346
|
+
if (value === null || !/^\d+$/.test(value))
|
|
131347
|
+
return null;
|
|
131348
|
+
const parsed = BigInt(value);
|
|
131349
|
+
return parsed > 0n ? parsed.toString() : null;
|
|
131350
|
+
}
|
|
131351
|
+
function integerField(record2, key) {
|
|
131352
|
+
if (typeof record2 !== "object" || record2 === null)
|
|
131353
|
+
return null;
|
|
131354
|
+
const value = record2[key];
|
|
131355
|
+
if (typeof value === "number" && Number.isSafeInteger(value)) {
|
|
131356
|
+
return BigInt(value);
|
|
131357
|
+
}
|
|
131358
|
+
if (typeof value === "string" && /^\d+$/.test(value))
|
|
131359
|
+
return BigInt(value);
|
|
131360
|
+
return null;
|
|
131361
|
+
}
|
|
131362
|
+
function unwrap2(body) {
|
|
131363
|
+
if (typeof body !== "object" || body === null)
|
|
131364
|
+
return null;
|
|
131365
|
+
const record2 = body;
|
|
131366
|
+
if (typeof record2.data === "object" && record2.data !== null) {
|
|
131367
|
+
return record2.data;
|
|
131368
|
+
}
|
|
131369
|
+
return record2;
|
|
131370
|
+
}
|
|
131371
|
+
function stringField2(record2, key) {
|
|
131372
|
+
const value = record2?.[key];
|
|
131373
|
+
return typeof value === "string" ? value : null;
|
|
131374
|
+
}
|
|
131375
|
+
|
|
131376
|
+
// ../core/dist/sync/pending-blob-deletions.js
|
|
131377
|
+
function markerId(key) {
|
|
131378
|
+
const range = key.range ? `${key.range.from}-${key.range.to}` : "";
|
|
131379
|
+
return `${key.scope}\0${key.version ?? ""}\0${range}`;
|
|
131380
|
+
}
|
|
131381
|
+
function normalizeRange(value) {
|
|
131382
|
+
if (typeof value !== "object" || value === null)
|
|
131383
|
+
return void 0;
|
|
131384
|
+
const { from, to: to3 } = value;
|
|
131385
|
+
if (typeof from !== "string" || typeof to3 !== "string" || !/^\d+$/.test(from) || !/^\d+$/.test(to3) || BigInt(from) > BigInt(to3)) {
|
|
131386
|
+
return void 0;
|
|
131387
|
+
}
|
|
131388
|
+
return { from, to: to3 };
|
|
131389
|
+
}
|
|
131390
|
+
function normalizePendingBlobDeletions(stored) {
|
|
131391
|
+
if (!Array.isArray(stored))
|
|
131392
|
+
return [];
|
|
131393
|
+
const keys = [];
|
|
131394
|
+
for (const item of stored) {
|
|
131395
|
+
if (typeof item === "string") {
|
|
131396
|
+
keys.push({ scope: item, version: null });
|
|
131397
|
+
} else if (typeof item === "object" && item !== null && typeof item.scope === "string") {
|
|
131398
|
+
const version4 = item.version;
|
|
131399
|
+
const range = typeof version4 === "string" ? void 0 : normalizeRange(item.range);
|
|
131400
|
+
keys.push({
|
|
131401
|
+
scope: item.scope,
|
|
131402
|
+
version: typeof version4 === "string" ? version4 : null,
|
|
131403
|
+
...range ? { range } : {}
|
|
131404
|
+
});
|
|
131405
|
+
}
|
|
131406
|
+
}
|
|
131407
|
+
return keys;
|
|
131408
|
+
}
|
|
131409
|
+
function createPendingBlobDeletionStore(kv) {
|
|
131410
|
+
let queue = Promise.resolve();
|
|
131411
|
+
function serialized(operation) {
|
|
131412
|
+
const run = queue.then(operation, operation);
|
|
131413
|
+
queue = run.catch(() => void 0);
|
|
131414
|
+
return run;
|
|
131415
|
+
}
|
|
131416
|
+
async function current() {
|
|
131417
|
+
return normalizePendingBlobDeletions(await kv.read());
|
|
131418
|
+
}
|
|
131419
|
+
return {
|
|
131420
|
+
list() {
|
|
131421
|
+
return serialized(current);
|
|
131422
|
+
},
|
|
131423
|
+
add(keys) {
|
|
131424
|
+
return serialized(async () => {
|
|
131425
|
+
if (keys.length === 0)
|
|
131426
|
+
return;
|
|
131427
|
+
const existing = await current();
|
|
131428
|
+
const known = new Set(existing.map(markerId));
|
|
131429
|
+
const next = [...existing];
|
|
131430
|
+
for (const key of keys) {
|
|
131431
|
+
const id2 = markerId(key);
|
|
131432
|
+
if (known.has(id2))
|
|
131433
|
+
continue;
|
|
131434
|
+
known.add(id2);
|
|
131435
|
+
next.push({
|
|
131436
|
+
scope: key.scope,
|
|
131437
|
+
version: key.version,
|
|
131438
|
+
...key.range ? { range: { ...key.range } } : {}
|
|
131439
|
+
});
|
|
131440
|
+
}
|
|
131441
|
+
if (next.length === existing.length)
|
|
131442
|
+
return;
|
|
131443
|
+
await kv.write(next);
|
|
131444
|
+
});
|
|
131445
|
+
},
|
|
131446
|
+
remove(keys) {
|
|
131447
|
+
return serialized(async () => {
|
|
131448
|
+
if (keys.length === 0)
|
|
131449
|
+
return;
|
|
131450
|
+
const existing = await current();
|
|
131451
|
+
const gone = new Set(keys.map(markerId));
|
|
131452
|
+
const next = existing.filter((key) => !gone.has(markerId(key)));
|
|
131453
|
+
if (next.length === existing.length)
|
|
131454
|
+
return;
|
|
131455
|
+
await kv.write(next);
|
|
131456
|
+
});
|
|
131457
|
+
}
|
|
131458
|
+
};
|
|
131459
|
+
}
|
|
131460
|
+
|
|
128984
131461
|
// ../core/dist/storage/adapters/sdk.js
|
|
128985
131462
|
function createSdkStorageAdapter(providerOrFactory, options) {
|
|
128986
131463
|
let cachedProvider;
|
|
@@ -129041,8 +131518,11 @@ function copyBytes(data) {
|
|
|
129041
131518
|
|
|
129042
131519
|
// ../core/dist/storage/adapters/vana.js
|
|
129043
131520
|
var DEFAULT_VANA_STORAGE_ENDPOINT = "https://storage.vana.org";
|
|
131521
|
+
function resolveVanaStorageEndpoint(config2) {
|
|
131522
|
+
return (config2.storage.config.vana?.apiUrl ?? DEFAULT_VANA_STORAGE_ENDPOINT).replace(/\/+$/, "");
|
|
131523
|
+
}
|
|
129044
131524
|
function createVanaSyncStorageAdapter(params) {
|
|
129045
|
-
const endpoint = (params.config
|
|
131525
|
+
const endpoint = resolveVanaStorageEndpoint(params.config);
|
|
129046
131526
|
const owner = params.serverOwner.toLowerCase();
|
|
129047
131527
|
const chainId = params.config.gateway.chainId;
|
|
129048
131528
|
return createSdkStorageAdapter(createVanaStorageProvider({
|
|
@@ -129097,6 +131577,7 @@ async function resolvePsLiteOwner(input) {
|
|
|
129097
131577
|
|
|
129098
131578
|
// ../lite/dist/sync.js
|
|
129099
131579
|
var SYNC_CURSOR_KEY = "sync-cursor-v1";
|
|
131580
|
+
var PENDING_BLOB_DELETIONS_KEY = "pending-blob-deletions-v1";
|
|
129100
131581
|
function createBrowserLogger(logger) {
|
|
129101
131582
|
const fallback = {
|
|
129102
131583
|
info: console.info.bind(console),
|
|
@@ -129127,6 +131608,19 @@ function createPsLiteSyncCursor(stateStore) {
|
|
|
129127
131608
|
}
|
|
129128
131609
|
};
|
|
129129
131610
|
}
|
|
131611
|
+
function createPsLitePendingBlobDeletionStore(stateStore) {
|
|
131612
|
+
return createPendingBlobDeletionStore({
|
|
131613
|
+
async read() {
|
|
131614
|
+
const state = await stateStore.get(PENDING_BLOB_DELETIONS_KEY);
|
|
131615
|
+
if (!state)
|
|
131616
|
+
return null;
|
|
131617
|
+
return normalizePendingBlobDeletions(state.keys ?? state.scopes);
|
|
131618
|
+
},
|
|
131619
|
+
async write(keys) {
|
|
131620
|
+
await stateStore.set(PENDING_BLOB_DELETIONS_KEY, { keys });
|
|
131621
|
+
}
|
|
131622
|
+
});
|
|
131623
|
+
}
|
|
129130
131624
|
function buildDownloadDiagnosticsHook(recorder) {
|
|
129131
131625
|
return {
|
|
129132
131626
|
onDownloadStart(fileId) {
|
|
@@ -129212,6 +131706,20 @@ async function createPsLiteSyncManager(options) {
|
|
|
129212
131706
|
});
|
|
129213
131707
|
const cursor = createPsLiteSyncCursor(options.stateStore);
|
|
129214
131708
|
const logger = createBrowserLogger(options.logger);
|
|
131709
|
+
const dataPointFeed = options.dataPointFeed ?? createGatewayDataPointFeed({ gatewayUrl: options.config.gateway.url });
|
|
131710
|
+
const scopeDeletions = options.scopeDeletions ?? createScopeDeletionTracker({ feed: dataPointFeed, serverOwner, logger });
|
|
131711
|
+
const deleteData = createGatewayDeleteDataPort({
|
|
131712
|
+
gatewayUrl: options.config.gateway.url,
|
|
131713
|
+
dataPointFeed,
|
|
131714
|
+
serverOwner,
|
|
131715
|
+
signer,
|
|
131716
|
+
storage: {
|
|
131717
|
+
endpoint: resolveVanaStorageEndpoint(options.config),
|
|
131718
|
+
chainId: options.config.gateway.chainId,
|
|
131719
|
+
signMessage: (message) => options.serverAccount.signMessage(message)
|
|
131720
|
+
}
|
|
131721
|
+
});
|
|
131722
|
+
const pendingBlobDeletions = createPsLitePendingBlobDeletionStore(options.stateStore);
|
|
129215
131723
|
const downloadDiagnostics = options.diagnostics ? buildDownloadDiagnosticsHook(options.diagnostics) : void 0;
|
|
129216
131724
|
const syncManager = createSyncManager({
|
|
129217
131725
|
storage: options.storage,
|
|
@@ -129221,7 +131729,9 @@ async function createPsLiteSyncManager(options) {
|
|
|
129221
131729
|
masterKey,
|
|
129222
131730
|
serverOwner,
|
|
129223
131731
|
logger,
|
|
129224
|
-
lineageGateway: options.lineageGateway
|
|
131732
|
+
lineageGateway: options.lineageGateway,
|
|
131733
|
+
dataPointFeed,
|
|
131734
|
+
scopeDeletions
|
|
129225
131735
|
}, {
|
|
129226
131736
|
storage: options.storage,
|
|
129227
131737
|
storageAdapter,
|
|
@@ -129230,8 +131740,13 @@ async function createPsLiteSyncManager(options) {
|
|
|
129230
131740
|
masterKey,
|
|
129231
131741
|
serverOwner,
|
|
129232
131742
|
logger,
|
|
129233
|
-
diagnostics: downloadDiagnostics
|
|
131743
|
+
diagnostics: downloadDiagnostics,
|
|
131744
|
+
dataPointFeed,
|
|
131745
|
+
scopeDeletions,
|
|
131746
|
+
onDataPointIndexed: options.onDataPointIndexed
|
|
129234
131747
|
}, {
|
|
131748
|
+
deleteData,
|
|
131749
|
+
pendingBlobDeletions,
|
|
129235
131750
|
async canSync() {
|
|
129236
131751
|
try {
|
|
129237
131752
|
const serverInfo = await gateway.getServer(options.serverAccount.address);
|
|
@@ -129253,7 +131768,59 @@ async function createPsLiteSyncManager(options) {
|
|
|
129253
131768
|
}
|
|
129254
131769
|
});
|
|
129255
131770
|
syncManager.start();
|
|
129256
|
-
return { syncManager, serverOwner };
|
|
131771
|
+
return { syncManager, serverOwner, dataPointFeed, scopeDeletions };
|
|
131772
|
+
}
|
|
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 };
|
|
129257
131824
|
}
|
|
129258
131825
|
|
|
129259
131826
|
// ../lite/dist/persistence.js
|
|
@@ -129319,8 +131886,32 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
129319
131886
|
requestSigner: createRequestSigner(identity.account)
|
|
129320
131887
|
});
|
|
129321
131888
|
let syncManager = options.syncManager ?? null;
|
|
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
|
+
}
|
|
129322
131913
|
if (!syncManager && config2.sync.enabled) {
|
|
129323
|
-
|
|
131914
|
+
const sync = await createPsLiteSyncManager({
|
|
129324
131915
|
config: config2,
|
|
129325
131916
|
stateStore,
|
|
129326
131917
|
storage,
|
|
@@ -129328,12 +131919,18 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
129328
131919
|
ownerAddress: options.ownerAddress,
|
|
129329
131920
|
serverAccount: identity.account,
|
|
129330
131921
|
gateway,
|
|
131922
|
+
dataPointFeed: options.dataPointFeed,
|
|
131923
|
+
scopeDeletions,
|
|
129331
131924
|
diagnostics,
|
|
129332
131925
|
logger: options.logger,
|
|
129333
|
-
lineageGateway
|
|
129334
|
-
|
|
131926
|
+
lineageGateway,
|
|
131927
|
+
onDataPointIndexed: (event) => derivatives?.scheduler.markSourceChanged(event.scope, {
|
|
131928
|
+
lineageSources: event.lineageSources
|
|
131929
|
+
})
|
|
131930
|
+
});
|
|
131931
|
+
syncManager = sync.syncManager;
|
|
131932
|
+
scopeDeletions = sync.scopeDeletions;
|
|
129335
131933
|
}
|
|
129336
|
-
let runtimeRef = null;
|
|
129337
131934
|
const auth = options.auth ?? createWeb3SignedPsLiteAuth({
|
|
129338
131935
|
origin: () => options.runtimeOrigin ?? config2.server.origin,
|
|
129339
131936
|
ownerAddress: serverOwner,
|
|
@@ -129360,8 +131957,10 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
129360
131957
|
serverOwner,
|
|
129361
131958
|
serverSigner,
|
|
129362
131959
|
syncManager,
|
|
131960
|
+
scopeDeletions,
|
|
129363
131961
|
diagnostics,
|
|
129364
131962
|
lineageGateway,
|
|
131963
|
+
derivatives,
|
|
129365
131964
|
saveConfig: async (nextConfig) => {
|
|
129366
131965
|
const saved = await savePsLiteConfig(stateStore, nextConfig);
|
|
129367
131966
|
Object.assign(config2, saved);
|
|
@@ -129384,7 +131983,8 @@ async function createIndexedDbPsLiteRuntime(options) {
|
|
|
129384
131983
|
storage,
|
|
129385
131984
|
tokenStore,
|
|
129386
131985
|
accessLogStore,
|
|
129387
|
-
syncManager
|
|
131986
|
+
syncManager,
|
|
131987
|
+
derivatives
|
|
129388
131988
|
};
|
|
129389
131989
|
}
|
|
129390
131990
|
|