@opendatalabs/personal-server-ts-server 1.31.0 → 1.33.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/app.d.ts +6 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +1 -0
- package/dist/app.js.map +1 -1
- package/dist/bootstrap.d.ts +7 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +4 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/routes/mcp.d.ts +7 -1
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +2 -0
- package/dist/routes/mcp.js.map +1 -1
- package/dist/storage/hierarchy.d.ts +6 -0
- package/dist/storage/hierarchy.d.ts.map +1 -1
- package/dist/storage/hierarchy.js +45 -1
- package/dist/storage/hierarchy.js.map +1 -1
- package/dist/storage/node-data-storage.d.ts.map +1 -1
- package/dist/storage/node-data-storage.js +60 -20
- package/dist/storage/node-data-storage.js.map +1 -1
- package/dist/ui/ps-lite-debug.js +1254 -122
- package/package.json +3 -3
package/dist/ui/ps-lite-debug.js
CHANGED
|
@@ -43409,10 +43409,10 @@ function concatBytes(...arrays) {
|
|
|
43409
43409
|
sum += a10.length;
|
|
43410
43410
|
}
|
|
43411
43411
|
const res = new Uint8Array(sum);
|
|
43412
|
-
for (let i10 = 0,
|
|
43412
|
+
for (let i10 = 0, pad3 = 0; i10 < arrays.length; i10++) {
|
|
43413
43413
|
const a10 = arrays[i10];
|
|
43414
|
-
res.set(a10,
|
|
43415
|
-
|
|
43414
|
+
res.set(a10, pad3);
|
|
43415
|
+
pad3 += a10.length;
|
|
43416
43416
|
}
|
|
43417
43417
|
return res;
|
|
43418
43418
|
}
|
|
@@ -44910,16 +44910,16 @@ var init_hmac = __esm({
|
|
|
44910
44910
|
this.blockLen = this.iHash.blockLen;
|
|
44911
44911
|
this.outputLen = this.iHash.outputLen;
|
|
44912
44912
|
const blockLen = this.blockLen;
|
|
44913
|
-
const
|
|
44914
|
-
|
|
44915
|
-
for (let i10 = 0; i10 <
|
|
44916
|
-
|
|
44917
|
-
this.iHash.update(
|
|
44913
|
+
const pad3 = new Uint8Array(blockLen);
|
|
44914
|
+
pad3.set(key.length > blockLen ? hash2.create().update(key).digest() : key);
|
|
44915
|
+
for (let i10 = 0; i10 < pad3.length; i10++)
|
|
44916
|
+
pad3[i10] ^= 54;
|
|
44917
|
+
this.iHash.update(pad3);
|
|
44918
44918
|
this.oHash = hash2.create();
|
|
44919
|
-
for (let i10 = 0; i10 <
|
|
44920
|
-
|
|
44921
|
-
this.oHash.update(
|
|
44922
|
-
clean(
|
|
44919
|
+
for (let i10 = 0; i10 < pad3.length; i10++)
|
|
44920
|
+
pad3[i10] ^= 54 ^ 92;
|
|
44921
|
+
this.oHash.update(pad3);
|
|
44922
|
+
clean(pad3);
|
|
44923
44923
|
}
|
|
44924
44924
|
update(buf) {
|
|
44925
44925
|
aexists(this);
|
|
@@ -45066,10 +45066,10 @@ function concatBytes3(...arrays) {
|
|
|
45066
45066
|
sum += a10.length;
|
|
45067
45067
|
}
|
|
45068
45068
|
const res = new Uint8Array(sum);
|
|
45069
|
-
for (let i10 = 0,
|
|
45069
|
+
for (let i10 = 0, pad3 = 0; i10 < arrays.length; i10++) {
|
|
45070
45070
|
const a10 = arrays[i10];
|
|
45071
|
-
res.set(a10,
|
|
45072
|
-
|
|
45071
|
+
res.set(a10, pad3);
|
|
45072
|
+
pad3 += a10.length;
|
|
45073
45073
|
}
|
|
45074
45074
|
return res;
|
|
45075
45075
|
}
|
|
@@ -71384,13 +71384,13 @@ var require_cipher = __commonJS({
|
|
|
71384
71384
|
}
|
|
71385
71385
|
this._input.compact();
|
|
71386
71386
|
};
|
|
71387
|
-
BlockCipher.prototype.finish = function(
|
|
71388
|
-
if (
|
|
71387
|
+
BlockCipher.prototype.finish = function(pad3) {
|
|
71388
|
+
if (pad3 && (this.mode.name === "ECB" || this.mode.name === "CBC")) {
|
|
71389
71389
|
this.mode.pad = function(input) {
|
|
71390
|
-
return
|
|
71390
|
+
return pad3(this.blockSize, input, false);
|
|
71391
71391
|
};
|
|
71392
71392
|
this.mode.unpad = function(output) {
|
|
71393
|
-
return
|
|
71393
|
+
return pad3(this.blockSize, output, true);
|
|
71394
71394
|
};
|
|
71395
71395
|
}
|
|
71396
71396
|
var options = {};
|
|
@@ -75188,11 +75188,11 @@ var require_rc2 = __commonJS({
|
|
|
75188
75188
|
*
|
|
75189
75189
|
* @return true if successful, false on error.
|
|
75190
75190
|
*/
|
|
75191
|
-
finish: function(
|
|
75191
|
+
finish: function(pad3) {
|
|
75192
75192
|
var rval = true;
|
|
75193
75193
|
if (encrypt) {
|
|
75194
|
-
if (
|
|
75195
|
-
rval =
|
|
75194
|
+
if (pad3) {
|
|
75195
|
+
rval = pad3(8, _input, !encrypt);
|
|
75196
75196
|
} else {
|
|
75197
75197
|
var padding = _input.length() === 8 ? 8 : 8 - _input.length();
|
|
75198
75198
|
_input.fillWithByte(padding, padding);
|
|
@@ -75205,8 +75205,8 @@ var require_rc2 = __commonJS({
|
|
|
75205
75205
|
if (!encrypt) {
|
|
75206
75206
|
rval = _input.length() === 0;
|
|
75207
75207
|
if (rval) {
|
|
75208
|
-
if (
|
|
75209
|
-
rval =
|
|
75208
|
+
if (pad3) {
|
|
75209
|
+
rval = pad3(8, _output, !encrypt);
|
|
75210
75210
|
} else {
|
|
75211
75211
|
var len = _output.length();
|
|
75212
75212
|
var count = _output.at(len - 1);
|
|
@@ -75579,7 +75579,7 @@ var require_jsbn = __commonJS({
|
|
|
75579
75579
|
return;
|
|
75580
75580
|
}
|
|
75581
75581
|
if (r10 == null) r10 = nbi();
|
|
75582
|
-
var y10 = nbi(), ts3 = this.s,
|
|
75582
|
+
var y10 = nbi(), ts3 = this.s, ms4 = m10.s;
|
|
75583
75583
|
var nsh = this.DB - nbits(pm2.data[pm2.t - 1]);
|
|
75584
75584
|
if (nsh > 0) {
|
|
75585
75585
|
pm2.lShiftTo(nsh, y10);
|
|
@@ -75612,7 +75612,7 @@ var require_jsbn = __commonJS({
|
|
|
75612
75612
|
}
|
|
75613
75613
|
if (q10 != null) {
|
|
75614
75614
|
r10.drShiftTo(ys3, q10);
|
|
75615
|
-
if (ts3 !=
|
|
75615
|
+
if (ts3 != ms4) BigInteger.ZERO.subTo(q10, q10);
|
|
75616
75616
|
}
|
|
75617
75617
|
r10.t = ys3;
|
|
75618
75618
|
r10.clamp();
|
|
@@ -92919,12 +92919,12 @@ function field(value, key) {
|
|
|
92919
92919
|
function arrayLength(value) {
|
|
92920
92920
|
return Array.isArray(value) ? value.length : 0;
|
|
92921
92921
|
}
|
|
92922
|
-
function nestedShortfall(scope,
|
|
92922
|
+
function nestedShortfall(scope, legacyItems2, projectedItems) {
|
|
92923
92923
|
const nested = NESTED_ITEMS[scope];
|
|
92924
92924
|
if (!nested)
|
|
92925
92925
|
return void 0;
|
|
92926
92926
|
const projectedById = new Map(projectedItems.map((item) => [itemId(item), nested(item).held]));
|
|
92927
|
-
const short =
|
|
92927
|
+
const short = legacyItems2.filter((item) => (projectedById.get(itemId(item)) ?? 0) < nested(item).held);
|
|
92928
92928
|
const incomplete = projectedItems.filter((item) => nested(item).selfShort);
|
|
92929
92929
|
const count = short.length + incomplete.length;
|
|
92930
92930
|
return count > 0 ? `the projection holds fewer nested rows than the source or the newest legacy version for ${count} of the ${legacyCollectionKey(scope)}` : void 0;
|
|
@@ -93984,7 +93984,7 @@ var isBytes3 = (a10) => a10 instanceof Uint8Array || ArrayBuffer.isView(a10) &&
|
|
|
93984
93984
|
var abytes3 = (a10, l10) => !isBytes3(a10) || typeof l10 === "number" && l10 > 0 && a10.length !== l10 ? err("Uint8Array expected") : a10;
|
|
93985
93985
|
var u8n2 = (len) => new Uint8Array(len);
|
|
93986
93986
|
var u8fr2 = (buf) => Uint8Array.from(buf);
|
|
93987
|
-
var padh = (n10,
|
|
93987
|
+
var padh = (n10, pad3) => n10.toString(16).padStart(pad3, "0");
|
|
93988
93988
|
var bytesToHex4 = (b10) => Array.from(abytes3(b10)).map((e10) => padh(e10, 2)).join("");
|
|
93989
93989
|
var C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
93990
93990
|
var _ch = (ch3) => {
|
|
@@ -94018,10 +94018,10 @@ var toU8 = (a10, len) => abytes3(isStr(a10) ? hexToBytes3(a10) : u8fr2(abytes3(a
|
|
|
94018
94018
|
var cr2 = () => globalThis?.crypto;
|
|
94019
94019
|
var concatBytes4 = (...arrs) => {
|
|
94020
94020
|
const r10 = u8n2(arrs.reduce((sum, a10) => sum + abytes3(a10).length, 0));
|
|
94021
|
-
let
|
|
94021
|
+
let pad3 = 0;
|
|
94022
94022
|
arrs.forEach((a10) => {
|
|
94023
|
-
r10.set(a10,
|
|
94024
|
-
|
|
94023
|
+
r10.set(a10, pad3);
|
|
94024
|
+
pad3 += a10.length;
|
|
94025
94025
|
});
|
|
94026
94026
|
return r10;
|
|
94027
94027
|
};
|
|
@@ -111036,8 +111036,8 @@ function parseRetryAfterBodyMs(responseText) {
|
|
|
111036
111036
|
function clampRateLimitDelay(delayMs) {
|
|
111037
111037
|
return Math.min(Math.max(0, delayMs), MAX_RATE_LIMIT_DELAY_MS);
|
|
111038
111038
|
}
|
|
111039
|
-
function sleep(
|
|
111040
|
-
return new Promise((resolve) => setTimeout(resolve,
|
|
111039
|
+
function sleep(ms4) {
|
|
111040
|
+
return new Promise((resolve) => setTimeout(resolve, ms4));
|
|
111041
111041
|
}
|
|
111042
111042
|
async function safeText(response) {
|
|
111043
111043
|
try {
|
|
@@ -112982,6 +112982,952 @@ function assertCanonicalJsonBody(bodyBytes) {
|
|
|
112982
112982
|
}
|
|
112983
112983
|
}
|
|
112984
112984
|
|
|
112985
|
+
// ../core/dist/additions/record-rules.js
|
|
112986
|
+
var singleton = () => ({
|
|
112987
|
+
collection: "profile",
|
|
112988
|
+
idFields: [],
|
|
112989
|
+
rowIdFields: [],
|
|
112990
|
+
singleton: true
|
|
112991
|
+
});
|
|
112992
|
+
var untracked = (collection, aliases) => ({
|
|
112993
|
+
collection,
|
|
112994
|
+
...aliases ? { aliases } : {},
|
|
112995
|
+
idFields: [],
|
|
112996
|
+
rowIdFields: []
|
|
112997
|
+
});
|
|
112998
|
+
var sameId = (collection, fields, aliases) => ({
|
|
112999
|
+
collection,
|
|
113000
|
+
...aliases ? { aliases } : {},
|
|
113001
|
+
idFields: fields,
|
|
113002
|
+
rowIdFields: fields
|
|
113003
|
+
});
|
|
113004
|
+
var MEMORY_RECORD_RULES = {
|
|
113005
|
+
// --- Empty: the owner app counts 0 records for these. -------------------
|
|
113006
|
+
"chatgpt.memories": [],
|
|
113007
|
+
"chatgpt.messages": [],
|
|
113008
|
+
"github.profile": [],
|
|
113009
|
+
"instagram.profile": [],
|
|
113010
|
+
// --- Tracked: an id that is equal in both stored forms. -----------------
|
|
113011
|
+
"chatgpt.conversations": [sameId("conversations", ["id"])],
|
|
113012
|
+
// Claude's conversations and projects keep the row id in both forms.
|
|
113013
|
+
"claude.conversations": [sameId("conversations", ["id"])],
|
|
113014
|
+
"claude.projects": [sameId("projects", ["id"])],
|
|
113015
|
+
// The binding projects the row's `html_url` into the legacy `url`.
|
|
113016
|
+
"github.repositories": [
|
|
113017
|
+
{
|
|
113018
|
+
collection: "repositories",
|
|
113019
|
+
idFields: ["url"],
|
|
113020
|
+
rowIdFields: ["html_url"]
|
|
113021
|
+
}
|
|
113022
|
+
],
|
|
113023
|
+
"github.starred": [
|
|
113024
|
+
{ collection: "starred", idFields: ["url"], rowIdFields: ["html_url"] }
|
|
113025
|
+
],
|
|
113026
|
+
"github.events": [sameId("events", ["id"])],
|
|
113027
|
+
// The PDPP streams behind this legacy scope are stored as their own scopes
|
|
113028
|
+
// (`github.issues`, `github.pull_requests`, `github.user`), never as one
|
|
113029
|
+
// `github.history` rows scope, so these rules serve the legacy body only.
|
|
113030
|
+
"github.history": [
|
|
113031
|
+
sameId("issues", ["id"]),
|
|
113032
|
+
sameId("pullRequests", ["id"], ["pull_requests"])
|
|
113033
|
+
],
|
|
113034
|
+
"github.issues": [sameId("issues", ["id"])],
|
|
113035
|
+
"github.pull_requests": [sameId("pullRequests", ["id"], ["pull_requests"])],
|
|
113036
|
+
// The PDPP `contributions` stream's records become the legacy `days` array.
|
|
113037
|
+
"github.contributions": [sameId("days", ["date"], ["contributions"])],
|
|
113038
|
+
// The binding projects the row `id` into the legacy `recordName`.
|
|
113039
|
+
"icloud_notes.notes": [
|
|
113040
|
+
{ collection: "notes", idFields: ["recordName"], rowIdFields: ["id"] }
|
|
113041
|
+
],
|
|
113042
|
+
"icloud_notes.folders": [
|
|
113043
|
+
{ collection: "folders", idFields: ["recordName"], rowIdFields: ["id"] }
|
|
113044
|
+
],
|
|
113045
|
+
// The legacy post has no id; `taken_at` is copied unchanged.
|
|
113046
|
+
"instagram.posts": [sameId("posts", ["taken_at"])],
|
|
113047
|
+
// The PDPP `following` stream's records become the legacy `accounts` array;
|
|
113048
|
+
// the binding projects the row `id` into the legacy `pk`.
|
|
113049
|
+
"instagram.following": [
|
|
113050
|
+
{
|
|
113051
|
+
collection: "accounts",
|
|
113052
|
+
aliases: ["following"],
|
|
113053
|
+
idFields: ["pk"],
|
|
113054
|
+
rowIdFields: ["id"]
|
|
113055
|
+
}
|
|
113056
|
+
],
|
|
113057
|
+
// The PDPP `ads` stream carries all kinds; `streamFilter` keeps each
|
|
113058
|
+
// collection to the rows the projection assigns to it. The owner app counts
|
|
113059
|
+
// the category rows too, so they are counted (untracked) here.
|
|
113060
|
+
"instagram.ads": [
|
|
113061
|
+
{
|
|
113062
|
+
...sameId("ad_topics", ["name"], ["ads"]),
|
|
113063
|
+
streamFilter: { field: "kind", equals: "ad_topic" }
|
|
113064
|
+
},
|
|
113065
|
+
{
|
|
113066
|
+
...sameId("advertisers", ["name"], ["ads"]),
|
|
113067
|
+
streamFilter: { field: "kind", equals: "advertiser" }
|
|
113068
|
+
},
|
|
113069
|
+
{
|
|
113070
|
+
...untracked("categories", ["ads"]),
|
|
113071
|
+
streamFilter: { field: "kind", equals: "ad_category" }
|
|
113072
|
+
}
|
|
113073
|
+
],
|
|
113074
|
+
"discord.servers": [sameId("servers", ["id"])],
|
|
113075
|
+
"discord.messages": [sameId("messages", ["id"])],
|
|
113076
|
+
"discord.connections": [sameId("connections", ["id"])],
|
|
113077
|
+
// These store a PDPP `{ records }` body, whose rows are the collection. The
|
|
113078
|
+
// dataset-named alias keeps a keyed body (`{ posts: [...] }`) on the same
|
|
113079
|
+
// `records:` keys.
|
|
113080
|
+
"x.posts": [sameId("records", ["id"], ["posts"])],
|
|
113081
|
+
"x.likes": [sameId("records", ["id"], ["likes"])],
|
|
113082
|
+
"x.bookmarks": [sameId("records", ["id"], ["bookmarks"])],
|
|
113083
|
+
// The binding projects the row `uri` unchanged.
|
|
113084
|
+
"spotify.playlists": [
|
|
113085
|
+
sameId("playlists", ["uri"], ["public_playlists", "items"])
|
|
113086
|
+
],
|
|
113087
|
+
"spotify.savedTracks": [
|
|
113088
|
+
sameId("savedTracks", ["uri"], ["tracks", "items", "saved_tracks"])
|
|
113089
|
+
],
|
|
113090
|
+
// The PDPP stream is `saved_tracks`, so the rows are stored under this
|
|
113091
|
+
// scope; its keys equal the legacy `spotify.savedTracks` keys.
|
|
113092
|
+
"spotify.saved_tracks": [
|
|
113093
|
+
sameId("savedTracks", ["uri"], ["saved_tracks", "tracks", "items"])
|
|
113094
|
+
],
|
|
113095
|
+
// The legacy body keeps the order number as `orderId`.
|
|
113096
|
+
"amazon.orders": [
|
|
113097
|
+
{ collection: "orders", idFields: ["orderId"], rowIdFields: ["id"] }
|
|
113098
|
+
],
|
|
113099
|
+
"shop.orders": [sameId("orders", ["id"])],
|
|
113100
|
+
"oura.activity": [sameId("days", ["id"], ["activity"])],
|
|
113101
|
+
"oura.readiness": [sameId("days", ["id"], ["readiness"])],
|
|
113102
|
+
"youtube.playlists": [sameId("playlists", ["url"])],
|
|
113103
|
+
// --- Counted, never tracked: the owner app counts them, but no field is --
|
|
113104
|
+
// --- provably equal in both stored forms. They report a total and no -----
|
|
113105
|
+
// --- additions, and a null trackedSince. ---------------------------------
|
|
113106
|
+
// The legacy body drops the row id.
|
|
113107
|
+
"linkedin.experience": [untracked("items", ["experience", "experiences"])],
|
|
113108
|
+
"linkedin.education": [untracked("items", ["education"])],
|
|
113109
|
+
"linkedin.connections": [untracked("connections")],
|
|
113110
|
+
"linkedin.skills": [untracked("skills")],
|
|
113111
|
+
"linkedin.languages": [untracked("languages")],
|
|
113112
|
+
// One `sleep` stream feeds two legacy arrays, so both are counted.
|
|
113113
|
+
"oura.sleep": [
|
|
113114
|
+
untracked("sleepPeriods", ["sleep"]),
|
|
113115
|
+
untracked("dailyScores")
|
|
113116
|
+
],
|
|
113117
|
+
// No binding fixture proves an id equal in both forms.
|
|
113118
|
+
"heb.orders": [untracked("orders")],
|
|
113119
|
+
"wholefoods.orders": [untracked("orders")],
|
|
113120
|
+
"heb.nutrition": [untracked("nutrition")],
|
|
113121
|
+
"wholefoods.nutrition": [untracked("nutrition")],
|
|
113122
|
+
"youtube.subscriptions": [untracked("subscriptions")],
|
|
113123
|
+
"youtube.likes": [untracked("likedVideos", ["likes"])],
|
|
113124
|
+
"youtube.watchLater": [untracked("watchLater")],
|
|
113125
|
+
"youtube.watch_later": [untracked("watchLater", ["watch_later"])],
|
|
113126
|
+
"youtube.history": [untracked("history")],
|
|
113127
|
+
"youtube.watch_history": [untracked("history", ["watch_history"])],
|
|
113128
|
+
"youtube.playlistItems": [untracked("playlists", ["playlistItems"])],
|
|
113129
|
+
"youtube.playlist_items": [untracked("playlists", ["playlist_items"])],
|
|
113130
|
+
// Single-record scopes.
|
|
113131
|
+
"linkedin.profile": [singleton()],
|
|
113132
|
+
"spotify.profile": [singleton()],
|
|
113133
|
+
"youtube.profile": [singleton()],
|
|
113134
|
+
"heb.profile": [singleton()],
|
|
113135
|
+
"wholefoods.profile": [singleton()],
|
|
113136
|
+
// Streams that only join into another scope's legacy body, which the owner
|
|
113137
|
+
// app counts when they are stored as their own scopes.
|
|
113138
|
+
"amazon.order_items": [untracked("order_items")],
|
|
113139
|
+
"heb.order_items": [untracked("order_items")],
|
|
113140
|
+
"wholefoods.order_items": [untracked("order_items")],
|
|
113141
|
+
"claude.messages": [untracked("messages")],
|
|
113142
|
+
"claude.account_profile": [untracked("account_profile")],
|
|
113143
|
+
"claude.project_documents": [untracked("project_documents")],
|
|
113144
|
+
"github.user": [untracked("user")],
|
|
113145
|
+
"github.user_stats": [untracked("user_stats")],
|
|
113146
|
+
"github.pinned_repositories": [untracked("pinned_repositories")],
|
|
113147
|
+
"github.organizations": [untracked("organizations")],
|
|
113148
|
+
"instagram.post_likes": [untracked("post_likes")],
|
|
113149
|
+
"spotify.playlist_items": [untracked("playlist_items")]
|
|
113150
|
+
};
|
|
113151
|
+
function memoryRecordRulesFor(scope) {
|
|
113152
|
+
if (!Object.prototype.hasOwnProperty.call(MEMORY_RECORD_RULES, scope)) {
|
|
113153
|
+
return null;
|
|
113154
|
+
}
|
|
113155
|
+
return MEMORY_RECORD_RULES[scope] ?? null;
|
|
113156
|
+
}
|
|
113157
|
+
|
|
113158
|
+
// ../core/dist/additions/first-added.js
|
|
113159
|
+
var MAX_TRACKED_KEYS = 2e5;
|
|
113160
|
+
var MAX_ID_LENGTH = 64;
|
|
113161
|
+
var MAX_COLLECTION_LENGTH = 64;
|
|
113162
|
+
var PRUNE_AFTER_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
113163
|
+
var RETRY_UNREADABLE_MS = 60 * 60 * 1e3;
|
|
113164
|
+
var MAX_RETRY_VERSIONS = 20;
|
|
113165
|
+
var YIELD_EVERY = 2e3;
|
|
113166
|
+
function yieldToEventLoop() {
|
|
113167
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
113168
|
+
}
|
|
113169
|
+
var ID_PROPERTIES = ["id", "uuid", "key", "uri", "url"];
|
|
113170
|
+
var SERVER_STAMP_KEYS2 = /* @__PURE__ */ new Set([
|
|
113171
|
+
"$writtenBy",
|
|
113172
|
+
"$lineage"
|
|
113173
|
+
]);
|
|
113174
|
+
function isRecord3(value) {
|
|
113175
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113176
|
+
}
|
|
113177
|
+
function hasOwn(data, key) {
|
|
113178
|
+
return Object.prototype.hasOwnProperty.call(data, key);
|
|
113179
|
+
}
|
|
113180
|
+
function isRowsBody(data) {
|
|
113181
|
+
const keys = Object.keys(data).filter((key) => !SERVER_STAMP_KEYS2.has(key));
|
|
113182
|
+
return keys.length === 1 && keys[0] === "records" && Array.isArray(data.records);
|
|
113183
|
+
}
|
|
113184
|
+
async function sha256Hex2(input) {
|
|
113185
|
+
const bytes2 = new TextEncoder().encode(input);
|
|
113186
|
+
const digest2 = await globalThis.crypto.subtle.digest("SHA-256", bytes2);
|
|
113187
|
+
let hex3 = "";
|
|
113188
|
+
for (const byte of new Uint8Array(digest2)) {
|
|
113189
|
+
hex3 += byte.toString(16).padStart(2, "0");
|
|
113190
|
+
}
|
|
113191
|
+
return hex3;
|
|
113192
|
+
}
|
|
113193
|
+
function valueAtPath(obj, path) {
|
|
113194
|
+
let current = obj;
|
|
113195
|
+
for (const segment of path.split(".")) {
|
|
113196
|
+
if (!isRecord3(current) || !hasOwn(current, segment))
|
|
113197
|
+
return void 0;
|
|
113198
|
+
current = current[segment];
|
|
113199
|
+
}
|
|
113200
|
+
return current;
|
|
113201
|
+
}
|
|
113202
|
+
async function idToken(id2) {
|
|
113203
|
+
if (typeof id2 === "number")
|
|
113204
|
+
return `n:${String(id2)}`;
|
|
113205
|
+
return id2.length > MAX_ID_LENGTH ? `h:${(await sha256Hex2(id2)).slice(0, 32)}` : `i:${id2}`;
|
|
113206
|
+
}
|
|
113207
|
+
async function collectionToken(name) {
|
|
113208
|
+
if (name.length > MAX_COLLECTION_LENGTH) {
|
|
113209
|
+
return `#${(await sha256Hex2(name)).slice(0, 32)}`;
|
|
113210
|
+
}
|
|
113211
|
+
return name.replace(/[\\:#]/g, (character) => `\\${character}`);
|
|
113212
|
+
}
|
|
113213
|
+
async function idPart(obj, fields) {
|
|
113214
|
+
for (const field2 of fields) {
|
|
113215
|
+
const value = valueAtPath(obj, field2);
|
|
113216
|
+
if (typeof value === "string" && value.length > 0)
|
|
113217
|
+
return idToken(value);
|
|
113218
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
113219
|
+
return idToken(value);
|
|
113220
|
+
}
|
|
113221
|
+
}
|
|
113222
|
+
return null;
|
|
113223
|
+
}
|
|
113224
|
+
var KeyCollector = class {
|
|
113225
|
+
keys = /* @__PURE__ */ new Set();
|
|
113226
|
+
total = 0;
|
|
113227
|
+
tooMany = false;
|
|
113228
|
+
/**
|
|
113229
|
+
* Count `items`, and track those with an id. Once the tracked keys pass the
|
|
113230
|
+
* cap it stops collecting (and frees them) but still counts, so a hostile
|
|
113231
|
+
* body costs a bounded amount of work and memory.
|
|
113232
|
+
*/
|
|
113233
|
+
async addItems(collection, items, idFields) {
|
|
113234
|
+
this.total += items.length;
|
|
113235
|
+
if (this.tooMany || idFields.length === 0)
|
|
113236
|
+
return;
|
|
113237
|
+
const prefix = await collectionToken(collection);
|
|
113238
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
113239
|
+
if (index % YIELD_EVERY === YIELD_EVERY - 1)
|
|
113240
|
+
await yieldToEventLoop();
|
|
113241
|
+
const item = items[index];
|
|
113242
|
+
if (!isRecord3(item))
|
|
113243
|
+
continue;
|
|
113244
|
+
const id2 = await idPart(item, idFields);
|
|
113245
|
+
if (id2 === null)
|
|
113246
|
+
continue;
|
|
113247
|
+
this.keys.add(`${prefix}:${id2}`);
|
|
113248
|
+
if (this.keys.size > MAX_TRACKED_KEYS) {
|
|
113249
|
+
this.tooMany = true;
|
|
113250
|
+
this.keys.clear();
|
|
113251
|
+
return;
|
|
113252
|
+
}
|
|
113253
|
+
}
|
|
113254
|
+
}
|
|
113255
|
+
result() {
|
|
113256
|
+
return {
|
|
113257
|
+
keys: Array.from(this.keys),
|
|
113258
|
+
total: this.total,
|
|
113259
|
+
...this.tooMany ? { tooMany: true } : {}
|
|
113260
|
+
};
|
|
113261
|
+
}
|
|
113262
|
+
};
|
|
113263
|
+
function datasetOf(scope) {
|
|
113264
|
+
const dot = scope.indexOf(".");
|
|
113265
|
+
return dot < 0 ? scope : scope.slice(dot + 1);
|
|
113266
|
+
}
|
|
113267
|
+
function passesStreamFilter(row, rule) {
|
|
113268
|
+
return !rule.streamFilter || row[rule.streamFilter.field] === rule.streamFilter.equals;
|
|
113269
|
+
}
|
|
113270
|
+
function legacyItems(data, rule) {
|
|
113271
|
+
for (const name of [rule.collection, ...rule.aliases ?? []]) {
|
|
113272
|
+
if (!hasOwn(data, name))
|
|
113273
|
+
continue;
|
|
113274
|
+
const value = data[name];
|
|
113275
|
+
if (!Array.isArray(value))
|
|
113276
|
+
continue;
|
|
113277
|
+
return value.filter(isRecord3);
|
|
113278
|
+
}
|
|
113279
|
+
return [];
|
|
113280
|
+
}
|
|
113281
|
+
async function extractRecordKeys(scope, data) {
|
|
113282
|
+
if (!isRecord3(data))
|
|
113283
|
+
return null;
|
|
113284
|
+
const rules = memoryRecordRulesFor(scope);
|
|
113285
|
+
if (rules !== null && rules.length === 0)
|
|
113286
|
+
return { keys: [], total: 0 };
|
|
113287
|
+
if (hasOwn(data, "$binary"))
|
|
113288
|
+
return null;
|
|
113289
|
+
const collector = new KeyCollector();
|
|
113290
|
+
const rows = isRowsBody(data) ? data.records : null;
|
|
113291
|
+
if (rules !== null) {
|
|
113292
|
+
if (rows !== null) {
|
|
113293
|
+
const dataset = datasetOf(scope);
|
|
113294
|
+
const named = rules.filter((rule) => rule.collection === dataset || (rule.aliases ?? []).includes(dataset));
|
|
113295
|
+
const chosen = named.length > 0 ? named : rules.length === 1 ? rules : [];
|
|
113296
|
+
if (chosen.length === 0 && rules.length > 0) {
|
|
113297
|
+
collector.total += rows.length;
|
|
113298
|
+
}
|
|
113299
|
+
for (const rule of chosen) {
|
|
113300
|
+
if (rule.singleton) {
|
|
113301
|
+
collector.total += rows.filter(isRecord3).length;
|
|
113302
|
+
continue;
|
|
113303
|
+
}
|
|
113304
|
+
const items = rows.filter(isRecord3).filter((row) => passesStreamFilter(row, rule));
|
|
113305
|
+
await collector.addItems(rule.collection, items, rule.rowIdFields);
|
|
113306
|
+
}
|
|
113307
|
+
} else {
|
|
113308
|
+
for (const rule of rules) {
|
|
113309
|
+
if (rule.singleton) {
|
|
113310
|
+
if (Object.keys(data).some((key) => !key.startsWith("$"))) {
|
|
113311
|
+
collector.total += 1;
|
|
113312
|
+
}
|
|
113313
|
+
continue;
|
|
113314
|
+
}
|
|
113315
|
+
await collector.addItems(rule.collection, legacyItems(data, rule), rule.idFields);
|
|
113316
|
+
}
|
|
113317
|
+
}
|
|
113318
|
+
return collector.result();
|
|
113319
|
+
}
|
|
113320
|
+
if (rows !== null) {
|
|
113321
|
+
await collector.addItems(datasetOf(scope), rows, ID_PROPERTIES);
|
|
113322
|
+
return collector.result();
|
|
113323
|
+
}
|
|
113324
|
+
let sawArray = false;
|
|
113325
|
+
for (const key of Object.keys(data)) {
|
|
113326
|
+
if (key.startsWith("$"))
|
|
113327
|
+
continue;
|
|
113328
|
+
const value = data[key];
|
|
113329
|
+
if (!Array.isArray(value))
|
|
113330
|
+
continue;
|
|
113331
|
+
sawArray = true;
|
|
113332
|
+
await collector.addItems(key, value, ID_PROPERTIES);
|
|
113333
|
+
}
|
|
113334
|
+
if (!sawArray)
|
|
113335
|
+
collector.total = 1;
|
|
113336
|
+
return collector.result();
|
|
113337
|
+
}
|
|
113338
|
+
function ms3(value) {
|
|
113339
|
+
return value === null ? Number.NaN : Date.parse(value);
|
|
113340
|
+
}
|
|
113341
|
+
function isNewer(a10, b10) {
|
|
113342
|
+
if (b10 === null)
|
|
113343
|
+
return true;
|
|
113344
|
+
const difference = Date.parse(a10) - Date.parse(b10);
|
|
113345
|
+
return difference > 0 || difference === 0 && a10 >= b10;
|
|
113346
|
+
}
|
|
113347
|
+
function isEarlier(a10, b10) {
|
|
113348
|
+
const difference = Date.parse(a10) - Date.parse(b10);
|
|
113349
|
+
return difference < 0 || difference === 0 && a10 < b10;
|
|
113350
|
+
}
|
|
113351
|
+
function isTrackable(extraction) {
|
|
113352
|
+
return extraction !== null && !extraction.tooMany && (extraction.keys.length > 0 || extraction.total === 0);
|
|
113353
|
+
}
|
|
113354
|
+
var LedgerFold = class {
|
|
113355
|
+
scope;
|
|
113356
|
+
baseline = null;
|
|
113357
|
+
current = null;
|
|
113358
|
+
latest = null;
|
|
113359
|
+
through = null;
|
|
113360
|
+
retry;
|
|
113361
|
+
skipped;
|
|
113362
|
+
partial = false;
|
|
113363
|
+
// A Map keeps arbitrary keys (including "__proto__") out of the prototype
|
|
113364
|
+
// chain; Object.fromEntries defines each one as an own property again.
|
|
113365
|
+
records = /* @__PURE__ */ new Map();
|
|
113366
|
+
constructor(ledger, scope) {
|
|
113367
|
+
this.scope = ledger?.scope ?? scope ?? null;
|
|
113368
|
+
if (!ledger)
|
|
113369
|
+
return;
|
|
113370
|
+
this.baseline = ledger.baseline;
|
|
113371
|
+
this.current = ledger.current;
|
|
113372
|
+
this.latest = { ...ledger.latest };
|
|
113373
|
+
this.through = ledger.through;
|
|
113374
|
+
this.retry = ledger.retry ? {
|
|
113375
|
+
versions: [...ledger.retry.versions],
|
|
113376
|
+
attemptedAt: ledger.retry.attemptedAt
|
|
113377
|
+
} : void 0;
|
|
113378
|
+
this.skipped = ledger.skipped;
|
|
113379
|
+
this.partial = ledger.partial === true;
|
|
113380
|
+
for (const [key, pair] of Object.entries(ledger.records)) {
|
|
113381
|
+
this.records.set(key, [pair[0], pair[1]]);
|
|
113382
|
+
}
|
|
113383
|
+
}
|
|
113384
|
+
async add(version4) {
|
|
113385
|
+
const at3 = Date.parse(version4.collectedAt);
|
|
113386
|
+
if (Number.isNaN(at3))
|
|
113387
|
+
return;
|
|
113388
|
+
if (this.scope === null)
|
|
113389
|
+
this.scope = version4.scope;
|
|
113390
|
+
if (this.scope !== version4.scope)
|
|
113391
|
+
return;
|
|
113392
|
+
const extraction = await extractRecordKeys(version4.scope, version4.data);
|
|
113393
|
+
const total = extraction?.total ?? 1;
|
|
113394
|
+
if (this.latest === null || isNewer(version4.collectedAt, this.latest.collectedAt)) {
|
|
113395
|
+
this.latest = { collectedAt: version4.collectedAt, total };
|
|
113396
|
+
}
|
|
113397
|
+
if (isNewer(version4.collectedAt, this.through)) {
|
|
113398
|
+
this.through = version4.collectedAt;
|
|
113399
|
+
}
|
|
113400
|
+
if (this.skipped !== void 0)
|
|
113401
|
+
return;
|
|
113402
|
+
if (!isTrackable(extraction))
|
|
113403
|
+
return;
|
|
113404
|
+
if (this.baseline === null) {
|
|
113405
|
+
this.baseline = version4.collectedAt;
|
|
113406
|
+
} else if (isEarlier(version4.collectedAt, this.baseline) && !this.partial) {
|
|
113407
|
+
this.baseline = version4.collectedAt;
|
|
113408
|
+
}
|
|
113409
|
+
if (isNewer(version4.collectedAt, this.current)) {
|
|
113410
|
+
this.current = version4.collectedAt;
|
|
113411
|
+
}
|
|
113412
|
+
const keys = extraction.keys;
|
|
113413
|
+
const fresh = [];
|
|
113414
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
113415
|
+
if (index % YIELD_EVERY === YIELD_EVERY - 1)
|
|
113416
|
+
await yieldToEventLoop();
|
|
113417
|
+
const key = keys[index];
|
|
113418
|
+
const existing = this.records.get(key);
|
|
113419
|
+
if (!existing) {
|
|
113420
|
+
fresh.push(key);
|
|
113421
|
+
continue;
|
|
113422
|
+
}
|
|
113423
|
+
if (isEarlier(version4.collectedAt, existing[0])) {
|
|
113424
|
+
existing[0] = version4.collectedAt;
|
|
113425
|
+
}
|
|
113426
|
+
if (isNewer(version4.collectedAt, existing[1])) {
|
|
113427
|
+
existing[1] = version4.collectedAt;
|
|
113428
|
+
}
|
|
113429
|
+
}
|
|
113430
|
+
if (fresh.length > 0)
|
|
113431
|
+
await this.insertFresh(fresh, keys, version4.collectedAt);
|
|
113432
|
+
}
|
|
113433
|
+
/**
|
|
113434
|
+
* Insert the records this version brings that the ledger does not know.
|
|
113435
|
+
* Capacity is decided ONCE: when they do not fit, absent records are evicted
|
|
113436
|
+
* in a single pass (see `evict`), and whatever still does not fit is left
|
|
113437
|
+
* out, smallest keys first, so the result never depends on the order of the
|
|
113438
|
+
* ids in the version.
|
|
113439
|
+
*/
|
|
113440
|
+
async insertFresh(fresh, versionKeys, collectedAt) {
|
|
113441
|
+
fresh.sort();
|
|
113442
|
+
let room = MAX_TRACKED_KEYS - this.records.size;
|
|
113443
|
+
if (fresh.length > room) {
|
|
113444
|
+
room += await this.evict(fresh.length - room, new Set(versionKeys));
|
|
113445
|
+
}
|
|
113446
|
+
const take = Math.min(fresh.length, Math.max(0, room));
|
|
113447
|
+
for (let index = 0; index < take; index += 1) {
|
|
113448
|
+
if (index % YIELD_EVERY === YIELD_EVERY - 1)
|
|
113449
|
+
await yieldToEventLoop();
|
|
113450
|
+
this.records.set(fresh[index], [collectedAt, collectedAt]);
|
|
113451
|
+
}
|
|
113452
|
+
}
|
|
113453
|
+
/**
|
|
113454
|
+
* Make room for `need` records by dropping some that are absent: not in the
|
|
113455
|
+
* newest tracked version, not in the version being folded, and not
|
|
113456
|
+
* pre-tracking (first seen at or before the baseline). Pre-tracking records
|
|
113457
|
+
* are never dropped. Dated records that are absent CAN be dropped (and are
|
|
113458
|
+
* dated as new if they return): that needs a scope near the cap, and
|
|
113459
|
+
* whoever can write the scope can provoke it. Among the evictable ones the
|
|
113460
|
+
* most recently first seen go first. Returns how many were dropped.
|
|
113461
|
+
*/
|
|
113462
|
+
async evict(need, inVersion) {
|
|
113463
|
+
const currentMs = ms3(this.current);
|
|
113464
|
+
const baselineMs = ms3(this.baseline);
|
|
113465
|
+
const candidates = [];
|
|
113466
|
+
let seen = 0;
|
|
113467
|
+
for (const [key, pair] of this.records) {
|
|
113468
|
+
seen += 1;
|
|
113469
|
+
if (seen % (YIELD_EVERY * 5) === 0)
|
|
113470
|
+
await yieldToEventLoop();
|
|
113471
|
+
if (inVersion.has(key))
|
|
113472
|
+
continue;
|
|
113473
|
+
if (Date.parse(pair[1]) === currentMs)
|
|
113474
|
+
continue;
|
|
113475
|
+
const firstMs = Date.parse(pair[0]);
|
|
113476
|
+
if (firstMs <= baselineMs)
|
|
113477
|
+
continue;
|
|
113478
|
+
candidates.push([firstMs, key]);
|
|
113479
|
+
}
|
|
113480
|
+
candidates.sort((a10, b10) => b10[0] - a10[0] || (a10[1] < b10[1] ? -1 : a10[1] > b10[1] ? 1 : 0));
|
|
113481
|
+
const count = Math.min(need, candidates.length);
|
|
113482
|
+
for (let index = 0; index < count; index += 1) {
|
|
113483
|
+
this.records.delete(candidates[index][1]);
|
|
113484
|
+
}
|
|
113485
|
+
return count;
|
|
113486
|
+
}
|
|
113487
|
+
/** Drop records that are not present and were last seen over 90 days before `current`. */
|
|
113488
|
+
async prune() {
|
|
113489
|
+
if (this.current === null || this.skipped !== void 0)
|
|
113490
|
+
return;
|
|
113491
|
+
const currentMs = ms3(this.current);
|
|
113492
|
+
const cutoff = currentMs - PRUNE_AFTER_MS;
|
|
113493
|
+
let seen = 0;
|
|
113494
|
+
for (const [key, pair] of this.records) {
|
|
113495
|
+
seen += 1;
|
|
113496
|
+
if (seen % (YIELD_EVERY * 5) === 0)
|
|
113497
|
+
await yieldToEventLoop();
|
|
113498
|
+
const lastMs = Date.parse(pair[1]);
|
|
113499
|
+
if (lastMs !== currentMs && lastMs < cutoff)
|
|
113500
|
+
this.records.delete(key);
|
|
113501
|
+
}
|
|
113502
|
+
}
|
|
113503
|
+
/**
|
|
113504
|
+
* Prune and return the ledger, or null when nothing was ever folded.
|
|
113505
|
+
* `partial` marks a ledger rebuilt from only the newest retained versions;
|
|
113506
|
+
* `through` overrides the completeness marker (see `ScopeFirstSeenLedger`).
|
|
113507
|
+
*/
|
|
113508
|
+
async finish(options = {}) {
|
|
113509
|
+
if (this.scope === null || this.latest === null)
|
|
113510
|
+
return null;
|
|
113511
|
+
await this.prune();
|
|
113512
|
+
const partial2 = this.partial || options.partial === true;
|
|
113513
|
+
const retry = options.retry === void 0 ? this.retry : options.retry;
|
|
113514
|
+
return {
|
|
113515
|
+
version: 3,
|
|
113516
|
+
scope: this.scope,
|
|
113517
|
+
baseline: this.baseline,
|
|
113518
|
+
current: this.current,
|
|
113519
|
+
latest: this.latest,
|
|
113520
|
+
through: options.through ?? this.through ?? this.latest.collectedAt,
|
|
113521
|
+
...retry ? { retry } : {},
|
|
113522
|
+
...this.skipped ? { skipped: this.skipped } : {},
|
|
113523
|
+
...partial2 ? { partial: true } : {},
|
|
113524
|
+
records: Object.fromEntries(this.records)
|
|
113525
|
+
};
|
|
113526
|
+
}
|
|
113527
|
+
};
|
|
113528
|
+
function listAddedTimestamps(ledger) {
|
|
113529
|
+
if (ledger.skipped !== void 0 || ledger.baseline === null || ledger.current === null || Date.parse(ledger.current) !== Date.parse(ledger.latest.collectedAt)) {
|
|
113530
|
+
return [];
|
|
113531
|
+
}
|
|
113532
|
+
const baselineMs = Date.parse(ledger.baseline);
|
|
113533
|
+
const currentMs = Date.parse(ledger.current);
|
|
113534
|
+
const added = [];
|
|
113535
|
+
for (const [first, last2] of Object.values(ledger.records)) {
|
|
113536
|
+
if (Date.parse(last2) !== currentMs)
|
|
113537
|
+
continue;
|
|
113538
|
+
if (Date.parse(first) <= baselineMs)
|
|
113539
|
+
continue;
|
|
113540
|
+
added.push(first);
|
|
113541
|
+
}
|
|
113542
|
+
if (added.length > ledger.latest.total) {
|
|
113543
|
+
added.sort();
|
|
113544
|
+
added.length = ledger.latest.total;
|
|
113545
|
+
}
|
|
113546
|
+
return added;
|
|
113547
|
+
}
|
|
113548
|
+
function parseableString(value) {
|
|
113549
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
113550
|
+
}
|
|
113551
|
+
function nullableParseable(value) {
|
|
113552
|
+
return value === null || parseableString(value);
|
|
113553
|
+
}
|
|
113554
|
+
var SKIP_REASONS = /* @__PURE__ */ new Set(["too_large", "unreadable"]);
|
|
113555
|
+
function readScopeFirstSeenLedger(value) {
|
|
113556
|
+
try {
|
|
113557
|
+
if (!isRecord3(value) || value.version !== 3)
|
|
113558
|
+
return null;
|
|
113559
|
+
const { scope, baseline, current, latest, through, records, skipped, partial: partial2 } = value;
|
|
113560
|
+
if (typeof scope !== "string" || scope.length === 0)
|
|
113561
|
+
return null;
|
|
113562
|
+
if (!nullableParseable(baseline) || !nullableParseable(current)) {
|
|
113563
|
+
return null;
|
|
113564
|
+
}
|
|
113565
|
+
if (!isRecord3(latest) || !parseableString(latest.collectedAt))
|
|
113566
|
+
return null;
|
|
113567
|
+
if (!parseableString(through))
|
|
113568
|
+
return null;
|
|
113569
|
+
let retryValue;
|
|
113570
|
+
if (value.retry !== void 0) {
|
|
113571
|
+
const retry = value.retry;
|
|
113572
|
+
if (!isRecord3(retry) || !Array.isArray(retry.versions) || retry.versions.length === 0 || retry.versions.length > MAX_RETRY_VERSIONS || !retry.versions.every(parseableString) || !parseableString(retry.attemptedAt)) {
|
|
113573
|
+
return null;
|
|
113574
|
+
}
|
|
113575
|
+
retryValue = {
|
|
113576
|
+
versions: [...retry.versions],
|
|
113577
|
+
attemptedAt: retry.attemptedAt
|
|
113578
|
+
};
|
|
113579
|
+
}
|
|
113580
|
+
const newestKnown = Math.max(Date.parse(latest.collectedAt), ...retryValue?.versions.map((version4) => Date.parse(version4)) ?? []);
|
|
113581
|
+
if (Date.parse(through) > newestKnown)
|
|
113582
|
+
return null;
|
|
113583
|
+
const total = latest.total;
|
|
113584
|
+
if (typeof total !== "number" || !Number.isInteger(total) || total < 0) {
|
|
113585
|
+
return null;
|
|
113586
|
+
}
|
|
113587
|
+
if (skipped !== void 0 && !SKIP_REASONS.has(skipped))
|
|
113588
|
+
return null;
|
|
113589
|
+
if (partial2 !== void 0 && partial2 !== true)
|
|
113590
|
+
return null;
|
|
113591
|
+
if (!isRecord3(records))
|
|
113592
|
+
return null;
|
|
113593
|
+
const entries = Object.entries(records);
|
|
113594
|
+
if (entries.length > MAX_TRACKED_KEYS)
|
|
113595
|
+
return null;
|
|
113596
|
+
const copied = /* @__PURE__ */ new Map();
|
|
113597
|
+
for (const [key, pair] of entries) {
|
|
113598
|
+
if (!Array.isArray(pair) || pair.length !== 2)
|
|
113599
|
+
return null;
|
|
113600
|
+
if (!parseableString(pair[0]) || !parseableString(pair[1]))
|
|
113601
|
+
return null;
|
|
113602
|
+
copied.set(key, [pair[0], pair[1]]);
|
|
113603
|
+
}
|
|
113604
|
+
return {
|
|
113605
|
+
version: 3,
|
|
113606
|
+
scope,
|
|
113607
|
+
baseline,
|
|
113608
|
+
current,
|
|
113609
|
+
latest: { collectedAt: latest.collectedAt, total },
|
|
113610
|
+
through,
|
|
113611
|
+
...retryValue ? { retry: retryValue } : {},
|
|
113612
|
+
...skipped ? { skipped } : {},
|
|
113613
|
+
...partial2 ? { partial: true } : {},
|
|
113614
|
+
records: Object.fromEntries(copied)
|
|
113615
|
+
};
|
|
113616
|
+
} catch {
|
|
113617
|
+
return null;
|
|
113618
|
+
}
|
|
113619
|
+
}
|
|
113620
|
+
|
|
113621
|
+
// ../core/dist/additions/scope-lock.js
|
|
113622
|
+
var tails = /* @__PURE__ */ new Map();
|
|
113623
|
+
async function withScopeLock(scope, fn3) {
|
|
113624
|
+
const previous = tails.get(scope) ?? Promise.resolve();
|
|
113625
|
+
let release;
|
|
113626
|
+
const mine = new Promise((resolve) => {
|
|
113627
|
+
release = resolve;
|
|
113628
|
+
});
|
|
113629
|
+
const tail = previous.then(() => mine);
|
|
113630
|
+
tails.set(scope, tail);
|
|
113631
|
+
await previous;
|
|
113632
|
+
try {
|
|
113633
|
+
return await fn3();
|
|
113634
|
+
} finally {
|
|
113635
|
+
release();
|
|
113636
|
+
if (tails.get(scope) === tail)
|
|
113637
|
+
tails.delete(scope);
|
|
113638
|
+
}
|
|
113639
|
+
}
|
|
113640
|
+
|
|
113641
|
+
// ../core/dist/additions/ledger-store.js
|
|
113642
|
+
var REBUILD_VERSION_LIMIT = 200;
|
|
113643
|
+
var REBUILD_BYTE_BUDGET = 256 * 1024 * 1024;
|
|
113644
|
+
function isRecord4(value) {
|
|
113645
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113646
|
+
}
|
|
113647
|
+
function readsNothing(scope) {
|
|
113648
|
+
return memoryRecordRulesFor(scope)?.length === 0;
|
|
113649
|
+
}
|
|
113650
|
+
async function readVersionData(storage, scope, collectedAt) {
|
|
113651
|
+
if (readsNothing(scope))
|
|
113652
|
+
return { scope, collectedAt, data: {} };
|
|
113653
|
+
try {
|
|
113654
|
+
const envelope = storage.readStoredEnvelope ? await storage.readStoredEnvelope(scope, collectedAt) : await storage.readEnvelope(scope, collectedAt);
|
|
113655
|
+
if (!isRecord4(envelope.data))
|
|
113656
|
+
return null;
|
|
113657
|
+
return { scope, collectedAt, data: envelope.data };
|
|
113658
|
+
} catch {
|
|
113659
|
+
return null;
|
|
113660
|
+
}
|
|
113661
|
+
}
|
|
113662
|
+
function retainedVersions(storage, scope) {
|
|
113663
|
+
return storage.listVersions(scope, { limit: REBUILD_VERSION_LIMIT }).filter((entry) => !Number.isNaN(Date.parse(entry.collectedAt))).sort((a10, b10) => Date.parse(b10.collectedAt) - Date.parse(a10.collectedAt) || (a10.collectedAt < b10.collectedAt ? 1 : a10.collectedAt > b10.collectedAt ? -1 : 0));
|
|
113664
|
+
}
|
|
113665
|
+
function withinBudget(scope, entries, budget) {
|
|
113666
|
+
if (readsNothing(scope))
|
|
113667
|
+
return [...entries];
|
|
113668
|
+
const selected = [];
|
|
113669
|
+
let used = 0;
|
|
113670
|
+
for (const entry of entries) {
|
|
113671
|
+
used += Math.max(0, entry.sizeBytes ?? 0);
|
|
113672
|
+
if (used > budget)
|
|
113673
|
+
break;
|
|
113674
|
+
selected.push(entry);
|
|
113675
|
+
}
|
|
113676
|
+
return selected;
|
|
113677
|
+
}
|
|
113678
|
+
async function readStoredLedger(storage, scope) {
|
|
113679
|
+
if (!storage.readFirstSeenLedger)
|
|
113680
|
+
return null;
|
|
113681
|
+
try {
|
|
113682
|
+
const ledger = readScopeFirstSeenLedger(await storage.readFirstSeenLedger(scope));
|
|
113683
|
+
return ledger !== null && ledger.scope === scope ? ledger : null;
|
|
113684
|
+
} catch {
|
|
113685
|
+
return null;
|
|
113686
|
+
}
|
|
113687
|
+
}
|
|
113688
|
+
async function dropIfScopeEmpty(storage, scope) {
|
|
113689
|
+
if (storage.findEntry({ scope }))
|
|
113690
|
+
return false;
|
|
113691
|
+
await storage.deleteFirstSeenLedger?.(scope);
|
|
113692
|
+
return true;
|
|
113693
|
+
}
|
|
113694
|
+
function latestStillStored(storage, ledger) {
|
|
113695
|
+
return storage.findEntry({ scope: ledger.scope, at: ledger.latest.collectedAt })?.collectedAt === ledger.latest.collectedAt;
|
|
113696
|
+
}
|
|
113697
|
+
function isMarker(ledger) {
|
|
113698
|
+
return ledger.skipped === "too_large" || ledger.skipped === "unreadable";
|
|
113699
|
+
}
|
|
113700
|
+
function newerThan(retained, ledger) {
|
|
113701
|
+
const throughMs = Date.parse(ledger.through);
|
|
113702
|
+
return retained.filter((entry) => Date.parse(entry.collectedAt) > throughMs);
|
|
113703
|
+
}
|
|
113704
|
+
async function foldEntries(storage, scope, entries, fold) {
|
|
113705
|
+
let folded = 0;
|
|
113706
|
+
const failed = [];
|
|
113707
|
+
for (const entry of [...entries].reverse()) {
|
|
113708
|
+
const version4 = await readVersionData(storage, scope, entry.collectedAt);
|
|
113709
|
+
if (version4) {
|
|
113710
|
+
await fold.add(version4);
|
|
113711
|
+
folded += 1;
|
|
113712
|
+
} else {
|
|
113713
|
+
failed.push(entry);
|
|
113714
|
+
}
|
|
113715
|
+
await yieldToEventLoop();
|
|
113716
|
+
}
|
|
113717
|
+
return { folded, failed };
|
|
113718
|
+
}
|
|
113719
|
+
function retryOf(failed, now) {
|
|
113720
|
+
if (failed.length === 0)
|
|
113721
|
+
return null;
|
|
113722
|
+
return {
|
|
113723
|
+
versions: failed.slice(0, MAX_RETRY_VERSIONS).map((entry) => entry.collectedAt),
|
|
113724
|
+
attemptedAt: now.toISOString()
|
|
113725
|
+
};
|
|
113726
|
+
}
|
|
113727
|
+
async function rebuild(storage, scope, retained, budget, now) {
|
|
113728
|
+
if (retained.length === 0)
|
|
113729
|
+
return null;
|
|
113730
|
+
const selected = withinBudget(scope, retained, budget);
|
|
113731
|
+
const fold = new LedgerFold(null, scope);
|
|
113732
|
+
const { folded, failed } = await foldEntries(storage, scope, selected, fold);
|
|
113733
|
+
if (folded === 0) {
|
|
113734
|
+
return {
|
|
113735
|
+
version: 3,
|
|
113736
|
+
scope,
|
|
113737
|
+
baseline: null,
|
|
113738
|
+
current: null,
|
|
113739
|
+
latest: { collectedAt: retained[0].collectedAt, total: 0 },
|
|
113740
|
+
through: retained[0].collectedAt,
|
|
113741
|
+
skipped: selected.length === 0 ? "too_large" : "unreadable",
|
|
113742
|
+
records: {}
|
|
113743
|
+
};
|
|
113744
|
+
}
|
|
113745
|
+
const total = storage.countVersions(scope);
|
|
113746
|
+
return fold.finish({
|
|
113747
|
+
partial: folded < total,
|
|
113748
|
+
through: retained[0].collectedAt,
|
|
113749
|
+
retry: retryOf(failed, now)
|
|
113750
|
+
});
|
|
113751
|
+
}
|
|
113752
|
+
async function catchUp(storage, ledger, retained, budget, now) {
|
|
113753
|
+
const newer = newerThan(retained, ledger);
|
|
113754
|
+
const selected = withinBudget(ledger.scope, newer, budget);
|
|
113755
|
+
const pending = (ledger.retry?.versions ?? []).filter((version4) => retained.some((entry) => entry.collectedAt === version4));
|
|
113756
|
+
const due = ledger.retry !== void 0 && pending.length > 0 && now.getTime() - Date.parse(ledger.retry.attemptedAt) >= RETRY_UNREADABLE_MS;
|
|
113757
|
+
const retryEntries = due ? withinBudget(ledger.scope, retained.filter((entry) => pending.includes(entry.collectedAt)), budget) : [];
|
|
113758
|
+
const forgotten = pending.length !== (ledger.retry?.versions.length ?? 0);
|
|
113759
|
+
if (selected.length === 0 && retryEntries.length === 0 && !forgotten) {
|
|
113760
|
+
return ledger;
|
|
113761
|
+
}
|
|
113762
|
+
const fold = new LedgerFold(ledger);
|
|
113763
|
+
const failedNew = selected.length > 0 ? (await foldEntries(storage, ledger.scope, selected, fold)).failed : [];
|
|
113764
|
+
const failedRetry = retryEntries.length > 0 ? (await foldEntries(storage, ledger.scope, retryEntries, fold)).failed : [];
|
|
113765
|
+
const stillFailing = due ? failedRetry.map((entry) => entry.collectedAt) : pending;
|
|
113766
|
+
const versions = [
|
|
113767
|
+
...stillFailing,
|
|
113768
|
+
...failedNew.map((entry) => entry.collectedAt)
|
|
113769
|
+
].slice(0, MAX_RETRY_VERSIONS);
|
|
113770
|
+
const attempted = due || failedNew.length > 0;
|
|
113771
|
+
const retry = versions.length === 0 ? null : {
|
|
113772
|
+
versions,
|
|
113773
|
+
attemptedAt: attempted ? now.toISOString() : ledger.retry.attemptedAt
|
|
113774
|
+
};
|
|
113775
|
+
const beyond = storage.listVersions(ledger.scope, {
|
|
113776
|
+
limit: 1,
|
|
113777
|
+
offset: retained.length
|
|
113778
|
+
})[0];
|
|
113779
|
+
const windowCut = beyond !== void 0 && Date.parse(beyond.collectedAt) > Date.parse(ledger.through);
|
|
113780
|
+
return await fold.finish({
|
|
113781
|
+
partial: windowCut || selected.length < newer.length,
|
|
113782
|
+
through: selected.length > 0 ? retained[0].collectedAt : ledger.through,
|
|
113783
|
+
retry
|
|
113784
|
+
}) ?? ledger;
|
|
113785
|
+
}
|
|
113786
|
+
async function recordStoredVersion(storage, version4) {
|
|
113787
|
+
if (!storage.readFirstSeenLedger || !storage.writeFirstSeenLedger)
|
|
113788
|
+
return;
|
|
113789
|
+
try {
|
|
113790
|
+
await withScopeLock(version4.scope, async () => {
|
|
113791
|
+
const retained = retainedVersions(storage, version4.scope);
|
|
113792
|
+
let existing = await readStoredLedger(storage, version4.scope);
|
|
113793
|
+
if (existing && !latestStillStored(storage, existing)) {
|
|
113794
|
+
await storage.deleteFirstSeenLedger?.(version4.scope);
|
|
113795
|
+
existing = null;
|
|
113796
|
+
}
|
|
113797
|
+
const others = retained.filter((entry) => entry.collectedAt !== version4.collectedAt);
|
|
113798
|
+
let through = version4.collectedAt;
|
|
113799
|
+
if (existing) {
|
|
113800
|
+
if (isMarker(existing))
|
|
113801
|
+
return;
|
|
113802
|
+
const throughMs = Date.parse(existing.through);
|
|
113803
|
+
const unfolded = others.some((entry) => Date.parse(entry.collectedAt) > throughMs);
|
|
113804
|
+
through = unfolded || Date.parse(version4.collectedAt) < throughMs ? existing.through : version4.collectedAt;
|
|
113805
|
+
} else if (others.length > 0) {
|
|
113806
|
+
return;
|
|
113807
|
+
}
|
|
113808
|
+
const fold = new LedgerFold(existing, version4.scope);
|
|
113809
|
+
await fold.add(version4);
|
|
113810
|
+
const next = await fold.finish({ through });
|
|
113811
|
+
if (!next)
|
|
113812
|
+
return;
|
|
113813
|
+
await storage.writeFirstSeenLedger(version4.scope, next);
|
|
113814
|
+
await dropIfScopeEmpty(storage, version4.scope);
|
|
113815
|
+
});
|
|
113816
|
+
} catch {
|
|
113817
|
+
}
|
|
113818
|
+
}
|
|
113819
|
+
async function ensureScopeLedger(storage, scope, options = {}) {
|
|
113820
|
+
const budget = options.byteBudget ?? REBUILD_BYTE_BUDGET;
|
|
113821
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
113822
|
+
return withScopeLock(scope, async () => {
|
|
113823
|
+
try {
|
|
113824
|
+
const retained = retainedVersions(storage, scope);
|
|
113825
|
+
if (retained.length === 0) {
|
|
113826
|
+
await storage.deleteFirstSeenLedger?.(scope);
|
|
113827
|
+
return null;
|
|
113828
|
+
}
|
|
113829
|
+
let existing = await readStoredLedger(storage, scope);
|
|
113830
|
+
if (existing && (!latestStillStored(storage, existing) || isMarker(existing) && newerThan(retained, existing).length > 0)) {
|
|
113831
|
+
existing = null;
|
|
113832
|
+
}
|
|
113833
|
+
const ledger = existing ? await catchUp(storage, existing, retained, budget, now) : await rebuild(storage, scope, retained, budget, now);
|
|
113834
|
+
if (ledger && ledger !== existing && storage.writeFirstSeenLedger) {
|
|
113835
|
+
try {
|
|
113836
|
+
await storage.writeFirstSeenLedger(scope, ledger);
|
|
113837
|
+
if (await dropIfScopeEmpty(storage, scope))
|
|
113838
|
+
return null;
|
|
113839
|
+
} catch {
|
|
113840
|
+
}
|
|
113841
|
+
}
|
|
113842
|
+
return ledger;
|
|
113843
|
+
} catch {
|
|
113844
|
+
return null;
|
|
113845
|
+
}
|
|
113846
|
+
});
|
|
113847
|
+
}
|
|
113848
|
+
|
|
113849
|
+
// ../core/dist/additions/summary.js
|
|
113850
|
+
var InvalidTimezoneError = class extends Error {
|
|
113851
|
+
};
|
|
113852
|
+
function createFormatter(timezone) {
|
|
113853
|
+
try {
|
|
113854
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
113855
|
+
timeZone: timezone,
|
|
113856
|
+
year: "numeric",
|
|
113857
|
+
month: "2-digit",
|
|
113858
|
+
day: "2-digit"
|
|
113859
|
+
});
|
|
113860
|
+
} catch {
|
|
113861
|
+
throw new InvalidTimezoneError(`Unknown timezone: ${timezone}`);
|
|
113862
|
+
}
|
|
113863
|
+
}
|
|
113864
|
+
function localDate(formatter, instant) {
|
|
113865
|
+
let year = "";
|
|
113866
|
+
let month = "";
|
|
113867
|
+
let day = "";
|
|
113868
|
+
for (const part of formatter.formatToParts(instant)) {
|
|
113869
|
+
if (part.type === "year")
|
|
113870
|
+
year = part.value;
|
|
113871
|
+
else if (part.type === "month")
|
|
113872
|
+
month = part.value;
|
|
113873
|
+
else if (part.type === "day")
|
|
113874
|
+
day = part.value;
|
|
113875
|
+
}
|
|
113876
|
+
return `${year}-${month}-${day}`;
|
|
113877
|
+
}
|
|
113878
|
+
function pad2(value) {
|
|
113879
|
+
return String(value).padStart(2, "0");
|
|
113880
|
+
}
|
|
113881
|
+
function buildDayRows(formatter, now, days) {
|
|
113882
|
+
const [year, month, day] = localDate(formatter, now).split("-").map(Number);
|
|
113883
|
+
const rows = [];
|
|
113884
|
+
for (let offset = days - 1; offset >= 0; offset -= 1) {
|
|
113885
|
+
const date5 = new Date(Date.UTC(year, month - 1, day - offset));
|
|
113886
|
+
rows.push({
|
|
113887
|
+
date: `${date5.getUTCFullYear()}-${pad2(date5.getUTCMonth() + 1)}-${pad2(date5.getUTCDate())}`,
|
|
113888
|
+
added: 0
|
|
113889
|
+
});
|
|
113890
|
+
}
|
|
113891
|
+
return rows;
|
|
113892
|
+
}
|
|
113893
|
+
function validateTimezone(timezone) {
|
|
113894
|
+
createFormatter(timezone);
|
|
113895
|
+
}
|
|
113896
|
+
async function summarizeAdditions(input) {
|
|
113897
|
+
const { timezone, days, now } = input;
|
|
113898
|
+
const formatter = createFormatter(timezone);
|
|
113899
|
+
const dayRows = buildDayRows(formatter, now, days);
|
|
113900
|
+
const dayIndex = new Map(dayRows.map((row, index) => [row.date, index]));
|
|
113901
|
+
const scopes = [];
|
|
113902
|
+
let total = 0;
|
|
113903
|
+
let trackedSince = null;
|
|
113904
|
+
let trackedSinceAt = Infinity;
|
|
113905
|
+
for await (const ledger of input.ledgers) {
|
|
113906
|
+
for (const firstSeen of listAddedTimestamps(ledger)) {
|
|
113907
|
+
const date5 = localDate(formatter, new Date(Date.parse(firstSeen)));
|
|
113908
|
+
const index = dayIndex.get(date5);
|
|
113909
|
+
if (index !== void 0)
|
|
113910
|
+
dayRows[index].added += 1;
|
|
113911
|
+
}
|
|
113912
|
+
total += ledger.latest.total;
|
|
113913
|
+
const scopeTrackedSince = ledger.skipped ? null : ledger.baseline;
|
|
113914
|
+
if (scopeTrackedSince !== null) {
|
|
113915
|
+
const baselineAt = Date.parse(scopeTrackedSince);
|
|
113916
|
+
if (baselineAt < trackedSinceAt) {
|
|
113917
|
+
trackedSinceAt = baselineAt;
|
|
113918
|
+
trackedSince = scopeTrackedSince;
|
|
113919
|
+
}
|
|
113920
|
+
}
|
|
113921
|
+
scopes.push({
|
|
113922
|
+
scope: ledger.scope,
|
|
113923
|
+
total: ledger.latest.total,
|
|
113924
|
+
trackedSince: scopeTrackedSince
|
|
113925
|
+
});
|
|
113926
|
+
}
|
|
113927
|
+
scopes.sort((a10, b10) => a10.scope.localeCompare(b10.scope));
|
|
113928
|
+
return { timezone, total, days: dayRows, trackedSince, scopes };
|
|
113929
|
+
}
|
|
113930
|
+
|
|
112985
113931
|
// ../core/dist/contracts/data.js
|
|
112986
113932
|
var IngestPersistedError = class extends Error {
|
|
112987
113933
|
relativePath;
|
|
@@ -113023,35 +113969,43 @@ function normalizeLimit(value) {
|
|
|
113023
113969
|
function normalizeOffset(value) {
|
|
113024
113970
|
return value ?? 0;
|
|
113025
113971
|
}
|
|
113026
|
-
function
|
|
113972
|
+
function isRecord5(value) {
|
|
113027
113973
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113028
113974
|
}
|
|
113029
113975
|
var VISIBILITY_PAGE_SIZE = 200;
|
|
113976
|
+
async function collectScopes(storage, scopePrefix, isVisible) {
|
|
113977
|
+
const scopes = [];
|
|
113978
|
+
for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
|
|
113979
|
+
const batch = storage.listScopes({
|
|
113980
|
+
scopePrefix,
|
|
113981
|
+
limit: VISIBILITY_PAGE_SIZE,
|
|
113982
|
+
offset: scan
|
|
113983
|
+
});
|
|
113984
|
+
for (const summary of batch.scopes) {
|
|
113985
|
+
if (!isVisible) {
|
|
113986
|
+
scopes.push(summary);
|
|
113987
|
+
continue;
|
|
113988
|
+
}
|
|
113989
|
+
const latest = storage.findEntry({
|
|
113990
|
+
scope: summary.scope,
|
|
113991
|
+
at: summary.latestCollectedAt
|
|
113992
|
+
});
|
|
113993
|
+
if (!latest || await isVisible(summary.scope, latest)) {
|
|
113994
|
+
scopes.push(summary);
|
|
113995
|
+
}
|
|
113996
|
+
}
|
|
113997
|
+
if (batch.scopes.length < VISIBILITY_PAGE_SIZE)
|
|
113998
|
+
break;
|
|
113999
|
+
}
|
|
114000
|
+
return scopes;
|
|
114001
|
+
}
|
|
113030
114002
|
async function listDataScopesContract(input) {
|
|
113031
114003
|
const limit = normalizeLimit(input.limit);
|
|
113032
114004
|
const offset = normalizeOffset(input.offset);
|
|
113033
114005
|
let page;
|
|
113034
114006
|
let total;
|
|
113035
114007
|
if (input.isVisible) {
|
|
113036
|
-
const visible =
|
|
113037
|
-
for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
|
|
113038
|
-
const batch = input.storage.listScopes({
|
|
113039
|
-
scopePrefix: input.scopePrefix,
|
|
113040
|
-
limit: VISIBILITY_PAGE_SIZE,
|
|
113041
|
-
offset: scan
|
|
113042
|
-
});
|
|
113043
|
-
for (const summary of batch.scopes) {
|
|
113044
|
-
const latest = input.storage.findEntry({
|
|
113045
|
-
scope: summary.scope,
|
|
113046
|
-
at: summary.latestCollectedAt
|
|
113047
|
-
});
|
|
113048
|
-
if (!latest || await input.isVisible(summary.scope, latest)) {
|
|
113049
|
-
visible.push(summary);
|
|
113050
|
-
}
|
|
113051
|
-
}
|
|
113052
|
-
if (batch.scopes.length < VISIBILITY_PAGE_SIZE)
|
|
113053
|
-
break;
|
|
113054
|
-
}
|
|
114008
|
+
const visible = await collectScopes(input.storage, input.scopePrefix, input.isVisible);
|
|
113055
114009
|
total = visible.length;
|
|
113056
114010
|
page = visible.slice(offset, offset + limit);
|
|
113057
114011
|
} else {
|
|
@@ -113133,6 +114087,42 @@ async function listDataVersionsContract(input) {
|
|
|
113133
114087
|
}
|
|
113134
114088
|
};
|
|
113135
114089
|
}
|
|
114090
|
+
function invalidQuery(message) {
|
|
114091
|
+
return {
|
|
114092
|
+
ok: false,
|
|
114093
|
+
status: 400,
|
|
114094
|
+
body: { error: "INVALID_QUERY", message }
|
|
114095
|
+
};
|
|
114096
|
+
}
|
|
114097
|
+
async function summarizeDataAdditionsContract(input) {
|
|
114098
|
+
if (!Number.isInteger(input.days) || input.days < 1 || input.days > 31) {
|
|
114099
|
+
return invalidQuery("days must be an integer between 1 and 31");
|
|
114100
|
+
}
|
|
114101
|
+
try {
|
|
114102
|
+
validateTimezone(input.timezone);
|
|
114103
|
+
} catch (err2) {
|
|
114104
|
+
if (err2 instanceof InvalidTimezoneError) {
|
|
114105
|
+
return invalidQuery("Unknown timezone");
|
|
114106
|
+
}
|
|
114107
|
+
throw err2;
|
|
114108
|
+
}
|
|
114109
|
+
const scopes = await collectScopes(input.storage, void 0, input.isVisible);
|
|
114110
|
+
async function* ledgers() {
|
|
114111
|
+
for (const summary of scopes) {
|
|
114112
|
+
const ledger = await ensureScopeLedger(input.storage, summary.scope, {
|
|
114113
|
+
now: input.now
|
|
114114
|
+
});
|
|
114115
|
+
if (ledger)
|
|
114116
|
+
yield ledger;
|
|
114117
|
+
}
|
|
114118
|
+
}
|
|
114119
|
+
return summarizeAdditions({
|
|
114120
|
+
ledgers: ledgers(),
|
|
114121
|
+
timezone: input.timezone,
|
|
114122
|
+
days: input.days,
|
|
114123
|
+
now: input.now
|
|
114124
|
+
});
|
|
114125
|
+
}
|
|
113136
114126
|
async function readDataContract(input) {
|
|
113137
114127
|
const scopeResult = parseDataScopeContract(input.scopeParam);
|
|
113138
114128
|
if (!scopeResult.ok)
|
|
@@ -113162,7 +114152,7 @@ async function ingestDataContract(input) {
|
|
|
113162
114152
|
const scopeResult = parseDataScopeContract(input.scopeParam);
|
|
113163
114153
|
if (!scopeResult.ok)
|
|
113164
114154
|
return scopeResult;
|
|
113165
|
-
if (!
|
|
114155
|
+
if (!isRecord5(input.body)) {
|
|
113166
114156
|
return {
|
|
113167
114157
|
ok: false,
|
|
113168
114158
|
status: 400,
|
|
@@ -113207,6 +114197,11 @@ async function ingestDataContract(input) {
|
|
|
113207
114197
|
sizeBytes: writeResult.sizeBytes,
|
|
113208
114198
|
afterTombstoneVersion: input.afterTombstoneVersion ?? null
|
|
113209
114199
|
});
|
|
114200
|
+
await recordStoredVersion(input.storage, {
|
|
114201
|
+
scope: scopeResult.scope,
|
|
114202
|
+
collectedAt: input.collectedAt,
|
|
114203
|
+
data: envelope.data
|
|
114204
|
+
});
|
|
113210
114205
|
return {
|
|
113211
114206
|
ok: true,
|
|
113212
114207
|
scope: scopeResult.scope,
|
|
@@ -113246,7 +114241,7 @@ async function ingestBinaryDataContract(input) {
|
|
|
113246
114241
|
}
|
|
113247
114242
|
};
|
|
113248
114243
|
}
|
|
113249
|
-
if (
|
|
114244
|
+
if (isRecord5(input.metadata) && (hasReservedWriterKey(input.metadata) || hasReservedLineageKey(input.metadata))) {
|
|
113250
114245
|
return {
|
|
113251
114246
|
ok: false,
|
|
113252
114247
|
status: 400,
|
|
@@ -113279,6 +114274,11 @@ async function ingestBinaryDataContract(input) {
|
|
|
113279
114274
|
sizeBytes: input.bytes.length,
|
|
113280
114275
|
afterTombstoneVersion: input.afterTombstoneVersion ?? null
|
|
113281
114276
|
});
|
|
114277
|
+
await recordStoredVersion(input.storage, {
|
|
114278
|
+
scope: scopeResult.scope,
|
|
114279
|
+
collectedAt: input.collectedAt,
|
|
114280
|
+
data: envelope.data
|
|
114281
|
+
});
|
|
113282
114282
|
return {
|
|
113283
114283
|
ok: true,
|
|
113284
114284
|
scope: scopeResult.scope,
|
|
@@ -114138,6 +115138,16 @@ function isExpired(expiresAt, nowMs2) {
|
|
|
114138
115138
|
// ../core/dist/mcp/connection-api.js
|
|
114139
115139
|
var TOKEN_BYTES = 32;
|
|
114140
115140
|
var OAUTH_AUTHORIZATION_TTL_MS = 10 * 60 * 1e3;
|
|
115141
|
+
var DEFAULT_MCP_GRANT_TTL_SECONDS = 0;
|
|
115142
|
+
function mcpGrantDefaultExpiry(ttlSeconds, now) {
|
|
115143
|
+
const ttl = ttlSeconds ?? DEFAULT_MCP_GRANT_TTL_SECONDS;
|
|
115144
|
+
if (!Number.isFinite(ttl) || ttl < 0) {
|
|
115145
|
+
throw new RangeError(`mcpGrantTtlSeconds must be a non-negative number, got ${ttlSeconds}`);
|
|
115146
|
+
}
|
|
115147
|
+
if (ttl === 0)
|
|
115148
|
+
return void 0;
|
|
115149
|
+
return Math.floor(nowMs(now) / 1e3) + Math.floor(ttl);
|
|
115150
|
+
}
|
|
114141
115151
|
var MCP_SCOPE_REQUEST_TOKEN_HEADER = "X-Vana-Scope-Request-Token";
|
|
114142
115152
|
var MCP_SCOPE_REQUEST_NOT_FOUND = "MCP_SCOPE_REQUEST_NOT_FOUND";
|
|
114143
115153
|
var MCP_SCOPE_REQUEST_READ_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -114355,6 +115365,7 @@ async function approveMcpScopeAccessRequest(input, options) {
|
|
|
114355
115365
|
const approvedScopes = parseApprovedScopes(input.scopes, pending);
|
|
114356
115366
|
const live = await readLiveGrantState(connection, options.gateway);
|
|
114357
115367
|
const grantedScopes = sortedUnique([...live.scopes, ...approvedScopes]);
|
|
115368
|
+
const expiresAt = live.expiry.kind === "inherit" ? live.expiry.expiresAt : mcpGrantDefaultExpiry(options.grantTtlSeconds, options.now);
|
|
114358
115369
|
let grantResult;
|
|
114359
115370
|
try {
|
|
114360
115371
|
grantResult = await createGrantContract({
|
|
@@ -114365,7 +115376,7 @@ async function approveMcpScopeAccessRequest(input, options) {
|
|
|
114365
115376
|
granteeAddress: connection.granteeAddress,
|
|
114366
115377
|
scopes: grantedScopes,
|
|
114367
115378
|
grantVersion: live.nextGrantVersion,
|
|
114368
|
-
...
|
|
115379
|
+
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
114369
115380
|
}
|
|
114370
115381
|
});
|
|
114371
115382
|
} catch (err2) {
|
|
@@ -114463,6 +115474,8 @@ async function readLiveGrantState(connection, gateway) {
|
|
|
114463
115474
|
const revoked = /* @__PURE__ */ new Set();
|
|
114464
115475
|
const scopes = /* @__PURE__ */ new Set();
|
|
114465
115476
|
let maxVersion = 0n;
|
|
115477
|
+
let anyLive = false;
|
|
115478
|
+
let anyPerpetual = false;
|
|
114466
115479
|
let expiresAt;
|
|
114467
115480
|
for (const grantId of grantIds) {
|
|
114468
115481
|
let live;
|
|
@@ -114482,8 +115495,11 @@ async function readLiveGrantState(connection, gateway) {
|
|
|
114482
115495
|
}
|
|
114483
115496
|
for (const scope of live.scopes)
|
|
114484
115497
|
scopes.add(scope);
|
|
115498
|
+
anyLive = true;
|
|
114485
115499
|
const liveExpiry = parseExpirySeconds(live.expiresAt);
|
|
114486
|
-
if (liveExpiry
|
|
115500
|
+
if (liveExpiry === void 0) {
|
|
115501
|
+
anyPerpetual = true;
|
|
115502
|
+
} else {
|
|
114487
115503
|
expiresAt = expiresAt === void 0 ? liveExpiry : Math.max(expiresAt, liveExpiry);
|
|
114488
115504
|
}
|
|
114489
115505
|
}
|
|
@@ -114496,7 +115512,7 @@ async function readLiveGrantState(connection, gateway) {
|
|
|
114496
115512
|
return {
|
|
114497
115513
|
scopes: sortedUnique(scopes),
|
|
114498
115514
|
nextGrantVersion: (maxVersion + 1n).toString(),
|
|
114499
|
-
|
|
115515
|
+
expiry: !anyLive ? { kind: "none" } : anyPerpetual ? { kind: "inherit" } : { kind: "inherit", expiresAt }
|
|
114500
115516
|
};
|
|
114501
115517
|
}
|
|
114502
115518
|
function parseUint(value) {
|
|
@@ -114511,8 +115527,8 @@ function parseExpirySeconds(value) {
|
|
|
114511
115527
|
const seconds = Number(value);
|
|
114512
115528
|
return seconds > 0 ? seconds : void 0;
|
|
114513
115529
|
}
|
|
114514
|
-
const
|
|
114515
|
-
return Number.isFinite(
|
|
115530
|
+
const ms4 = Date.parse(value);
|
|
115531
|
+
return Number.isFinite(ms4) ? Math.floor(ms4 / 1e3) : void 0;
|
|
114516
115532
|
}
|
|
114517
115533
|
function sortedUnique(values) {
|
|
114518
115534
|
return Array.from(new Set(values)).sort();
|
|
@@ -114693,6 +115709,7 @@ async function approveMcpOAuthAuthorizationWithScopes(input, options) {
|
|
|
114693
115709
|
}
|
|
114694
115710
|
throw err2;
|
|
114695
115711
|
}
|
|
115712
|
+
const expiresAt = input.expiresAt ?? mcpGrantDefaultExpiry(options.grantTtlSeconds, options.now);
|
|
114696
115713
|
const grantResult = await createGrantContract({
|
|
114697
115714
|
gateway: options.gateway,
|
|
114698
115715
|
serverOwner: options.serverOwner,
|
|
@@ -114700,7 +115717,7 @@ async function approveMcpOAuthAuthorizationWithScopes(input, options) {
|
|
|
114700
115717
|
body: {
|
|
114701
115718
|
granteeAddress: connection.granteeAddress,
|
|
114702
115719
|
scopes: input.scopes,
|
|
114703
|
-
...
|
|
115720
|
+
...expiresAt !== void 0 ? { expiresAt } : {},
|
|
114704
115721
|
...input.nonce !== void 0 ? { nonce: input.nonce } : {}
|
|
114705
115722
|
}
|
|
114706
115723
|
});
|
|
@@ -115559,8 +116576,8 @@ async function buildChallenge(input) {
|
|
|
115559
116576
|
}
|
|
115560
116577
|
function base64decode(input) {
|
|
115561
116578
|
let s10 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
115562
|
-
const
|
|
115563
|
-
s10 += "=".repeat(
|
|
116579
|
+
const pad3 = (4 - s10.length % 4) % 4;
|
|
116580
|
+
s10 += "=".repeat(pad3);
|
|
115564
116581
|
const binString = atob(s10);
|
|
115565
116582
|
const bytes2 = Uint8Array.from(binString, (c10) => c10.codePointAt(0) ?? 0);
|
|
115566
116583
|
return new TextDecoder().decode(bytes2);
|
|
@@ -116181,6 +117198,23 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
116181
117198
|
});
|
|
116182
117199
|
return jsonResponse(result.response);
|
|
116183
117200
|
}
|
|
117201
|
+
if (pathname === "/additions") {
|
|
117202
|
+
if (request2.method !== "GET")
|
|
117203
|
+
return methodNotAllowed();
|
|
117204
|
+
await deps.auth.authorizeOwner(request2);
|
|
117205
|
+
const daysRaw = url2.searchParams.get("days");
|
|
117206
|
+
const result = await summarizeDataAdditionsContract({
|
|
117207
|
+
storage: deps.storage,
|
|
117208
|
+
isVisible: discoveryVisibility(deps),
|
|
117209
|
+
timezone: url2.searchParams.get("tz") ?? "UTC",
|
|
117210
|
+
// Digits only: Number() would also accept "", "1e1", "0x7" and " 7".
|
|
117211
|
+
days: daysRaw === null ? 7 : /^\d{1,3}$/.test(daysRaw) ? Number(daysRaw) : Number.NaN,
|
|
117212
|
+
now: (deps.now ?? (() => /* @__PURE__ */ new Date()))()
|
|
117213
|
+
});
|
|
117214
|
+
if ("ok" in result)
|
|
117215
|
+
return contractErrorResponse(result);
|
|
117216
|
+
return jsonResponse(result);
|
|
117217
|
+
}
|
|
116184
117218
|
const parts = pathname.split("/").filter(Boolean);
|
|
116185
117219
|
if (parts.length === 2 && parts[1] === "versions") {
|
|
116186
117220
|
if (request2.method !== "GET")
|
|
@@ -117342,7 +118376,8 @@ function normalizeState(state) {
|
|
|
117342
118376
|
})),
|
|
117343
118377
|
envelopes: state.envelopes,
|
|
117344
118378
|
blockManifests: state.blockManifests ?? [],
|
|
117345
|
-
blockPayloads: state.blockPayloads ?? []
|
|
118379
|
+
blockPayloads: state.blockPayloads ?? [],
|
|
118380
|
+
...state.pendingLedgerDeletes?.length ? { pendingLedgerDeletes: state.pendingLedgerDeletes } : {}
|
|
117346
118381
|
};
|
|
117347
118382
|
}
|
|
117348
118383
|
function createIndexedDbFallbackDataFileStore(envelopes, blockManifests = /* @__PURE__ */ new Map(), blockPayloads = /* @__PURE__ */ new Map()) {
|
|
@@ -117567,6 +118602,18 @@ function createIndexedDbPsLitePersistence(options = {}) {
|
|
|
117567
118602
|
},
|
|
117568
118603
|
async write(state) {
|
|
117569
118604
|
await runIndexedDbTransaction(resolved, "readwrite", (store) => store.put(state, resolved.key));
|
|
118605
|
+
},
|
|
118606
|
+
// Side records live in the same object store under their own keys, which
|
|
118607
|
+
// a build that only knows `resolved.key` never reads.
|
|
118608
|
+
async readAux(name) {
|
|
118609
|
+
const value = await runIndexedDbTransaction(resolved, "readonly", (store) => store.get(`${resolved.key}:${name}`));
|
|
118610
|
+
return value ?? null;
|
|
118611
|
+
},
|
|
118612
|
+
async writeAux(name, value) {
|
|
118613
|
+
await runIndexedDbTransaction(resolved, "readwrite", (store) => store.put(value, `${resolved.key}:${name}`));
|
|
118614
|
+
},
|
|
118615
|
+
async deleteAux(name) {
|
|
118616
|
+
await runIndexedDbTransaction(resolved, "readwrite", (store) => store.delete(`${resolved.key}:${name}`));
|
|
117570
118617
|
}
|
|
117571
118618
|
};
|
|
117572
118619
|
}
|
|
@@ -117578,6 +118625,9 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117578
118625
|
]));
|
|
117579
118626
|
const fallbackBlockManifests = new Map((state.blockManifests ?? []).map(({ path, manifest }) => [path, manifest]));
|
|
117580
118627
|
const fallbackBlockPayloads = new Map((state.blockPayloads ?? []).map(({ path, block }) => [path, block]));
|
|
118628
|
+
const ledgerAux = (scope) => `first-seen:${scope}`;
|
|
118629
|
+
const firstSeenLedgers = /* @__PURE__ */ new Map();
|
|
118630
|
+
const pendingLedgerDeletes = new Set(state.pendingLedgerDeletes ?? []);
|
|
117581
118631
|
const fallbackStore = createIndexedDbFallbackDataFileStore(fallbackEnvelopes, fallbackBlockManifests, fallbackBlockPayloads);
|
|
117582
118632
|
const fileStore = dataFileStore ?? (adapter.kind !== "custom" && await isOpfsAvailable() ? await createOpfsPsLiteDataFileStore() : fallbackStore);
|
|
117583
118633
|
const capabilities = {
|
|
@@ -117591,7 +118641,8 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117591
118641
|
...state,
|
|
117592
118642
|
envelopes: fileStore.kind === "indexeddb" ? Array.from(fallbackEnvelopes.values()) : [],
|
|
117593
118643
|
blockManifests: Array.from(fallbackBlockManifests.entries()).map(([path, manifest]) => ({ path, manifest })),
|
|
117594
|
-
blockPayloads: Array.from(fallbackBlockPayloads.entries()).map(([path, block]) => ({ path, block }))
|
|
118644
|
+
blockPayloads: Array.from(fallbackBlockPayloads.entries()).map(([path, block]) => ({ path, block })),
|
|
118645
|
+
pendingLedgerDeletes: pendingLedgerDeletes.size > 0 ? Array.from(pendingLedgerDeletes) : void 0
|
|
117595
118646
|
};
|
|
117596
118647
|
const write = persistQueue.then(() => persistence.write(snapshot));
|
|
117597
118648
|
persistQueue = write.catch(() => void 0);
|
|
@@ -117869,33 +118920,55 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117869
118920
|
}
|
|
117870
118921
|
return updated;
|
|
117871
118922
|
},
|
|
117872
|
-
async
|
|
117873
|
-
|
|
117874
|
-
|
|
117875
|
-
|
|
117876
|
-
|
|
117877
|
-
|
|
117878
|
-
|
|
117879
|
-
|
|
117880
|
-
|
|
117881
|
-
|
|
117882
|
-
|
|
117883
|
-
|
|
117884
|
-
|
|
117885
|
-
|
|
117886
|
-
|
|
117887
|
-
|
|
117888
|
-
|
|
117889
|
-
|
|
117890
|
-
|
|
117891
|
-
|
|
117892
|
-
|
|
117893
|
-
|
|
117894
|
-
|
|
117895
|
-
]
|
|
117896
|
-
|
|
117897
|
-
|
|
117898
|
-
|
|
118923
|
+
async readFirstSeenLedger(scope) {
|
|
118924
|
+
if (!firstSeenLedgers.has(scope)) {
|
|
118925
|
+
const stored = await persistence.readAux?.(ledgerAux(scope)) ?? null;
|
|
118926
|
+
if (stored !== null)
|
|
118927
|
+
firstSeenLedgers.set(scope, stored);
|
|
118928
|
+
}
|
|
118929
|
+
return structuredClone(firstSeenLedgers.get(scope) ?? null);
|
|
118930
|
+
},
|
|
118931
|
+
async writeFirstSeenLedger(scope, ledger) {
|
|
118932
|
+
firstSeenLedgers.set(scope, structuredClone(ledger));
|
|
118933
|
+
await persistence.writeAux?.(ledgerAux(scope), ledger);
|
|
118934
|
+
},
|
|
118935
|
+
async deleteFirstSeenLedger(scope) {
|
|
118936
|
+
firstSeenLedgers.delete(scope);
|
|
118937
|
+
await persistence.deleteAux?.(ledgerAux(scope));
|
|
118938
|
+
},
|
|
118939
|
+
// Deletions run under the scope's first-seen sidecar lock (a rebuild in
|
|
118940
|
+
// flight cannot write it back), and the sidecar goes with the scope's last
|
|
118941
|
+
// version, so no delete path leaves a stale ledger behind.
|
|
118942
|
+
deleteScope(scope) {
|
|
118943
|
+
return withScopeLock(scope, async () => {
|
|
118944
|
+
await dropLedger(scope);
|
|
118945
|
+
let deleted = 0;
|
|
118946
|
+
const deletedPaths = [];
|
|
118947
|
+
const deletedBlockTrees = [];
|
|
118948
|
+
state = {
|
|
118949
|
+
...state,
|
|
118950
|
+
entries: state.entries.filter((entry) => {
|
|
118951
|
+
if (entry.scope !== scope)
|
|
118952
|
+
return true;
|
|
118953
|
+
deleted += 1;
|
|
118954
|
+
deletedPaths.push(envelopePath(entry.scope, entry.collectedAt));
|
|
118955
|
+
deletedBlockTrees.push(blockTreePath(entry.scope, entry.collectedAt));
|
|
118956
|
+
return false;
|
|
118957
|
+
})
|
|
118958
|
+
};
|
|
118959
|
+
await Promise.all([
|
|
118960
|
+
...deletedPaths.flatMap((path) => [
|
|
118961
|
+
fileStore.deleteEnvelope(path),
|
|
118962
|
+
fallbackStore.deleteEnvelope(path)
|
|
118963
|
+
]),
|
|
118964
|
+
...deletedBlockTrees.flatMap((path) => [
|
|
118965
|
+
fileStore.deleteBlockTree?.(path),
|
|
118966
|
+
fallbackStore.deleteBlockTree?.(path)
|
|
118967
|
+
])
|
|
118968
|
+
].filter((promise2) => promise2 !== void 0));
|
|
118969
|
+
await persist();
|
|
118970
|
+
return deleted;
|
|
118971
|
+
});
|
|
117899
118972
|
},
|
|
117900
118973
|
async deleteVersion(scope, collectedAt) {
|
|
117901
118974
|
const entry = state.entries.find((e10) => e10.scope === scope && e10.collectedAt === collectedAt);
|
|
@@ -117910,7 +118983,35 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117910
118983
|
return removeEntry(entry);
|
|
117911
118984
|
}
|
|
117912
118985
|
};
|
|
118986
|
+
async function dropLedger(scope) {
|
|
118987
|
+
const attempt = async (name) => {
|
|
118988
|
+
try {
|
|
118989
|
+
await storagePort.deleteFirstSeenLedger(name);
|
|
118990
|
+
return true;
|
|
118991
|
+
} catch {
|
|
118992
|
+
return false;
|
|
118993
|
+
}
|
|
118994
|
+
};
|
|
118995
|
+
const before = pendingLedgerDeletes.size;
|
|
118996
|
+
if (await attempt(scope))
|
|
118997
|
+
pendingLedgerDeletes.delete(scope);
|
|
118998
|
+
else
|
|
118999
|
+
pendingLedgerDeletes.add(scope);
|
|
119000
|
+
for (const other of [...pendingLedgerDeletes]) {
|
|
119001
|
+
if (other === scope)
|
|
119002
|
+
continue;
|
|
119003
|
+
const stillStored = state.entries.some((e10) => e10.scope === other);
|
|
119004
|
+
if (stillStored || await attempt(other))
|
|
119005
|
+
pendingLedgerDeletes.delete(other);
|
|
119006
|
+
}
|
|
119007
|
+
if (pendingLedgerDeletes.size !== before) {
|
|
119008
|
+
await persist().catch(() => void 0);
|
|
119009
|
+
}
|
|
119010
|
+
}
|
|
117913
119011
|
async function removeEntry(entry) {
|
|
119012
|
+
return withScopeLock(entry.scope, () => removeEntryLocked(entry));
|
|
119013
|
+
}
|
|
119014
|
+
async function removeEntryLocked(entry) {
|
|
117914
119015
|
const blobPath = envelopePath(entry.scope, entry.collectedAt);
|
|
117915
119016
|
await Promise.all([
|
|
117916
119017
|
fileStore.deleteEnvelope(blobPath),
|
|
@@ -117923,6 +119024,9 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117923
119024
|
entries: state.entries.filter((e10) => e10 !== entry)
|
|
117924
119025
|
};
|
|
117925
119026
|
await persist();
|
|
119027
|
+
if (!state.entries.some((e10) => e10.scope === entry.scope)) {
|
|
119028
|
+
await dropLedger(entry.scope);
|
|
119029
|
+
}
|
|
117926
119030
|
return true;
|
|
117927
119031
|
}
|
|
117928
119032
|
if (fileStore.readEnvelopePreview) {
|
|
@@ -117936,6 +119040,20 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117936
119040
|
return preview;
|
|
117937
119041
|
};
|
|
117938
119042
|
}
|
|
119043
|
+
if (pendingLedgerDeletes.size > 0) {
|
|
119044
|
+
for (const scope of [...pendingLedgerDeletes]) {
|
|
119045
|
+
if (state.entries.some((e10) => e10.scope === scope)) {
|
|
119046
|
+
pendingLedgerDeletes.delete(scope);
|
|
119047
|
+
continue;
|
|
119048
|
+
}
|
|
119049
|
+
try {
|
|
119050
|
+
await storagePort.deleteFirstSeenLedger(scope);
|
|
119051
|
+
pendingLedgerDeletes.delete(scope);
|
|
119052
|
+
} catch {
|
|
119053
|
+
}
|
|
119054
|
+
}
|
|
119055
|
+
await persist().catch(() => void 0);
|
|
119056
|
+
}
|
|
117939
119057
|
return storagePort;
|
|
117940
119058
|
}
|
|
117941
119059
|
async function readPreviewFromFileStore(store, path, maxBytes) {
|
|
@@ -118324,7 +119442,7 @@ var KEYS_BY_TYPE = {
|
|
|
118324
119442
|
boolean: ["name", "type", "required"],
|
|
118325
119443
|
enum: ["name", "type", "required", "values"]
|
|
118326
119444
|
};
|
|
118327
|
-
function
|
|
119445
|
+
function isRecord6(value) {
|
|
118328
119446
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
118329
119447
|
}
|
|
118330
119448
|
function invalid(message, details) {
|
|
@@ -118385,7 +119503,7 @@ function parseEnumValues(value, index) {
|
|
|
118385
119503
|
return values;
|
|
118386
119504
|
}
|
|
118387
119505
|
function parseField(value, index) {
|
|
118388
|
-
if (!
|
|
119506
|
+
if (!isRecord6(value)) {
|
|
118389
119507
|
invalid(`answerShape.fields[${index}] must be an object`, { index });
|
|
118390
119508
|
}
|
|
118391
119509
|
const name = parseFieldName(value.name, index);
|
|
@@ -118441,7 +119559,7 @@ function parseField(value, index) {
|
|
|
118441
119559
|
function parseAnswerShapeInput(value) {
|
|
118442
119560
|
if (value === void 0 || value === null)
|
|
118443
119561
|
return null;
|
|
118444
|
-
if (!
|
|
119562
|
+
if (!isRecord6(value)) {
|
|
118445
119563
|
invalid("answerShape must be an object with a fields array", {});
|
|
118446
119564
|
}
|
|
118447
119565
|
for (const key of Object.keys(value)) {
|
|
@@ -118654,7 +119772,7 @@ var MAX_QUESTION_CHARS = 8e3;
|
|
|
118654
119772
|
var MAX_MODEL_CHARS = 128;
|
|
118655
119773
|
var MAX_ECHOED_SCOPE_CHARS = 128;
|
|
118656
119774
|
var MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
|
|
118657
|
-
function
|
|
119775
|
+
function isRecord7(value) {
|
|
118658
119776
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
118659
119777
|
}
|
|
118660
119778
|
function parseScope(value, field2) {
|
|
@@ -118670,7 +119788,7 @@ function parseScope(value, field2) {
|
|
|
118670
119788
|
return parsed.scope;
|
|
118671
119789
|
}
|
|
118672
119790
|
function parseQuestionInput(body) {
|
|
118673
|
-
if (!
|
|
119791
|
+
if (!isRecord7(body)) {
|
|
118674
119792
|
throw new DerivativeQuestionInvalidError("Body must be a JSON object");
|
|
118675
119793
|
}
|
|
118676
119794
|
const derivedScope = parseScope(body.derivedScope, "derivedScope");
|
|
@@ -118806,11 +119924,11 @@ var TIMESTAMP_KEYS = [
|
|
|
118806
119924
|
"published_at"
|
|
118807
119925
|
];
|
|
118808
119926
|
var RESERVED_KEYS = /* @__PURE__ */ new Set(["$lineage", "$writtenBy", "$binary"]);
|
|
118809
|
-
function
|
|
119927
|
+
function isRecord8(value) {
|
|
118810
119928
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
118811
119929
|
}
|
|
118812
119930
|
function timestampOf(item) {
|
|
118813
|
-
if (!
|
|
119931
|
+
if (!isRecord8(item))
|
|
118814
119932
|
return null;
|
|
118815
119933
|
for (const key of TIMESTAMP_KEYS) {
|
|
118816
119934
|
const value = item[key];
|
|
@@ -118851,7 +119969,7 @@ function trimSourceData(data, options = {}) {
|
|
|
118851
119969
|
total = 0;
|
|
118852
119970
|
if (Array.isArray(data))
|
|
118853
119971
|
return trimArray(data, limit2);
|
|
118854
|
-
if (
|
|
119972
|
+
if (isRecord8(data)) {
|
|
118855
119973
|
const stamped = "$lineage" in data;
|
|
118856
119974
|
const out = {};
|
|
118857
119975
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -118965,7 +120083,7 @@ function parseAnswer(content) {
|
|
|
118965
120083
|
for (const candidate of jsonFramings(content)) {
|
|
118966
120084
|
try {
|
|
118967
120085
|
const parsed = JSON.parse(candidate);
|
|
118968
|
-
if (
|
|
120086
|
+
if (isRecord8(parsed) && typeof parsed.answer === "string") {
|
|
118969
120087
|
return {
|
|
118970
120088
|
answer: parsed.answer,
|
|
118971
120089
|
evidence: typeof parsed.evidence === "string" ? parsed.evidence : null
|
|
@@ -118985,10 +120103,10 @@ function parseShapedAnswer(content) {
|
|
|
118985
120103
|
} catch {
|
|
118986
120104
|
continue;
|
|
118987
120105
|
}
|
|
118988
|
-
if (!
|
|
120106
|
+
if (!isRecord8(parsed))
|
|
118989
120107
|
continue;
|
|
118990
120108
|
const evidence = typeof parsed.evidence === "string" ? parsed.evidence : null;
|
|
118991
|
-
if (
|
|
120109
|
+
if (isRecord8(parsed.answer)) {
|
|
118992
120110
|
found.push({ answer: parsed.answer, evidence });
|
|
118993
120111
|
}
|
|
118994
120112
|
found.push({ answer: parsed, evidence });
|
|
@@ -119021,11 +120139,11 @@ var InferenceRequestError = class extends Error {
|
|
|
119021
120139
|
this.retryable = options.retryable;
|
|
119022
120140
|
}
|
|
119023
120141
|
};
|
|
119024
|
-
function
|
|
120142
|
+
function isRecord9(value) {
|
|
119025
120143
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
119026
120144
|
}
|
|
119027
120145
|
function readUsage(value) {
|
|
119028
|
-
if (!
|
|
120146
|
+
if (!isRecord9(value))
|
|
119029
120147
|
return void 0;
|
|
119030
120148
|
const num2 = (v10) => typeof v10 === "number" ? v10 : void 0;
|
|
119031
120149
|
const usage = {
|
|
@@ -119036,10 +120154,10 @@ function readUsage(value) {
|
|
|
119036
120154
|
return usage;
|
|
119037
120155
|
}
|
|
119038
120156
|
function readContent(body) {
|
|
119039
|
-
if (!
|
|
120157
|
+
if (!isRecord9(body) || !Array.isArray(body.choices))
|
|
119040
120158
|
return null;
|
|
119041
120159
|
const first = body.choices[0];
|
|
119042
|
-
if (!
|
|
120160
|
+
if (!isRecord9(first) || !isRecord9(first.message))
|
|
119043
120161
|
return null;
|
|
119044
120162
|
const index = typeof first.index === "number" ? first.index : 0;
|
|
119045
120163
|
const field2 = `choices.${index}.message.content`;
|
|
@@ -119048,7 +120166,7 @@ function readContent(body) {
|
|
|
119048
120166
|
if (typeof content === "string")
|
|
119049
120167
|
return { content, field: field2, id: id2 };
|
|
119050
120168
|
if (Array.isArray(content)) {
|
|
119051
|
-
const text = content.map((part) =>
|
|
120169
|
+
const text = content.map((part) => isRecord9(part) && typeof part.text === "string" ? part.text : "").join("");
|
|
119052
120170
|
return { content: text, field: field2, id: id2 };
|
|
119053
120171
|
}
|
|
119054
120172
|
return null;
|
|
@@ -119056,7 +120174,7 @@ function readContent(body) {
|
|
|
119056
120174
|
async function readErrorType(response) {
|
|
119057
120175
|
try {
|
|
119058
120176
|
const body = await response.json();
|
|
119059
|
-
if (
|
|
120177
|
+
if (isRecord9(body) && isRecord9(body.error)) {
|
|
119060
120178
|
return typeof body.error.type === "string" ? body.error.type : null;
|
|
119061
120179
|
}
|
|
119062
120180
|
} catch {
|
|
@@ -119164,7 +120282,7 @@ function createOpenAiCompatibleInferenceProvider(options = {}) {
|
|
|
119164
120282
|
ok: true,
|
|
119165
120283
|
result: {
|
|
119166
120284
|
content,
|
|
119167
|
-
usage: readUsage(
|
|
120285
|
+
usage: readUsage(isRecord9(parsed) ? parsed.usage : void 0),
|
|
119168
120286
|
...receiptId ? { receiptId } : {},
|
|
119169
120287
|
...aciIdentity ? { aciIdentity } : {}
|
|
119170
120288
|
}
|
|
@@ -119197,7 +120315,7 @@ function isRetryableInferenceError(err2) {
|
|
|
119197
120315
|
}
|
|
119198
120316
|
async function withRetries(deps, attempt, retryable) {
|
|
119199
120317
|
const delays = deps.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
|
|
119200
|
-
const sleep2 = deps.sleep ?? ((
|
|
120318
|
+
const sleep2 = deps.sleep ?? ((ms4) => new Promise((r10) => setTimeout(r10, ms4)));
|
|
119201
120319
|
for (let index = 0; ; index += 1) {
|
|
119202
120320
|
try {
|
|
119203
120321
|
return await attempt();
|
|
@@ -119575,7 +120693,7 @@ function isTransientFailureOutcome(outcome) {
|
|
|
119575
120693
|
return shaped.status === "failed" && shaped.registration?.errorCode === "inference_unavailable";
|
|
119576
120694
|
}
|
|
119577
120695
|
var defaultTimers = {
|
|
119578
|
-
setTimeout: (callback,
|
|
120696
|
+
setTimeout: (callback, ms4) => setTimeout(callback, ms4),
|
|
119579
120697
|
clearTimeout: (handle) => clearTimeout(handle)
|
|
119580
120698
|
};
|
|
119581
120699
|
function createRecomputeScheduler(options) {
|
|
@@ -120270,25 +121388,25 @@ var E2eeAttestationError = class extends Error {
|
|
|
120270
121388
|
this.name = "E2eeAttestationError";
|
|
120271
121389
|
}
|
|
120272
121390
|
};
|
|
120273
|
-
function
|
|
121391
|
+
function isRecord10(value) {
|
|
120274
121392
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
120275
121393
|
}
|
|
120276
|
-
async function
|
|
121394
|
+
async function sha256Hex3(bytes2) {
|
|
120277
121395
|
const buffer = new ArrayBuffer(bytes2.byteLength);
|
|
120278
121396
|
new Uint8Array(buffer).set(bytes2);
|
|
120279
121397
|
const digest2 = await globalThis.crypto.subtle.digest("SHA-256", buffer);
|
|
120280
121398
|
return bytesToHex6(new Uint8Array(digest2));
|
|
120281
121399
|
}
|
|
120282
121400
|
async function workloadKeysetDigest(keyset) {
|
|
120283
|
-
return `sha256:${await
|
|
121401
|
+
return `sha256:${await sha256Hex3(canonicalJsonBytes(keyset))}`;
|
|
120284
121402
|
}
|
|
120285
121403
|
async function reportDataFor(keysetDigest, nonce) {
|
|
120286
121404
|
const nonceJson = nonce === null ? "null" : `"${nonce}"`;
|
|
120287
121405
|
const statement = `{"keyset_digest":"${keysetDigest}","nonce":${nonceJson},"purpose":"${ACI_REPORT_DATA_PURPOSE}"}`;
|
|
120288
|
-
return
|
|
121406
|
+
return sha256Hex3(new TextEncoder().encode(statement));
|
|
120289
121407
|
}
|
|
120290
121408
|
function parseReport(body) {
|
|
120291
|
-
if (!
|
|
121409
|
+
if (!isRecord10(body) || typeof body.api_version !== "string" || typeof body.workload_keyset_digest !== "string" || !isRecord10(body.attestation) || typeof body.attestation.tee_type !== "string" || typeof body.attestation.report_data !== "string" || !isRecord10(body.attestation.workload_keyset)) {
|
|
120292
121410
|
throw new E2eeAttestationError("malformed_report", "attestation report is missing required fields");
|
|
120293
121411
|
}
|
|
120294
121412
|
const keyset = body.attestation.workload_keyset;
|
|
@@ -120335,7 +121453,7 @@ async function verifyAciReportBinding(report, nonce, nowSeconds) {
|
|
|
120335
121453
|
}
|
|
120336
121454
|
function selectX25519Key(keyset, expectedKeyId) {
|
|
120337
121455
|
for (const entry of keyset.e2ee_public_keys) {
|
|
120338
|
-
if (!
|
|
121456
|
+
if (!isRecord10(entry) || entry.algo !== E2EE_ALGO_X25519)
|
|
120339
121457
|
continue;
|
|
120340
121458
|
if (typeof entry.public_key !== "string")
|
|
120341
121459
|
continue;
|
|
@@ -122895,7 +124013,7 @@ var objectToNumericMapAsync = async (object3) => {
|
|
|
122895
124013
|
}
|
|
122896
124014
|
return map2;
|
|
122897
124015
|
};
|
|
122898
|
-
var wait = (
|
|
124016
|
+
var wait = (ms4) => new Promise((resolve) => setTimeout(resolve, ms4));
|
|
122899
124017
|
var SPACE_OR_PUNCTUATION = /[\n\r\p{Z}\p{P}]+/u;
|
|
122900
124018
|
|
|
122901
124019
|
// ../core/dist/mcp/search/index.js
|
|
@@ -135948,6 +137066,7 @@ function createPsLiteRuntime(options) {
|
|
|
135948
137066
|
gatewayConfig: boundGatewayConfig,
|
|
135949
137067
|
serverOwner: options.serverOwner ?? options.identity?.address,
|
|
135950
137068
|
serverSigner: options.serverSigner,
|
|
137069
|
+
grantTtlSeconds: options.mcpGrantTtlSeconds,
|
|
135951
137070
|
activityRecorder
|
|
135952
137071
|
});
|
|
135953
137072
|
if (mcpResponse)
|
|
@@ -136130,7 +137249,8 @@ async function handleMcpRoute(input) {
|
|
|
136130
137249
|
gatewayUrl: input.gatewayConfig.url,
|
|
136131
137250
|
serverOwner: input.serverOwner,
|
|
136132
137251
|
serverSigner: input.serverSigner,
|
|
136133
|
-
now: input.now
|
|
137252
|
+
now: input.now,
|
|
137253
|
+
grantTtlSeconds: input.grantTtlSeconds
|
|
136134
137254
|
});
|
|
136135
137255
|
return jsonResponse4({ redirectTo: approved.redirectTo });
|
|
136136
137256
|
} catch (err2) {
|
|
@@ -136315,7 +137435,8 @@ async function handleMcpRoute(input) {
|
|
|
136315
137435
|
gateway,
|
|
136316
137436
|
serverOwner: input.serverOwner,
|
|
136317
137437
|
serverSigner: input.serverSigner,
|
|
136318
|
-
now: input.now
|
|
137438
|
+
now: input.now,
|
|
137439
|
+
grantTtlSeconds: input.grantTtlSeconds
|
|
136319
137440
|
});
|
|
136320
137441
|
finish("succeeded");
|
|
136321
137442
|
return jsonResponse4({
|
|
@@ -137128,6 +138249,11 @@ async function downloadOne(deps, record2) {
|
|
|
137128
138249
|
throw err2;
|
|
137129
138250
|
}
|
|
137130
138251
|
diagnostics?.onIndexEnd(record2.id, envelope.scope);
|
|
138252
|
+
await recordStoredVersion(storage, {
|
|
138253
|
+
scope: envelope.scope,
|
|
138254
|
+
collectedAt: envelope.collectedAt,
|
|
138255
|
+
data: envelope.data
|
|
138256
|
+
});
|
|
137131
138257
|
logger.info({ dataPointId: record2.id, scope: envelope.scope, path: relativePath }, "Downloaded and indexed data point");
|
|
137132
138258
|
if (deps.onDataPointIndexed) {
|
|
137133
138259
|
try {
|
|
@@ -137298,6 +138424,12 @@ async function reconcileDeletedDataPoint(deps, record2, deletedAt) {
|
|
|
137298
138424
|
if (orphanKeys.length > 0 && deps.pendingBlobDeletions) {
|
|
137299
138425
|
await deps.pendingBlobDeletions.add(orphanKeys);
|
|
137300
138426
|
}
|
|
138427
|
+
if (removed > 0 || kept === 0) {
|
|
138428
|
+
try {
|
|
138429
|
+
await storage.deleteFirstSeenLedger?.(record2.scope);
|
|
138430
|
+
} catch {
|
|
138431
|
+
}
|
|
138432
|
+
}
|
|
137301
138433
|
if (removed > 0 || kept > 0) {
|
|
137302
138434
|
logger.info({ dataPointId: record2.id, scope: record2.scope, deletedAt, removed, kept }, "Reconciled gateway deletion against local index");
|
|
137303
138435
|
}
|