@opendatalabs/personal-server-ts-server 1.32.0 → 1.33.1
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/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 +1274 -116
- 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,998 @@ 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
|
+
truncated = 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.truncated = ledger.truncated === 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.truncated) {
|
|
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
|
+
* baseline records (first seen at or before the baseline). Baseline records
|
|
113457
|
+
* are never dropped. Other absent records 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
|
+
* `truncated` 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 truncated = this.truncated || options.truncated === true;
|
|
113513
|
+
const retry = options.retry === void 0 ? this.retry : options.retry;
|
|
113514
|
+
return {
|
|
113515
|
+
version: 4,
|
|
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
|
+
...truncated ? { truncated: 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 (ledger.partial === true && 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 !== 4)
|
|
113558
|
+
return null;
|
|
113559
|
+
const { scope, baseline, current, latest, through, records, skipped, truncated } = 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 (truncated !== void 0 && truncated !== 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: 4,
|
|
113606
|
+
scope,
|
|
113607
|
+
baseline,
|
|
113608
|
+
current,
|
|
113609
|
+
latest: { collectedAt: latest.collectedAt, total },
|
|
113610
|
+
through,
|
|
113611
|
+
...retryValue ? { retry: retryValue } : {},
|
|
113612
|
+
...skipped ? { skipped } : {},
|
|
113613
|
+
...truncated ? { truncated: 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 OLDEST_PAGE = 20;
|
|
113643
|
+
var REBUILD_VERSION_LIMIT = 200;
|
|
113644
|
+
var REBUILD_BYTE_BUDGET = 256 * 1024 * 1024;
|
|
113645
|
+
function isRecord4(value) {
|
|
113646
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113647
|
+
}
|
|
113648
|
+
function readsNothing(scope) {
|
|
113649
|
+
return memoryRecordRulesFor(scope)?.length === 0;
|
|
113650
|
+
}
|
|
113651
|
+
async function readVersionData(storage, scope, collectedAt) {
|
|
113652
|
+
if (readsNothing(scope))
|
|
113653
|
+
return { scope, collectedAt, data: {} };
|
|
113654
|
+
try {
|
|
113655
|
+
const envelope = storage.readStoredEnvelope ? await storage.readStoredEnvelope(scope, collectedAt) : await storage.readEnvelope(scope, collectedAt);
|
|
113656
|
+
if (!isRecord4(envelope.data))
|
|
113657
|
+
return null;
|
|
113658
|
+
return { scope, collectedAt, data: envelope.data };
|
|
113659
|
+
} catch {
|
|
113660
|
+
return null;
|
|
113661
|
+
}
|
|
113662
|
+
}
|
|
113663
|
+
function retainedVersions(storage, scope) {
|
|
113664
|
+
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));
|
|
113665
|
+
}
|
|
113666
|
+
function withinBudget(scope, entries, budget) {
|
|
113667
|
+
if (readsNothing(scope))
|
|
113668
|
+
return [...entries];
|
|
113669
|
+
const selected = [];
|
|
113670
|
+
let used = 0;
|
|
113671
|
+
for (const entry of entries) {
|
|
113672
|
+
used += Math.max(0, entry.sizeBytes ?? 0);
|
|
113673
|
+
if (used > budget)
|
|
113674
|
+
break;
|
|
113675
|
+
selected.push(entry);
|
|
113676
|
+
}
|
|
113677
|
+
return selected;
|
|
113678
|
+
}
|
|
113679
|
+
async function readStoredLedger(storage, scope) {
|
|
113680
|
+
if (!storage.readFirstSeenLedger)
|
|
113681
|
+
return null;
|
|
113682
|
+
try {
|
|
113683
|
+
const ledger = readScopeFirstSeenLedger(await storage.readFirstSeenLedger(scope));
|
|
113684
|
+
return ledger !== null && ledger.scope === scope ? ledger : null;
|
|
113685
|
+
} catch {
|
|
113686
|
+
return null;
|
|
113687
|
+
}
|
|
113688
|
+
}
|
|
113689
|
+
async function dropIfScopeEmpty(storage, scope) {
|
|
113690
|
+
if (storage.findEntry({ scope }))
|
|
113691
|
+
return false;
|
|
113692
|
+
await storage.deleteFirstSeenLedger?.(scope);
|
|
113693
|
+
return true;
|
|
113694
|
+
}
|
|
113695
|
+
function latestStillStored(storage, ledger) {
|
|
113696
|
+
return storage.findEntry({ scope: ledger.scope, at: ledger.latest.collectedAt })?.collectedAt === ledger.latest.collectedAt;
|
|
113697
|
+
}
|
|
113698
|
+
function baselineStillStored(storage, ledger) {
|
|
113699
|
+
if (ledger.baseline === null)
|
|
113700
|
+
return true;
|
|
113701
|
+
return storage.findEntry({ scope: ledger.scope, at: ledger.baseline })?.collectedAt === ledger.baseline;
|
|
113702
|
+
}
|
|
113703
|
+
function isMarker(ledger) {
|
|
113704
|
+
return ledger.skipped === "too_large" || ledger.skipped === "unreadable";
|
|
113705
|
+
}
|
|
113706
|
+
function newerThan(retained, ledger) {
|
|
113707
|
+
const throughMs = Date.parse(ledger.through);
|
|
113708
|
+
return retained.filter((entry) => Date.parse(entry.collectedAt) > throughMs);
|
|
113709
|
+
}
|
|
113710
|
+
async function foldEntries(storage, scope, entries, fold) {
|
|
113711
|
+
let folded = 0;
|
|
113712
|
+
const failed = [];
|
|
113713
|
+
for (const entry of [...entries].reverse()) {
|
|
113714
|
+
const version4 = await readVersionData(storage, scope, entry.collectedAt);
|
|
113715
|
+
if (version4) {
|
|
113716
|
+
await fold.add(version4);
|
|
113717
|
+
folded += 1;
|
|
113718
|
+
} else {
|
|
113719
|
+
failed.push(entry);
|
|
113720
|
+
}
|
|
113721
|
+
await yieldToEventLoop();
|
|
113722
|
+
}
|
|
113723
|
+
return { folded, failed };
|
|
113724
|
+
}
|
|
113725
|
+
function oldestStartsAtFirst(oldestInstant) {
|
|
113726
|
+
const lowest = oldestInstant.reduce((a10, b10) => b10.version < a10.version ? b10 : a10);
|
|
113727
|
+
return lowest.version <= 1 || (lowest.afterTombstoneVersion ?? null) !== null;
|
|
113728
|
+
}
|
|
113729
|
+
function baselineIsKnown(storage, ledger) {
|
|
113730
|
+
if (ledger.baseline === null || ledger.skipped !== void 0)
|
|
113731
|
+
return true;
|
|
113732
|
+
if (ledger.truncated === true)
|
|
113733
|
+
return false;
|
|
113734
|
+
const count = storage.countVersions(ledger.scope);
|
|
113735
|
+
const tail = storage.listVersions(ledger.scope, {
|
|
113736
|
+
limit: OLDEST_PAGE,
|
|
113737
|
+
offset: Math.max(0, count - OLDEST_PAGE)
|
|
113738
|
+
}).filter((entry) => !Number.isNaN(Date.parse(entry.collectedAt)));
|
|
113739
|
+
if (tail.length === 0)
|
|
113740
|
+
return false;
|
|
113741
|
+
const oldestMs = Math.min(...tail.map((e10) => Date.parse(e10.collectedAt)));
|
|
113742
|
+
if (Date.parse(ledger.baseline) !== oldestMs)
|
|
113743
|
+
return false;
|
|
113744
|
+
return oldestStartsAtFirst(tail.filter((entry) => Date.parse(entry.collectedAt) === oldestMs));
|
|
113745
|
+
}
|
|
113746
|
+
function withDerivedPartial(storage, ledger) {
|
|
113747
|
+
if (baselineIsKnown(storage, ledger))
|
|
113748
|
+
return ledger;
|
|
113749
|
+
return { ...ledger, partial: true };
|
|
113750
|
+
}
|
|
113751
|
+
function retryOf(failed, now) {
|
|
113752
|
+
if (failed.length === 0)
|
|
113753
|
+
return null;
|
|
113754
|
+
return {
|
|
113755
|
+
versions: failed.slice(0, MAX_RETRY_VERSIONS).map((entry) => entry.collectedAt),
|
|
113756
|
+
attemptedAt: now.toISOString()
|
|
113757
|
+
};
|
|
113758
|
+
}
|
|
113759
|
+
async function rebuild(storage, scope, retained, budget, now) {
|
|
113760
|
+
if (retained.length === 0)
|
|
113761
|
+
return null;
|
|
113762
|
+
const selected = withinBudget(scope, retained, budget);
|
|
113763
|
+
const fold = new LedgerFold(null, scope);
|
|
113764
|
+
const { folded, failed } = await foldEntries(storage, scope, selected, fold);
|
|
113765
|
+
if (folded === 0) {
|
|
113766
|
+
return {
|
|
113767
|
+
version: 4,
|
|
113768
|
+
scope,
|
|
113769
|
+
baseline: null,
|
|
113770
|
+
current: null,
|
|
113771
|
+
latest: { collectedAt: retained[0].collectedAt, total: 0 },
|
|
113772
|
+
through: retained[0].collectedAt,
|
|
113773
|
+
skipped: selected.length === 0 ? "too_large" : "unreadable",
|
|
113774
|
+
records: {}
|
|
113775
|
+
};
|
|
113776
|
+
}
|
|
113777
|
+
const total = storage.countVersions(scope);
|
|
113778
|
+
return fold.finish({
|
|
113779
|
+
// Truncated only when the window or the byte budget left versions out. A
|
|
113780
|
+
// version that could not be read is not a truncation: it is retried (see
|
|
113781
|
+
// `retry`), and the ledger converges once it is read or deleted.
|
|
113782
|
+
truncated: selected.length < retained.length || retained.length < total,
|
|
113783
|
+
through: retained[0].collectedAt,
|
|
113784
|
+
retry: retryOf(failed, now)
|
|
113785
|
+
});
|
|
113786
|
+
}
|
|
113787
|
+
async function catchUp(storage, ledger, retained, budget, now) {
|
|
113788
|
+
const newer = newerThan(retained, ledger);
|
|
113789
|
+
const selected = withinBudget(ledger.scope, newer, budget);
|
|
113790
|
+
const pending = (ledger.retry?.versions ?? []).filter((version4) => retained.some((entry) => entry.collectedAt === version4));
|
|
113791
|
+
const due = ledger.retry !== void 0 && pending.length > 0 && now.getTime() - Date.parse(ledger.retry.attemptedAt) >= RETRY_UNREADABLE_MS;
|
|
113792
|
+
const retryEntries = due ? withinBudget(ledger.scope, retained.filter((entry) => pending.includes(entry.collectedAt)), budget) : [];
|
|
113793
|
+
const forgotten = pending.length !== (ledger.retry?.versions.length ?? 0);
|
|
113794
|
+
if (selected.length === 0 && retryEntries.length === 0 && !forgotten) {
|
|
113795
|
+
return ledger;
|
|
113796
|
+
}
|
|
113797
|
+
const fold = new LedgerFold(ledger);
|
|
113798
|
+
const failedNew = selected.length > 0 ? (await foldEntries(storage, ledger.scope, selected, fold)).failed : [];
|
|
113799
|
+
const failedRetry = retryEntries.length > 0 ? (await foldEntries(storage, ledger.scope, retryEntries, fold)).failed : [];
|
|
113800
|
+
const stillFailing = due ? failedRetry.map((entry) => entry.collectedAt) : pending;
|
|
113801
|
+
const versions = [
|
|
113802
|
+
...stillFailing,
|
|
113803
|
+
...failedNew.map((entry) => entry.collectedAt)
|
|
113804
|
+
].slice(0, MAX_RETRY_VERSIONS);
|
|
113805
|
+
const attempted = due || failedNew.length > 0;
|
|
113806
|
+
const retry = versions.length === 0 ? null : {
|
|
113807
|
+
versions,
|
|
113808
|
+
attemptedAt: attempted ? now.toISOString() : ledger.retry.attemptedAt
|
|
113809
|
+
};
|
|
113810
|
+
const beyond = storage.listVersions(ledger.scope, {
|
|
113811
|
+
limit: 1,
|
|
113812
|
+
offset: retained.length
|
|
113813
|
+
})[0];
|
|
113814
|
+
const windowCut = beyond !== void 0 && Date.parse(beyond.collectedAt) > Date.parse(ledger.through);
|
|
113815
|
+
return await fold.finish({
|
|
113816
|
+
truncated: windowCut || selected.length < newer.length,
|
|
113817
|
+
through: selected.length > 0 ? retained[0].collectedAt : ledger.through,
|
|
113818
|
+
retry
|
|
113819
|
+
}) ?? ledger;
|
|
113820
|
+
}
|
|
113821
|
+
async function recordStoredVersion(storage, version4) {
|
|
113822
|
+
if (!storage.readFirstSeenLedger || !storage.writeFirstSeenLedger)
|
|
113823
|
+
return;
|
|
113824
|
+
try {
|
|
113825
|
+
await withScopeLock(version4.scope, async () => {
|
|
113826
|
+
const retained = retainedVersions(storage, version4.scope);
|
|
113827
|
+
let existing = await readStoredLedger(storage, version4.scope);
|
|
113828
|
+
if (existing && !latestStillStored(storage, existing)) {
|
|
113829
|
+
await storage.deleteFirstSeenLedger?.(version4.scope);
|
|
113830
|
+
existing = null;
|
|
113831
|
+
}
|
|
113832
|
+
const others = retained.filter((entry) => entry.collectedAt !== version4.collectedAt);
|
|
113833
|
+
let through = version4.collectedAt;
|
|
113834
|
+
if (existing) {
|
|
113835
|
+
if (isMarker(existing))
|
|
113836
|
+
return;
|
|
113837
|
+
const throughMs = Date.parse(existing.through);
|
|
113838
|
+
const unfolded = others.some((entry) => Date.parse(entry.collectedAt) > throughMs);
|
|
113839
|
+
through = unfolded || Date.parse(version4.collectedAt) < throughMs ? existing.through : version4.collectedAt;
|
|
113840
|
+
} else if (others.length > 0) {
|
|
113841
|
+
return;
|
|
113842
|
+
}
|
|
113843
|
+
const fold = new LedgerFold(existing, version4.scope);
|
|
113844
|
+
await fold.add(version4);
|
|
113845
|
+
const next = await fold.finish({ through });
|
|
113846
|
+
if (!next)
|
|
113847
|
+
return;
|
|
113848
|
+
await storage.writeFirstSeenLedger(version4.scope, next);
|
|
113849
|
+
await dropIfScopeEmpty(storage, version4.scope);
|
|
113850
|
+
});
|
|
113851
|
+
} catch {
|
|
113852
|
+
}
|
|
113853
|
+
}
|
|
113854
|
+
async function ensureScopeLedger(storage, scope, options = {}) {
|
|
113855
|
+
const budget = options.byteBudget ?? REBUILD_BYTE_BUDGET;
|
|
113856
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
113857
|
+
return withScopeLock(scope, async () => {
|
|
113858
|
+
try {
|
|
113859
|
+
const retained = retainedVersions(storage, scope);
|
|
113860
|
+
if (retained.length === 0) {
|
|
113861
|
+
await storage.deleteFirstSeenLedger?.(scope);
|
|
113862
|
+
return null;
|
|
113863
|
+
}
|
|
113864
|
+
let existing = await readStoredLedger(storage, scope);
|
|
113865
|
+
if (existing && (!latestStillStored(storage, existing) || !baselineStillStored(storage, existing) || isMarker(existing) && newerThan(retained, existing).length > 0)) {
|
|
113866
|
+
existing = null;
|
|
113867
|
+
}
|
|
113868
|
+
const ledger = existing ? await catchUp(storage, existing, retained, budget, now) : await rebuild(storage, scope, retained, budget, now);
|
|
113869
|
+
if (ledger && ledger !== existing && storage.writeFirstSeenLedger) {
|
|
113870
|
+
try {
|
|
113871
|
+
await storage.writeFirstSeenLedger(scope, ledger);
|
|
113872
|
+
if (await dropIfScopeEmpty(storage, scope))
|
|
113873
|
+
return null;
|
|
113874
|
+
} catch {
|
|
113875
|
+
}
|
|
113876
|
+
}
|
|
113877
|
+
return ledger ? withDerivedPartial(storage, ledger) : ledger;
|
|
113878
|
+
} catch {
|
|
113879
|
+
return null;
|
|
113880
|
+
}
|
|
113881
|
+
});
|
|
113882
|
+
}
|
|
113883
|
+
|
|
113884
|
+
// ../core/dist/additions/summary.js
|
|
113885
|
+
var InvalidTimezoneError = class extends Error {
|
|
113886
|
+
};
|
|
113887
|
+
function createFormatter(timezone) {
|
|
113888
|
+
try {
|
|
113889
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
113890
|
+
timeZone: timezone,
|
|
113891
|
+
year: "numeric",
|
|
113892
|
+
month: "2-digit",
|
|
113893
|
+
day: "2-digit"
|
|
113894
|
+
});
|
|
113895
|
+
} catch {
|
|
113896
|
+
throw new InvalidTimezoneError(`Unknown timezone: ${timezone}`);
|
|
113897
|
+
}
|
|
113898
|
+
}
|
|
113899
|
+
function localDate(formatter, instant) {
|
|
113900
|
+
let year = "";
|
|
113901
|
+
let month = "";
|
|
113902
|
+
let day = "";
|
|
113903
|
+
for (const part of formatter.formatToParts(instant)) {
|
|
113904
|
+
if (part.type === "year")
|
|
113905
|
+
year = part.value;
|
|
113906
|
+
else if (part.type === "month")
|
|
113907
|
+
month = part.value;
|
|
113908
|
+
else if (part.type === "day")
|
|
113909
|
+
day = part.value;
|
|
113910
|
+
}
|
|
113911
|
+
return `${year}-${month}-${day}`;
|
|
113912
|
+
}
|
|
113913
|
+
function pad2(value) {
|
|
113914
|
+
return String(value).padStart(2, "0");
|
|
113915
|
+
}
|
|
113916
|
+
function buildDayRows(formatter, now, days) {
|
|
113917
|
+
const [year, month, day] = localDate(formatter, now).split("-").map(Number);
|
|
113918
|
+
const rows = [];
|
|
113919
|
+
for (let offset = days - 1; offset >= 0; offset -= 1) {
|
|
113920
|
+
const date5 = new Date(Date.UTC(year, month - 1, day - offset));
|
|
113921
|
+
rows.push({
|
|
113922
|
+
date: `${date5.getUTCFullYear()}-${pad2(date5.getUTCMonth() + 1)}-${pad2(date5.getUTCDate())}`,
|
|
113923
|
+
added: 0
|
|
113924
|
+
});
|
|
113925
|
+
}
|
|
113926
|
+
return rows;
|
|
113927
|
+
}
|
|
113928
|
+
function validateTimezone(timezone) {
|
|
113929
|
+
createFormatter(timezone);
|
|
113930
|
+
}
|
|
113931
|
+
async function summarizeAdditions(input) {
|
|
113932
|
+
const { timezone, days, now } = input;
|
|
113933
|
+
const formatter = createFormatter(timezone);
|
|
113934
|
+
const dayRows = buildDayRows(formatter, now, days);
|
|
113935
|
+
const dayIndex = new Map(dayRows.map((row, index) => [row.date, index]));
|
|
113936
|
+
const scopes = [];
|
|
113937
|
+
let total = 0;
|
|
113938
|
+
let trackedSince = null;
|
|
113939
|
+
let trackedSinceAt = Infinity;
|
|
113940
|
+
let anyPartial = false;
|
|
113941
|
+
for await (const ledger of input.ledgers) {
|
|
113942
|
+
for (const firstSeen of listAddedTimestamps(ledger)) {
|
|
113943
|
+
const date5 = localDate(formatter, new Date(Date.parse(firstSeen)));
|
|
113944
|
+
const index = dayIndex.get(date5);
|
|
113945
|
+
if (index !== void 0)
|
|
113946
|
+
dayRows[index].added += 1;
|
|
113947
|
+
}
|
|
113948
|
+
total += ledger.latest.total;
|
|
113949
|
+
const scopeTrackedSince = ledger.skipped ? null : ledger.baseline;
|
|
113950
|
+
if (scopeTrackedSince !== null) {
|
|
113951
|
+
const baselineAt = Date.parse(scopeTrackedSince);
|
|
113952
|
+
if (baselineAt < trackedSinceAt) {
|
|
113953
|
+
trackedSinceAt = baselineAt;
|
|
113954
|
+
trackedSince = scopeTrackedSince;
|
|
113955
|
+
}
|
|
113956
|
+
}
|
|
113957
|
+
const partial2 = scopeTrackedSince !== null && ledger.partial === true;
|
|
113958
|
+
anyPartial ||= partial2;
|
|
113959
|
+
scopes.push({
|
|
113960
|
+
scope: ledger.scope,
|
|
113961
|
+
total: ledger.latest.total,
|
|
113962
|
+
trackedSince: scopeTrackedSince,
|
|
113963
|
+
partial: partial2
|
|
113964
|
+
});
|
|
113965
|
+
}
|
|
113966
|
+
scopes.sort((a10, b10) => a10.scope.localeCompare(b10.scope));
|
|
113967
|
+
return {
|
|
113968
|
+
timezone,
|
|
113969
|
+
total,
|
|
113970
|
+
days: dayRows,
|
|
113971
|
+
trackedSince,
|
|
113972
|
+
partial: anyPartial,
|
|
113973
|
+
scopes
|
|
113974
|
+
};
|
|
113975
|
+
}
|
|
113976
|
+
|
|
112985
113977
|
// ../core/dist/contracts/data.js
|
|
112986
113978
|
var IngestPersistedError = class extends Error {
|
|
112987
113979
|
relativePath;
|
|
@@ -113023,35 +114015,43 @@ function normalizeLimit(value) {
|
|
|
113023
114015
|
function normalizeOffset(value) {
|
|
113024
114016
|
return value ?? 0;
|
|
113025
114017
|
}
|
|
113026
|
-
function
|
|
114018
|
+
function isRecord5(value) {
|
|
113027
114019
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
113028
114020
|
}
|
|
113029
114021
|
var VISIBILITY_PAGE_SIZE = 200;
|
|
114022
|
+
async function collectScopes(storage, scopePrefix, isVisible) {
|
|
114023
|
+
const scopes = [];
|
|
114024
|
+
for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
|
|
114025
|
+
const batch = storage.listScopes({
|
|
114026
|
+
scopePrefix,
|
|
114027
|
+
limit: VISIBILITY_PAGE_SIZE,
|
|
114028
|
+
offset: scan
|
|
114029
|
+
});
|
|
114030
|
+
for (const summary of batch.scopes) {
|
|
114031
|
+
if (!isVisible) {
|
|
114032
|
+
scopes.push(summary);
|
|
114033
|
+
continue;
|
|
114034
|
+
}
|
|
114035
|
+
const latest = storage.findEntry({
|
|
114036
|
+
scope: summary.scope,
|
|
114037
|
+
at: summary.latestCollectedAt
|
|
114038
|
+
});
|
|
114039
|
+
if (!latest || await isVisible(summary.scope, latest)) {
|
|
114040
|
+
scopes.push(summary);
|
|
114041
|
+
}
|
|
114042
|
+
}
|
|
114043
|
+
if (batch.scopes.length < VISIBILITY_PAGE_SIZE)
|
|
114044
|
+
break;
|
|
114045
|
+
}
|
|
114046
|
+
return scopes;
|
|
114047
|
+
}
|
|
113030
114048
|
async function listDataScopesContract(input) {
|
|
113031
114049
|
const limit = normalizeLimit(input.limit);
|
|
113032
114050
|
const offset = normalizeOffset(input.offset);
|
|
113033
114051
|
let page;
|
|
113034
114052
|
let total;
|
|
113035
114053
|
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
|
-
}
|
|
114054
|
+
const visible = await collectScopes(input.storage, input.scopePrefix, input.isVisible);
|
|
113055
114055
|
total = visible.length;
|
|
113056
114056
|
page = visible.slice(offset, offset + limit);
|
|
113057
114057
|
} else {
|
|
@@ -113133,6 +114133,42 @@ async function listDataVersionsContract(input) {
|
|
|
113133
114133
|
}
|
|
113134
114134
|
};
|
|
113135
114135
|
}
|
|
114136
|
+
function invalidQuery(message) {
|
|
114137
|
+
return {
|
|
114138
|
+
ok: false,
|
|
114139
|
+
status: 400,
|
|
114140
|
+
body: { error: "INVALID_QUERY", message }
|
|
114141
|
+
};
|
|
114142
|
+
}
|
|
114143
|
+
async function summarizeDataAdditionsContract(input) {
|
|
114144
|
+
if (!Number.isInteger(input.days) || input.days < 1 || input.days > 31) {
|
|
114145
|
+
return invalidQuery("days must be an integer between 1 and 31");
|
|
114146
|
+
}
|
|
114147
|
+
try {
|
|
114148
|
+
validateTimezone(input.timezone);
|
|
114149
|
+
} catch (err2) {
|
|
114150
|
+
if (err2 instanceof InvalidTimezoneError) {
|
|
114151
|
+
return invalidQuery("Unknown timezone");
|
|
114152
|
+
}
|
|
114153
|
+
throw err2;
|
|
114154
|
+
}
|
|
114155
|
+
const scopes = await collectScopes(input.storage, void 0, input.isVisible);
|
|
114156
|
+
async function* ledgers() {
|
|
114157
|
+
for (const summary of scopes) {
|
|
114158
|
+
const ledger = await ensureScopeLedger(input.storage, summary.scope, {
|
|
114159
|
+
now: input.now
|
|
114160
|
+
});
|
|
114161
|
+
if (ledger)
|
|
114162
|
+
yield ledger;
|
|
114163
|
+
}
|
|
114164
|
+
}
|
|
114165
|
+
return summarizeAdditions({
|
|
114166
|
+
ledgers: ledgers(),
|
|
114167
|
+
timezone: input.timezone,
|
|
114168
|
+
days: input.days,
|
|
114169
|
+
now: input.now
|
|
114170
|
+
});
|
|
114171
|
+
}
|
|
113136
114172
|
async function readDataContract(input) {
|
|
113137
114173
|
const scopeResult = parseDataScopeContract(input.scopeParam);
|
|
113138
114174
|
if (!scopeResult.ok)
|
|
@@ -113162,7 +114198,7 @@ async function ingestDataContract(input) {
|
|
|
113162
114198
|
const scopeResult = parseDataScopeContract(input.scopeParam);
|
|
113163
114199
|
if (!scopeResult.ok)
|
|
113164
114200
|
return scopeResult;
|
|
113165
|
-
if (!
|
|
114201
|
+
if (!isRecord5(input.body)) {
|
|
113166
114202
|
return {
|
|
113167
114203
|
ok: false,
|
|
113168
114204
|
status: 400,
|
|
@@ -113207,6 +114243,11 @@ async function ingestDataContract(input) {
|
|
|
113207
114243
|
sizeBytes: writeResult.sizeBytes,
|
|
113208
114244
|
afterTombstoneVersion: input.afterTombstoneVersion ?? null
|
|
113209
114245
|
});
|
|
114246
|
+
await recordStoredVersion(input.storage, {
|
|
114247
|
+
scope: scopeResult.scope,
|
|
114248
|
+
collectedAt: input.collectedAt,
|
|
114249
|
+
data: envelope.data
|
|
114250
|
+
});
|
|
113210
114251
|
return {
|
|
113211
114252
|
ok: true,
|
|
113212
114253
|
scope: scopeResult.scope,
|
|
@@ -113246,7 +114287,7 @@ async function ingestBinaryDataContract(input) {
|
|
|
113246
114287
|
}
|
|
113247
114288
|
};
|
|
113248
114289
|
}
|
|
113249
|
-
if (
|
|
114290
|
+
if (isRecord5(input.metadata) && (hasReservedWriterKey(input.metadata) || hasReservedLineageKey(input.metadata))) {
|
|
113250
114291
|
return {
|
|
113251
114292
|
ok: false,
|
|
113252
114293
|
status: 400,
|
|
@@ -113279,6 +114320,11 @@ async function ingestBinaryDataContract(input) {
|
|
|
113279
114320
|
sizeBytes: input.bytes.length,
|
|
113280
114321
|
afterTombstoneVersion: input.afterTombstoneVersion ?? null
|
|
113281
114322
|
});
|
|
114323
|
+
await recordStoredVersion(input.storage, {
|
|
114324
|
+
scope: scopeResult.scope,
|
|
114325
|
+
collectedAt: input.collectedAt,
|
|
114326
|
+
data: envelope.data
|
|
114327
|
+
});
|
|
113282
114328
|
return {
|
|
113283
114329
|
ok: true,
|
|
113284
114330
|
scope: scopeResult.scope,
|
|
@@ -114527,8 +115573,8 @@ function parseExpirySeconds(value) {
|
|
|
114527
115573
|
const seconds = Number(value);
|
|
114528
115574
|
return seconds > 0 ? seconds : void 0;
|
|
114529
115575
|
}
|
|
114530
|
-
const
|
|
114531
|
-
return Number.isFinite(
|
|
115576
|
+
const ms4 = Date.parse(value);
|
|
115577
|
+
return Number.isFinite(ms4) ? Math.floor(ms4 / 1e3) : void 0;
|
|
114532
115578
|
}
|
|
114533
115579
|
function sortedUnique(values) {
|
|
114534
115580
|
return Array.from(new Set(values)).sort();
|
|
@@ -115576,8 +116622,8 @@ async function buildChallenge(input) {
|
|
|
115576
116622
|
}
|
|
115577
116623
|
function base64decode(input) {
|
|
115578
116624
|
let s10 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
115579
|
-
const
|
|
115580
|
-
s10 += "=".repeat(
|
|
116625
|
+
const pad3 = (4 - s10.length % 4) % 4;
|
|
116626
|
+
s10 += "=".repeat(pad3);
|
|
115581
116627
|
const binString = atob(s10);
|
|
115582
116628
|
const bytes2 = Uint8Array.from(binString, (c10) => c10.codePointAt(0) ?? 0);
|
|
115583
116629
|
return new TextDecoder().decode(bytes2);
|
|
@@ -116198,6 +117244,23 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
|
|
|
116198
117244
|
});
|
|
116199
117245
|
return jsonResponse(result.response);
|
|
116200
117246
|
}
|
|
117247
|
+
if (pathname === "/additions") {
|
|
117248
|
+
if (request2.method !== "GET")
|
|
117249
|
+
return methodNotAllowed();
|
|
117250
|
+
await deps.auth.authorizeOwner(request2);
|
|
117251
|
+
const daysRaw = url2.searchParams.get("days");
|
|
117252
|
+
const result = await summarizeDataAdditionsContract({
|
|
117253
|
+
storage: deps.storage,
|
|
117254
|
+
isVisible: discoveryVisibility(deps),
|
|
117255
|
+
timezone: url2.searchParams.get("tz") ?? "UTC",
|
|
117256
|
+
// Digits only: Number() would also accept "", "1e1", "0x7" and " 7".
|
|
117257
|
+
days: daysRaw === null ? 7 : /^\d{1,3}$/.test(daysRaw) ? Number(daysRaw) : Number.NaN,
|
|
117258
|
+
now: (deps.now ?? (() => /* @__PURE__ */ new Date()))()
|
|
117259
|
+
});
|
|
117260
|
+
if ("ok" in result)
|
|
117261
|
+
return contractErrorResponse(result);
|
|
117262
|
+
return jsonResponse(result);
|
|
117263
|
+
}
|
|
116201
117264
|
const parts = pathname.split("/").filter(Boolean);
|
|
116202
117265
|
if (parts.length === 2 && parts[1] === "versions") {
|
|
116203
117266
|
if (request2.method !== "GET")
|
|
@@ -117359,7 +118422,8 @@ function normalizeState(state) {
|
|
|
117359
118422
|
})),
|
|
117360
118423
|
envelopes: state.envelopes,
|
|
117361
118424
|
blockManifests: state.blockManifests ?? [],
|
|
117362
|
-
blockPayloads: state.blockPayloads ?? []
|
|
118425
|
+
blockPayloads: state.blockPayloads ?? [],
|
|
118426
|
+
...state.pendingLedgerDeletes?.length ? { pendingLedgerDeletes: state.pendingLedgerDeletes } : {}
|
|
117363
118427
|
};
|
|
117364
118428
|
}
|
|
117365
118429
|
function createIndexedDbFallbackDataFileStore(envelopes, blockManifests = /* @__PURE__ */ new Map(), blockPayloads = /* @__PURE__ */ new Map()) {
|
|
@@ -117584,6 +118648,18 @@ function createIndexedDbPsLitePersistence(options = {}) {
|
|
|
117584
118648
|
},
|
|
117585
118649
|
async write(state) {
|
|
117586
118650
|
await runIndexedDbTransaction(resolved, "readwrite", (store) => store.put(state, resolved.key));
|
|
118651
|
+
},
|
|
118652
|
+
// Side records live in the same object store under their own keys, which
|
|
118653
|
+
// a build that only knows `resolved.key` never reads.
|
|
118654
|
+
async readAux(name) {
|
|
118655
|
+
const value = await runIndexedDbTransaction(resolved, "readonly", (store) => store.get(`${resolved.key}:${name}`));
|
|
118656
|
+
return value ?? null;
|
|
118657
|
+
},
|
|
118658
|
+
async writeAux(name, value) {
|
|
118659
|
+
await runIndexedDbTransaction(resolved, "readwrite", (store) => store.put(value, `${resolved.key}:${name}`));
|
|
118660
|
+
},
|
|
118661
|
+
async deleteAux(name) {
|
|
118662
|
+
await runIndexedDbTransaction(resolved, "readwrite", (store) => store.delete(`${resolved.key}:${name}`));
|
|
117587
118663
|
}
|
|
117588
118664
|
};
|
|
117589
118665
|
}
|
|
@@ -117595,6 +118671,9 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117595
118671
|
]));
|
|
117596
118672
|
const fallbackBlockManifests = new Map((state.blockManifests ?? []).map(({ path, manifest }) => [path, manifest]));
|
|
117597
118673
|
const fallbackBlockPayloads = new Map((state.blockPayloads ?? []).map(({ path, block }) => [path, block]));
|
|
118674
|
+
const ledgerAux = (scope) => `first-seen:${scope}`;
|
|
118675
|
+
const firstSeenLedgers = /* @__PURE__ */ new Map();
|
|
118676
|
+
const pendingLedgerDeletes = new Set(state.pendingLedgerDeletes ?? []);
|
|
117598
118677
|
const fallbackStore = createIndexedDbFallbackDataFileStore(fallbackEnvelopes, fallbackBlockManifests, fallbackBlockPayloads);
|
|
117599
118678
|
const fileStore = dataFileStore ?? (adapter.kind !== "custom" && await isOpfsAvailable() ? await createOpfsPsLiteDataFileStore() : fallbackStore);
|
|
117600
118679
|
const capabilities = {
|
|
@@ -117608,7 +118687,8 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117608
118687
|
...state,
|
|
117609
118688
|
envelopes: fileStore.kind === "indexeddb" ? Array.from(fallbackEnvelopes.values()) : [],
|
|
117610
118689
|
blockManifests: Array.from(fallbackBlockManifests.entries()).map(([path, manifest]) => ({ path, manifest })),
|
|
117611
|
-
blockPayloads: Array.from(fallbackBlockPayloads.entries()).map(([path, block]) => ({ path, block }))
|
|
118690
|
+
blockPayloads: Array.from(fallbackBlockPayloads.entries()).map(([path, block]) => ({ path, block })),
|
|
118691
|
+
pendingLedgerDeletes: pendingLedgerDeletes.size > 0 ? Array.from(pendingLedgerDeletes) : void 0
|
|
117612
118692
|
};
|
|
117613
118693
|
const write = persistQueue.then(() => persistence.write(snapshot));
|
|
117614
118694
|
persistQueue = write.catch(() => void 0);
|
|
@@ -117886,33 +118966,55 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117886
118966
|
}
|
|
117887
118967
|
return updated;
|
|
117888
118968
|
},
|
|
117889
|
-
async
|
|
117890
|
-
|
|
117891
|
-
|
|
117892
|
-
|
|
117893
|
-
|
|
117894
|
-
|
|
117895
|
-
|
|
117896
|
-
|
|
117897
|
-
|
|
117898
|
-
|
|
117899
|
-
|
|
117900
|
-
|
|
117901
|
-
|
|
117902
|
-
|
|
117903
|
-
|
|
117904
|
-
|
|
117905
|
-
|
|
117906
|
-
|
|
117907
|
-
|
|
117908
|
-
|
|
117909
|
-
|
|
117910
|
-
|
|
117911
|
-
|
|
117912
|
-
]
|
|
117913
|
-
|
|
117914
|
-
|
|
117915
|
-
|
|
118969
|
+
async readFirstSeenLedger(scope) {
|
|
118970
|
+
if (!firstSeenLedgers.has(scope)) {
|
|
118971
|
+
const stored = await persistence.readAux?.(ledgerAux(scope)) ?? null;
|
|
118972
|
+
if (stored !== null)
|
|
118973
|
+
firstSeenLedgers.set(scope, stored);
|
|
118974
|
+
}
|
|
118975
|
+
return structuredClone(firstSeenLedgers.get(scope) ?? null);
|
|
118976
|
+
},
|
|
118977
|
+
async writeFirstSeenLedger(scope, ledger) {
|
|
118978
|
+
firstSeenLedgers.set(scope, structuredClone(ledger));
|
|
118979
|
+
await persistence.writeAux?.(ledgerAux(scope), ledger);
|
|
118980
|
+
},
|
|
118981
|
+
async deleteFirstSeenLedger(scope) {
|
|
118982
|
+
firstSeenLedgers.delete(scope);
|
|
118983
|
+
await persistence.deleteAux?.(ledgerAux(scope));
|
|
118984
|
+
},
|
|
118985
|
+
// Deletions run under the scope's first-seen sidecar lock (a rebuild in
|
|
118986
|
+
// flight cannot write it back), and the sidecar goes with the scope's last
|
|
118987
|
+
// version, so no delete path leaves a stale ledger behind.
|
|
118988
|
+
deleteScope(scope) {
|
|
118989
|
+
return withScopeLock(scope, async () => {
|
|
118990
|
+
await dropLedger(scope);
|
|
118991
|
+
let deleted = 0;
|
|
118992
|
+
const deletedPaths = [];
|
|
118993
|
+
const deletedBlockTrees = [];
|
|
118994
|
+
state = {
|
|
118995
|
+
...state,
|
|
118996
|
+
entries: state.entries.filter((entry) => {
|
|
118997
|
+
if (entry.scope !== scope)
|
|
118998
|
+
return true;
|
|
118999
|
+
deleted += 1;
|
|
119000
|
+
deletedPaths.push(envelopePath(entry.scope, entry.collectedAt));
|
|
119001
|
+
deletedBlockTrees.push(blockTreePath(entry.scope, entry.collectedAt));
|
|
119002
|
+
return false;
|
|
119003
|
+
})
|
|
119004
|
+
};
|
|
119005
|
+
await Promise.all([
|
|
119006
|
+
...deletedPaths.flatMap((path) => [
|
|
119007
|
+
fileStore.deleteEnvelope(path),
|
|
119008
|
+
fallbackStore.deleteEnvelope(path)
|
|
119009
|
+
]),
|
|
119010
|
+
...deletedBlockTrees.flatMap((path) => [
|
|
119011
|
+
fileStore.deleteBlockTree?.(path),
|
|
119012
|
+
fallbackStore.deleteBlockTree?.(path)
|
|
119013
|
+
])
|
|
119014
|
+
].filter((promise2) => promise2 !== void 0));
|
|
119015
|
+
await persist();
|
|
119016
|
+
return deleted;
|
|
119017
|
+
});
|
|
117916
119018
|
},
|
|
117917
119019
|
async deleteVersion(scope, collectedAt) {
|
|
117918
119020
|
const entry = state.entries.find((e10) => e10.scope === scope && e10.collectedAt === collectedAt);
|
|
@@ -117927,7 +119029,35 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117927
119029
|
return removeEntry(entry);
|
|
117928
119030
|
}
|
|
117929
119031
|
};
|
|
119032
|
+
async function dropLedger(scope) {
|
|
119033
|
+
const attempt = async (name) => {
|
|
119034
|
+
try {
|
|
119035
|
+
await storagePort.deleteFirstSeenLedger(name);
|
|
119036
|
+
return true;
|
|
119037
|
+
} catch {
|
|
119038
|
+
return false;
|
|
119039
|
+
}
|
|
119040
|
+
};
|
|
119041
|
+
const before = pendingLedgerDeletes.size;
|
|
119042
|
+
if (await attempt(scope))
|
|
119043
|
+
pendingLedgerDeletes.delete(scope);
|
|
119044
|
+
else
|
|
119045
|
+
pendingLedgerDeletes.add(scope);
|
|
119046
|
+
for (const other of [...pendingLedgerDeletes]) {
|
|
119047
|
+
if (other === scope)
|
|
119048
|
+
continue;
|
|
119049
|
+
const stillStored = state.entries.some((e10) => e10.scope === other);
|
|
119050
|
+
if (stillStored || await attempt(other))
|
|
119051
|
+
pendingLedgerDeletes.delete(other);
|
|
119052
|
+
}
|
|
119053
|
+
if (pendingLedgerDeletes.size !== before) {
|
|
119054
|
+
await persist().catch(() => void 0);
|
|
119055
|
+
}
|
|
119056
|
+
}
|
|
117930
119057
|
async function removeEntry(entry) {
|
|
119058
|
+
return withScopeLock(entry.scope, () => removeEntryLocked(entry));
|
|
119059
|
+
}
|
|
119060
|
+
async function removeEntryLocked(entry) {
|
|
117931
119061
|
const blobPath = envelopePath(entry.scope, entry.collectedAt);
|
|
117932
119062
|
await Promise.all([
|
|
117933
119063
|
fileStore.deleteEnvelope(blobPath),
|
|
@@ -117940,6 +119070,9 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117940
119070
|
entries: state.entries.filter((e10) => e10 !== entry)
|
|
117941
119071
|
};
|
|
117942
119072
|
await persist();
|
|
119073
|
+
if (!state.entries.some((e10) => e10.scope === entry.scope)) {
|
|
119074
|
+
await dropLedger(entry.scope);
|
|
119075
|
+
}
|
|
117943
119076
|
return true;
|
|
117944
119077
|
}
|
|
117945
119078
|
if (fileStore.readEnvelopePreview) {
|
|
@@ -117953,6 +119086,20 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
|
|
|
117953
119086
|
return preview;
|
|
117954
119087
|
};
|
|
117955
119088
|
}
|
|
119089
|
+
if (pendingLedgerDeletes.size > 0) {
|
|
119090
|
+
for (const scope of [...pendingLedgerDeletes]) {
|
|
119091
|
+
if (state.entries.some((e10) => e10.scope === scope)) {
|
|
119092
|
+
pendingLedgerDeletes.delete(scope);
|
|
119093
|
+
continue;
|
|
119094
|
+
}
|
|
119095
|
+
try {
|
|
119096
|
+
await storagePort.deleteFirstSeenLedger(scope);
|
|
119097
|
+
pendingLedgerDeletes.delete(scope);
|
|
119098
|
+
} catch {
|
|
119099
|
+
}
|
|
119100
|
+
}
|
|
119101
|
+
await persist().catch(() => void 0);
|
|
119102
|
+
}
|
|
117956
119103
|
return storagePort;
|
|
117957
119104
|
}
|
|
117958
119105
|
async function readPreviewFromFileStore(store, path, maxBytes) {
|
|
@@ -118341,7 +119488,7 @@ var KEYS_BY_TYPE = {
|
|
|
118341
119488
|
boolean: ["name", "type", "required"],
|
|
118342
119489
|
enum: ["name", "type", "required", "values"]
|
|
118343
119490
|
};
|
|
118344
|
-
function
|
|
119491
|
+
function isRecord6(value) {
|
|
118345
119492
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
118346
119493
|
}
|
|
118347
119494
|
function invalid(message, details) {
|
|
@@ -118402,7 +119549,7 @@ function parseEnumValues(value, index) {
|
|
|
118402
119549
|
return values;
|
|
118403
119550
|
}
|
|
118404
119551
|
function parseField(value, index) {
|
|
118405
|
-
if (!
|
|
119552
|
+
if (!isRecord6(value)) {
|
|
118406
119553
|
invalid(`answerShape.fields[${index}] must be an object`, { index });
|
|
118407
119554
|
}
|
|
118408
119555
|
const name = parseFieldName(value.name, index);
|
|
@@ -118458,7 +119605,7 @@ function parseField(value, index) {
|
|
|
118458
119605
|
function parseAnswerShapeInput(value) {
|
|
118459
119606
|
if (value === void 0 || value === null)
|
|
118460
119607
|
return null;
|
|
118461
|
-
if (!
|
|
119608
|
+
if (!isRecord6(value)) {
|
|
118462
119609
|
invalid("answerShape must be an object with a fields array", {});
|
|
118463
119610
|
}
|
|
118464
119611
|
for (const key of Object.keys(value)) {
|
|
@@ -118671,7 +119818,7 @@ var MAX_QUESTION_CHARS = 8e3;
|
|
|
118671
119818
|
var MAX_MODEL_CHARS = 128;
|
|
118672
119819
|
var MAX_ECHOED_SCOPE_CHARS = 128;
|
|
118673
119820
|
var MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
|
|
118674
|
-
function
|
|
119821
|
+
function isRecord7(value) {
|
|
118675
119822
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
118676
119823
|
}
|
|
118677
119824
|
function parseScope(value, field2) {
|
|
@@ -118687,7 +119834,7 @@ function parseScope(value, field2) {
|
|
|
118687
119834
|
return parsed.scope;
|
|
118688
119835
|
}
|
|
118689
119836
|
function parseQuestionInput(body) {
|
|
118690
|
-
if (!
|
|
119837
|
+
if (!isRecord7(body)) {
|
|
118691
119838
|
throw new DerivativeQuestionInvalidError("Body must be a JSON object");
|
|
118692
119839
|
}
|
|
118693
119840
|
const derivedScope = parseScope(body.derivedScope, "derivedScope");
|
|
@@ -118823,11 +119970,11 @@ var TIMESTAMP_KEYS = [
|
|
|
118823
119970
|
"published_at"
|
|
118824
119971
|
];
|
|
118825
119972
|
var RESERVED_KEYS = /* @__PURE__ */ new Set(["$lineage", "$writtenBy", "$binary"]);
|
|
118826
|
-
function
|
|
119973
|
+
function isRecord8(value) {
|
|
118827
119974
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
118828
119975
|
}
|
|
118829
119976
|
function timestampOf(item) {
|
|
118830
|
-
if (!
|
|
119977
|
+
if (!isRecord8(item))
|
|
118831
119978
|
return null;
|
|
118832
119979
|
for (const key of TIMESTAMP_KEYS) {
|
|
118833
119980
|
const value = item[key];
|
|
@@ -118868,7 +120015,7 @@ function trimSourceData(data, options = {}) {
|
|
|
118868
120015
|
total = 0;
|
|
118869
120016
|
if (Array.isArray(data))
|
|
118870
120017
|
return trimArray(data, limit2);
|
|
118871
|
-
if (
|
|
120018
|
+
if (isRecord8(data)) {
|
|
118872
120019
|
const stamped = "$lineage" in data;
|
|
118873
120020
|
const out = {};
|
|
118874
120021
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -118982,7 +120129,7 @@ function parseAnswer(content) {
|
|
|
118982
120129
|
for (const candidate of jsonFramings(content)) {
|
|
118983
120130
|
try {
|
|
118984
120131
|
const parsed = JSON.parse(candidate);
|
|
118985
|
-
if (
|
|
120132
|
+
if (isRecord8(parsed) && typeof parsed.answer === "string") {
|
|
118986
120133
|
return {
|
|
118987
120134
|
answer: parsed.answer,
|
|
118988
120135
|
evidence: typeof parsed.evidence === "string" ? parsed.evidence : null
|
|
@@ -119002,10 +120149,10 @@ function parseShapedAnswer(content) {
|
|
|
119002
120149
|
} catch {
|
|
119003
120150
|
continue;
|
|
119004
120151
|
}
|
|
119005
|
-
if (!
|
|
120152
|
+
if (!isRecord8(parsed))
|
|
119006
120153
|
continue;
|
|
119007
120154
|
const evidence = typeof parsed.evidence === "string" ? parsed.evidence : null;
|
|
119008
|
-
if (
|
|
120155
|
+
if (isRecord8(parsed.answer)) {
|
|
119009
120156
|
found.push({ answer: parsed.answer, evidence });
|
|
119010
120157
|
}
|
|
119011
120158
|
found.push({ answer: parsed, evidence });
|
|
@@ -119038,11 +120185,11 @@ var InferenceRequestError = class extends Error {
|
|
|
119038
120185
|
this.retryable = options.retryable;
|
|
119039
120186
|
}
|
|
119040
120187
|
};
|
|
119041
|
-
function
|
|
120188
|
+
function isRecord9(value) {
|
|
119042
120189
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
119043
120190
|
}
|
|
119044
120191
|
function readUsage(value) {
|
|
119045
|
-
if (!
|
|
120192
|
+
if (!isRecord9(value))
|
|
119046
120193
|
return void 0;
|
|
119047
120194
|
const num2 = (v10) => typeof v10 === "number" ? v10 : void 0;
|
|
119048
120195
|
const usage = {
|
|
@@ -119053,10 +120200,10 @@ function readUsage(value) {
|
|
|
119053
120200
|
return usage;
|
|
119054
120201
|
}
|
|
119055
120202
|
function readContent(body) {
|
|
119056
|
-
if (!
|
|
120203
|
+
if (!isRecord9(body) || !Array.isArray(body.choices))
|
|
119057
120204
|
return null;
|
|
119058
120205
|
const first = body.choices[0];
|
|
119059
|
-
if (!
|
|
120206
|
+
if (!isRecord9(first) || !isRecord9(first.message))
|
|
119060
120207
|
return null;
|
|
119061
120208
|
const index = typeof first.index === "number" ? first.index : 0;
|
|
119062
120209
|
const field2 = `choices.${index}.message.content`;
|
|
@@ -119065,7 +120212,7 @@ function readContent(body) {
|
|
|
119065
120212
|
if (typeof content === "string")
|
|
119066
120213
|
return { content, field: field2, id: id2 };
|
|
119067
120214
|
if (Array.isArray(content)) {
|
|
119068
|
-
const text = content.map((part) =>
|
|
120215
|
+
const text = content.map((part) => isRecord9(part) && typeof part.text === "string" ? part.text : "").join("");
|
|
119069
120216
|
return { content: text, field: field2, id: id2 };
|
|
119070
120217
|
}
|
|
119071
120218
|
return null;
|
|
@@ -119073,7 +120220,7 @@ function readContent(body) {
|
|
|
119073
120220
|
async function readErrorType(response) {
|
|
119074
120221
|
try {
|
|
119075
120222
|
const body = await response.json();
|
|
119076
|
-
if (
|
|
120223
|
+
if (isRecord9(body) && isRecord9(body.error)) {
|
|
119077
120224
|
return typeof body.error.type === "string" ? body.error.type : null;
|
|
119078
120225
|
}
|
|
119079
120226
|
} catch {
|
|
@@ -119181,7 +120328,7 @@ function createOpenAiCompatibleInferenceProvider(options = {}) {
|
|
|
119181
120328
|
ok: true,
|
|
119182
120329
|
result: {
|
|
119183
120330
|
content,
|
|
119184
|
-
usage: readUsage(
|
|
120331
|
+
usage: readUsage(isRecord9(parsed) ? parsed.usage : void 0),
|
|
119185
120332
|
...receiptId ? { receiptId } : {},
|
|
119186
120333
|
...aciIdentity ? { aciIdentity } : {}
|
|
119187
120334
|
}
|
|
@@ -119214,7 +120361,7 @@ function isRetryableInferenceError(err2) {
|
|
|
119214
120361
|
}
|
|
119215
120362
|
async function withRetries(deps, attempt, retryable) {
|
|
119216
120363
|
const delays = deps.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
|
|
119217
|
-
const sleep2 = deps.sleep ?? ((
|
|
120364
|
+
const sleep2 = deps.sleep ?? ((ms4) => new Promise((r10) => setTimeout(r10, ms4)));
|
|
119218
120365
|
for (let index = 0; ; index += 1) {
|
|
119219
120366
|
try {
|
|
119220
120367
|
return await attempt();
|
|
@@ -119592,7 +120739,7 @@ function isTransientFailureOutcome(outcome) {
|
|
|
119592
120739
|
return shaped.status === "failed" && shaped.registration?.errorCode === "inference_unavailable";
|
|
119593
120740
|
}
|
|
119594
120741
|
var defaultTimers = {
|
|
119595
|
-
setTimeout: (callback,
|
|
120742
|
+
setTimeout: (callback, ms4) => setTimeout(callback, ms4),
|
|
119596
120743
|
clearTimeout: (handle) => clearTimeout(handle)
|
|
119597
120744
|
};
|
|
119598
120745
|
function createRecomputeScheduler(options) {
|
|
@@ -120287,25 +121434,25 @@ var E2eeAttestationError = class extends Error {
|
|
|
120287
121434
|
this.name = "E2eeAttestationError";
|
|
120288
121435
|
}
|
|
120289
121436
|
};
|
|
120290
|
-
function
|
|
121437
|
+
function isRecord10(value) {
|
|
120291
121438
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
120292
121439
|
}
|
|
120293
|
-
async function
|
|
121440
|
+
async function sha256Hex3(bytes2) {
|
|
120294
121441
|
const buffer = new ArrayBuffer(bytes2.byteLength);
|
|
120295
121442
|
new Uint8Array(buffer).set(bytes2);
|
|
120296
121443
|
const digest2 = await globalThis.crypto.subtle.digest("SHA-256", buffer);
|
|
120297
121444
|
return bytesToHex6(new Uint8Array(digest2));
|
|
120298
121445
|
}
|
|
120299
121446
|
async function workloadKeysetDigest(keyset) {
|
|
120300
|
-
return `sha256:${await
|
|
121447
|
+
return `sha256:${await sha256Hex3(canonicalJsonBytes(keyset))}`;
|
|
120301
121448
|
}
|
|
120302
121449
|
async function reportDataFor(keysetDigest, nonce) {
|
|
120303
121450
|
const nonceJson = nonce === null ? "null" : `"${nonce}"`;
|
|
120304
121451
|
const statement = `{"keyset_digest":"${keysetDigest}","nonce":${nonceJson},"purpose":"${ACI_REPORT_DATA_PURPOSE}"}`;
|
|
120305
|
-
return
|
|
121452
|
+
return sha256Hex3(new TextEncoder().encode(statement));
|
|
120306
121453
|
}
|
|
120307
121454
|
function parseReport(body) {
|
|
120308
|
-
if (!
|
|
121455
|
+
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)) {
|
|
120309
121456
|
throw new E2eeAttestationError("malformed_report", "attestation report is missing required fields");
|
|
120310
121457
|
}
|
|
120311
121458
|
const keyset = body.attestation.workload_keyset;
|
|
@@ -120352,7 +121499,7 @@ async function verifyAciReportBinding(report, nonce, nowSeconds) {
|
|
|
120352
121499
|
}
|
|
120353
121500
|
function selectX25519Key(keyset, expectedKeyId) {
|
|
120354
121501
|
for (const entry of keyset.e2ee_public_keys) {
|
|
120355
|
-
if (!
|
|
121502
|
+
if (!isRecord10(entry) || entry.algo !== E2EE_ALGO_X25519)
|
|
120356
121503
|
continue;
|
|
120357
121504
|
if (typeof entry.public_key !== "string")
|
|
120358
121505
|
continue;
|
|
@@ -122912,7 +124059,7 @@ var objectToNumericMapAsync = async (object3) => {
|
|
|
122912
124059
|
}
|
|
122913
124060
|
return map2;
|
|
122914
124061
|
};
|
|
122915
|
-
var wait = (
|
|
124062
|
+
var wait = (ms4) => new Promise((resolve) => setTimeout(resolve, ms4));
|
|
122916
124063
|
var SPACE_OR_PUNCTUATION = /[\n\r\p{Z}\p{P}]+/u;
|
|
122917
124064
|
|
|
122918
124065
|
// ../core/dist/mcp/search/index.js
|
|
@@ -137148,6 +138295,11 @@ async function downloadOne(deps, record2) {
|
|
|
137148
138295
|
throw err2;
|
|
137149
138296
|
}
|
|
137150
138297
|
diagnostics?.onIndexEnd(record2.id, envelope.scope);
|
|
138298
|
+
await recordStoredVersion(storage, {
|
|
138299
|
+
scope: envelope.scope,
|
|
138300
|
+
collectedAt: envelope.collectedAt,
|
|
138301
|
+
data: envelope.data
|
|
138302
|
+
});
|
|
137151
138303
|
logger.info({ dataPointId: record2.id, scope: envelope.scope, path: relativePath }, "Downloaded and indexed data point");
|
|
137152
138304
|
if (deps.onDataPointIndexed) {
|
|
137153
138305
|
try {
|
|
@@ -137318,6 +138470,12 @@ async function reconcileDeletedDataPoint(deps, record2, deletedAt) {
|
|
|
137318
138470
|
if (orphanKeys.length > 0 && deps.pendingBlobDeletions) {
|
|
137319
138471
|
await deps.pendingBlobDeletions.add(orphanKeys);
|
|
137320
138472
|
}
|
|
138473
|
+
if (removed > 0 || kept === 0) {
|
|
138474
|
+
try {
|
|
138475
|
+
await storage.deleteFirstSeenLedger?.(record2.scope);
|
|
138476
|
+
} catch {
|
|
138477
|
+
}
|
|
138478
|
+
}
|
|
137321
138479
|
if (removed > 0 || kept > 0) {
|
|
137322
138480
|
logger.info({ dataPointId: record2.id, scope: record2.scope, deletedAt, removed, kept }, "Reconciled gateway deletion against local index");
|
|
137323
138481
|
}
|