@opendatalabs/personal-server-ts-lite 1.34.1 → 1.35.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/additions-crypto.d.ts +1 -1
- package/dist/additions-crypto.d.ts.map +1 -1
- package/dist/additions-crypto.js +16 -6
- package/dist/additions-crypto.js.map +1 -1
- package/dist/additions-protocol.d.ts +9 -1
- package/dist/additions-protocol.d.ts.map +1 -1
- package/dist/additions-protocol.js.map +1 -1
- package/dist/additions-session.d.ts +2 -0
- package/dist/additions-session.d.ts.map +1 -1
- package/dist/additions-session.js +29 -4
- package/dist/additions-session.js.map +1 -1
- package/dist/additions-transport.d.ts +10 -2
- package/dist/additions-transport.d.ts.map +1 -1
- package/dist/additions-transport.js +143 -48
- package/dist/additions-transport.js.map +1 -1
- package/dist/additions-worker.bundle.js +538 -101
- package/dist/additions-worker.js +45 -24
- package/dist/additions-worker.js.map +1 -1
- package/dist/browser-runtime.d.ts +23 -0
- package/dist/browser-runtime.d.ts.map +1 -1
- package/dist/browser-runtime.js +38 -1
- package/dist/browser-runtime.js.map +1 -1
- package/dist/canonical-persistence.d.ts +53 -0
- package/dist/canonical-persistence.d.ts.map +1 -0
- package/dist/canonical-persistence.js +13 -0
- package/dist/canonical-persistence.js.map +1 -0
- package/dist/canonical-store.d.ts +395 -0
- package/dist/canonical-store.d.ts.map +1 -0
- package/dist/canonical-store.js +1807 -0
- package/dist/canonical-store.js.map +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +154 -1
- package/dist/client.js.map +1 -1
- package/dist/diagnostics.d.ts +3 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +9 -1
- package/dist/diagnostics.js.map +1 -1
- package/dist/history-probe-worker.bundle.js +31216 -0
- package/dist/history-probe.worker.d.ts +35 -0
- package/dist/history-probe.worker.d.ts.map +1 -0
- package/dist/history-probe.worker.js +160 -0
- package/dist/history-probe.worker.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-store.d.ts.map +1 -1
- package/dist/mcp-store.js +109 -19
- package/dist/mcp-store.js.map +1 -1
- package/dist/oura-import.d.ts +2 -0
- package/dist/oura-import.d.ts.map +1 -0
- package/dist/oura-import.js +3 -0
- package/dist/oura-import.js.map +1 -0
- package/dist/replication-coordinator-state.d.ts +19 -0
- package/dist/replication-coordinator-state.d.ts.map +1 -0
- package/dist/replication-coordinator-state.js +20 -0
- package/dist/replication-coordinator-state.js.map +1 -0
- package/dist/replication-door.d.ts +17 -0
- package/dist/replication-door.d.ts.map +1 -0
- package/dist/replication-door.js +23 -0
- package/dist/replication-door.js.map +1 -0
- package/dist/replication-engine.d.ts +49 -0
- package/dist/replication-engine.d.ts.map +1 -0
- package/dist/replication-engine.js +589 -0
- package/dist/replication-engine.js.map +1 -0
- package/dist/replication-host.d.ts +92 -0
- package/dist/replication-host.d.ts.map +1 -0
- package/dist/replication-host.js +135 -0
- package/dist/replication-host.js.map +1 -0
- package/dist/replication-ports.d.ts +194 -0
- package/dist/replication-ports.d.ts.map +1 -0
- package/dist/replication-ports.js +58 -0
- package/dist/replication-ports.js.map +1 -0
- package/dist/replication-runtime.d.ts +64 -0
- package/dist/replication-runtime.d.ts.map +1 -0
- package/dist/replication-runtime.js +79 -0
- package/dist/replication-runtime.js.map +1 -0
- package/dist/replication-storage.d.ts +42 -0
- package/dist/replication-storage.d.ts.map +1 -0
- package/dist/replication-storage.js +173 -0
- package/dist/replication-storage.js.map +1 -0
- package/dist/runtime.d.ts +20 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +80 -1
- package/dist/runtime.js.map +1 -1
- package/dist/state.d.ts +1 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/storage.d.ts +17 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +367 -142
- package/dist/storage.js.map +1 -1
- package/dist/sync.d.ts +8 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +25 -7
- package/dist/sync.js.map +1 -1
- package/package.json +8 -4
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createReplicationDriver, } from "@opendatalabs/personal-server-ts-core/replication/host-driver";
|
|
2
|
+
import { replicationBootConfigProblem, } from "./replication-ports.js";
|
|
3
|
+
/** How long a pause waits for an aborted step before reporting it stuck. */
|
|
4
|
+
export const LITE_REPLICATION_PAUSE_GRACE_MS = 2_000;
|
|
5
|
+
/**
|
|
6
|
+
* Build the runtime for one boot. With the door anything but `on`, or no
|
|
7
|
+
* boot config or `enabled: false`, it is inert: no engine runs and `status`
|
|
8
|
+
* says why.
|
|
9
|
+
*/
|
|
10
|
+
export function createLiteReplicationRuntime(input) {
|
|
11
|
+
const inert = (status) => ({
|
|
12
|
+
status: () => status,
|
|
13
|
+
trigger: async () => undefined,
|
|
14
|
+
wake: () => { },
|
|
15
|
+
localWrite: () => { },
|
|
16
|
+
resume: () => { },
|
|
17
|
+
pause: async () => { },
|
|
18
|
+
stop: async () => true,
|
|
19
|
+
});
|
|
20
|
+
if (input.door.state === "refused")
|
|
21
|
+
return inert({ state: "refused", refusal: input.door.refusal });
|
|
22
|
+
if (input.door.state !== "on" || !input.config?.enabled)
|
|
23
|
+
return inert({ state: "off" });
|
|
24
|
+
const problem = replicationBootConfigProblem(input.config);
|
|
25
|
+
if (problem)
|
|
26
|
+
return inert({ state: "blocked", reason: problem });
|
|
27
|
+
if (!input.engine)
|
|
28
|
+
return inert({ state: "blocked", reason: "no_engine" });
|
|
29
|
+
const { step } = input.config.limits;
|
|
30
|
+
const driver = createReplicationDriver({
|
|
31
|
+
stepper: input.engine,
|
|
32
|
+
budget: { units: step.units, bytes: step.bytes },
|
|
33
|
+
deadlineMs: step.deadlineMs,
|
|
34
|
+
timers: input.timers,
|
|
35
|
+
onReport: input.onReport,
|
|
36
|
+
onError: input.onError,
|
|
37
|
+
});
|
|
38
|
+
// Every stop still settling. A queued resume waits for all of them: an
|
|
39
|
+
// older, longer stop would otherwise stop the driver the resume restarted.
|
|
40
|
+
const pausing = new Set();
|
|
41
|
+
// Bumped synchronously by every resume, pause and stop. A resume queued
|
|
42
|
+
// behind a pause starts only if no later call has superseded it.
|
|
43
|
+
let lifecycle = 0;
|
|
44
|
+
return {
|
|
45
|
+
status() {
|
|
46
|
+
const { state, ...rest } = driver.status();
|
|
47
|
+
return { state: state === "running" ? "on" : "paused", ...rest };
|
|
48
|
+
},
|
|
49
|
+
trigger: () => driver.trigger(),
|
|
50
|
+
wake: (dependency) => driver.wake(dependency),
|
|
51
|
+
localWrite: () => driver.localWrite(),
|
|
52
|
+
resume() {
|
|
53
|
+
const mine = ++lifecycle;
|
|
54
|
+
// A resume during a pause waits for it, so the old step settles first.
|
|
55
|
+
if (pausing.size)
|
|
56
|
+
void Promise.allSettled([...pausing]).then(() => {
|
|
57
|
+
if (mine === lifecycle)
|
|
58
|
+
driver.start();
|
|
59
|
+
});
|
|
60
|
+
else
|
|
61
|
+
driver.start();
|
|
62
|
+
},
|
|
63
|
+
async pause() {
|
|
64
|
+
await this.stop(LITE_REPLICATION_PAUSE_GRACE_MS);
|
|
65
|
+
},
|
|
66
|
+
async stop(graceMs) {
|
|
67
|
+
lifecycle++;
|
|
68
|
+
const stopping = driver.stop(graceMs);
|
|
69
|
+
pausing.add(stopping);
|
|
70
|
+
try {
|
|
71
|
+
return await stopping;
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
pausing.delete(stopping);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=replication-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replication-runtime.js","sourceRoot":"","sources":["../src/replication-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type BoundedStorageAdapter } from "@opendatalabs/personal-server-ts-core/storage/adapters";
|
|
2
|
+
import { type LiteReplicaObjectTransfers, type LiteReplicaPersistence, type LiteReplicaTransaction } from "./replication-ports.js";
|
|
3
|
+
/** Deadline of one transfer when the caller's budget sets none. */
|
|
4
|
+
export declare const LITE_REPLICA_TRANSFER_DEADLINE_MS = 60000;
|
|
5
|
+
/**
|
|
6
|
+
* Replica bytes this adapter attached and has not released yet. A row
|
|
7
|
+
* commits with the attach and leaves with the release, so bytes a crash
|
|
8
|
+
* left attached between them stay listed until the engine reclaims them
|
|
9
|
+
* (`reclaimLiteTransientBytes`).
|
|
10
|
+
*/
|
|
11
|
+
export declare const LITE_REPLICA_TRANSIENT_MIGRATION = "CREATE TABLE IF NOT EXISTS pdpp_lite_replica_transient (id TEXT PRIMARY KEY)";
|
|
12
|
+
/**
|
|
13
|
+
* Attached replica byte ids whose transfer this process still runs. A
|
|
14
|
+
* cancelled step stops waiting for its transfer before the native call
|
|
15
|
+
* settles, so the next step can start while the bytes are still in use; the
|
|
16
|
+
* transfer releases them itself when it settles.
|
|
17
|
+
*/
|
|
18
|
+
export type LiteTransientBytesInUse = Set<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Release every transient replica byte left attached, in the caller's
|
|
21
|
+
* transaction, except those `inUse`. The engine calls it under its writer
|
|
22
|
+
* lock, before a step's first transfer.
|
|
23
|
+
*/
|
|
24
|
+
export declare function reclaimLiteTransientBytes(tx: LiteReplicaTransaction, inUse?: ReadonlySet<string>): Promise<number>;
|
|
25
|
+
/** Headers for one upload, computed over its exact body before it is staged. */
|
|
26
|
+
export type LiteReplicaUploadHeaders = (request: {
|
|
27
|
+
method: "PUT";
|
|
28
|
+
url: string;
|
|
29
|
+
body: Uint8Array;
|
|
30
|
+
}) => Record<string, string> | Promise<Record<string, string>>;
|
|
31
|
+
export declare function createLiteReplicaStorage(input: {
|
|
32
|
+
persistence: LiteReplicaPersistence;
|
|
33
|
+
transfers: LiteReplicaObjectTransfers;
|
|
34
|
+
/** The object URL of a storage key (the inverse of the storage layout). */
|
|
35
|
+
urlForKey(key: string): string;
|
|
36
|
+
/** Upload headers, e.g. storage authorization over the exact body. */
|
|
37
|
+
headers?: LiteReplicaUploadHeaders;
|
|
38
|
+
deadlineMs?: number;
|
|
39
|
+
/** Shared with the engine's reclaim (`reclaimLiteTransientBytes`). */
|
|
40
|
+
inUse?: LiteTransientBytesInUse;
|
|
41
|
+
}): BoundedStorageAdapter;
|
|
42
|
+
//# sourceMappingURL=replication-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replication-storage.d.ts","sourceRoot":"","sources":["../src/replication-storage.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,wDAAwD,CAAC;AAChE,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,wBAAwB,CAAC;AAGhC,mEAAmE;AACnE,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAQxD;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,iFACmC,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;AAElD;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,sBAAsB,EAC1B,KAAK,GAAE,WAAW,CAAC,MAAM,CAAa,mBAkBvC;AAED,gFAAgF;AAChF,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,KAAK,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;CAClB,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAQ/D,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,WAAW,EAAE,sBAAsB,CAAC;IACpC,SAAS,EAAE,0BAA0B,CAAC;IACtC,2EAA2E;IAC3E,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,sEAAsE;IACtE,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC,GAAG,qBAAqB,CAoIxB"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replica object storage over the native transfers (host contract §4.2), as
|
|
3
|
+
* the storage adapter core's DPv2 replica transport (`replication/dpv2.ts`)
|
|
4
|
+
* takes. Bulk bytes move natively and land in replica byte storage; JS sees
|
|
5
|
+
* only what one fragment or manifest read needs. Gateway calls (register,
|
|
6
|
+
* evidence, owner feed) stay in PS JS core over Lite's HTTP client.
|
|
7
|
+
*/
|
|
8
|
+
import { sha256 } from "viem";
|
|
9
|
+
import { AdditionsBudgetExceeded, } from "@opendatalabs/personal-server-ts-core/additions";
|
|
10
|
+
import { StoredBlobConflictError, } from "@opendatalabs/personal-server-ts-core/storage/adapters";
|
|
11
|
+
import { LiteReplicaTransferError, } from "./replication-ports.js";
|
|
12
|
+
const FRAME_BYTES = 128 * 1024;
|
|
13
|
+
/** Deadline of one transfer when the caller's budget sets none. */
|
|
14
|
+
export const LITE_REPLICA_TRANSFER_DEADLINE_MS = 60_000;
|
|
15
|
+
function* frames(bytes) {
|
|
16
|
+
if (bytes.length === 0)
|
|
17
|
+
yield new Uint8Array(0);
|
|
18
|
+
for (let i = 0; i < bytes.length; i += FRAME_BYTES)
|
|
19
|
+
yield bytes.subarray(i, i + FRAME_BYTES);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Replica bytes this adapter attached and has not released yet. A row
|
|
23
|
+
* commits with the attach and leaves with the release, so bytes a crash
|
|
24
|
+
* left attached between them stay listed until the engine reclaims them
|
|
25
|
+
* (`reclaimLiteTransientBytes`).
|
|
26
|
+
*/
|
|
27
|
+
export const LITE_REPLICA_TRANSIENT_MIGRATION = "CREATE TABLE IF NOT EXISTS pdpp_lite_replica_transient (id TEXT PRIMARY KEY)";
|
|
28
|
+
/**
|
|
29
|
+
* Release every transient replica byte left attached, in the caller's
|
|
30
|
+
* transaction, except those `inUse`. The engine calls it under its writer
|
|
31
|
+
* lock, before a step's first transfer.
|
|
32
|
+
*/
|
|
33
|
+
export async function reclaimLiteTransientBytes(tx, inUse = new Set()) {
|
|
34
|
+
await tx.sql.exec(LITE_REPLICA_TRANSIENT_MIGRATION);
|
|
35
|
+
const rows = await tx.sql.all("SELECT id FROM pdpp_lite_replica_transient", []);
|
|
36
|
+
let released = 0;
|
|
37
|
+
for (const row of rows) {
|
|
38
|
+
const id = row.id;
|
|
39
|
+
if (inUse.has(id))
|
|
40
|
+
continue;
|
|
41
|
+
await tx.releaseBytes(id);
|
|
42
|
+
await tx.sql.run("DELETE FROM pdpp_lite_replica_transient WHERE id=?", [
|
|
43
|
+
id,
|
|
44
|
+
]);
|
|
45
|
+
released += 1;
|
|
46
|
+
}
|
|
47
|
+
return released;
|
|
48
|
+
}
|
|
49
|
+
/** A storage failure the DPv2 transport reads as definitive absence. */
|
|
50
|
+
const notFound = (url) => Object.assign(new Error(`replica object not found: ${url}`), {
|
|
51
|
+
status: 404,
|
|
52
|
+
});
|
|
53
|
+
export function createLiteReplicaStorage(input) {
|
|
54
|
+
const { persistence, transfers } = input;
|
|
55
|
+
const inUse = input.inUse ?? new Set();
|
|
56
|
+
const deadline = (budget) => Math.max(1, Math.min(input.deadlineMs ?? LITE_REPLICA_TRANSFER_DEADLINE_MS, budget?.remainingMilliseconds ?? Infinity));
|
|
57
|
+
/** Marks `id` in use until `release`, so no reclaim takes it meanwhile. */
|
|
58
|
+
const attach = async (id, length, digest) => {
|
|
59
|
+
inUse.add(id);
|
|
60
|
+
try {
|
|
61
|
+
await persistence.transaction(async (tx) => {
|
|
62
|
+
await tx.sql.exec(LITE_REPLICA_TRANSIENT_MIGRATION);
|
|
63
|
+
await tx.attachBytes(id, { length, sha256: digest });
|
|
64
|
+
await tx.sql.run("INSERT OR IGNORE INTO pdpp_lite_replica_transient (id) VALUES (?)", [id]);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
inUse.delete(id);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const release = async (id) => {
|
|
73
|
+
try {
|
|
74
|
+
await persistence.transaction(async (tx) => {
|
|
75
|
+
await tx.releaseBytes(id);
|
|
76
|
+
await tx.sql.run("DELETE FROM pdpp_lite_replica_transient WHERE id=?", [
|
|
77
|
+
id,
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
inUse.delete(id);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
async function read(id) {
|
|
86
|
+
const parts = [];
|
|
87
|
+
let size = 0;
|
|
88
|
+
for await (const part of persistence.readBytes(id)) {
|
|
89
|
+
parts.push(part);
|
|
90
|
+
size += part.length;
|
|
91
|
+
}
|
|
92
|
+
const bytes = new Uint8Array(size);
|
|
93
|
+
let offset = 0;
|
|
94
|
+
for (const part of parts) {
|
|
95
|
+
bytes.set(part, offset);
|
|
96
|
+
offset += part.length;
|
|
97
|
+
}
|
|
98
|
+
return bytes;
|
|
99
|
+
}
|
|
100
|
+
const unsupported = () => {
|
|
101
|
+
throw new Error("Lite replica storage supports bounded reads only");
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
urlForKey: (key) => input.urlForKey(key),
|
|
105
|
+
/**
|
|
106
|
+
* Write-once: the native upload of different bytes to a stored key
|
|
107
|
+
* fails with HTTP 409, which is `StoredBlobConflictError`.
|
|
108
|
+
*/
|
|
109
|
+
async upload(key, data, signal) {
|
|
110
|
+
const url = input.urlForKey(key);
|
|
111
|
+
const headers = (await input.headers?.({ method: "PUT", url, body: data })) ?? {};
|
|
112
|
+
const id = await persistence.stageBytes((async function* () {
|
|
113
|
+
yield* frames(data);
|
|
114
|
+
})());
|
|
115
|
+
await attach(id, data.length, sha256(data).slice(2));
|
|
116
|
+
try {
|
|
117
|
+
await transfers.upload({ url, method: "PUT", headers, bytesId: id }, {
|
|
118
|
+
signal: signal ?? new AbortController().signal,
|
|
119
|
+
deadlineMs: deadline(),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof LiteReplicaTransferError &&
|
|
124
|
+
error.code === "http-status" &&
|
|
125
|
+
/\b409\b/.test(error.message))
|
|
126
|
+
throw new StoredBlobConflictError(key);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
await release(id);
|
|
131
|
+
}
|
|
132
|
+
return url;
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* At most `budget.remaining` bytes. A spent budget only probes: a present
|
|
136
|
+
* object is over budget, a missing one is not found.
|
|
137
|
+
*/
|
|
138
|
+
async downloadBounded(url, budget) {
|
|
139
|
+
const signal = budget.signal ?? new AbortController().signal;
|
|
140
|
+
const call = { signal, deadlineMs: deadline(budget) };
|
|
141
|
+
if (budget.remaining <= 0) {
|
|
142
|
+
if (!(await transfers.probe({ url }, call)))
|
|
143
|
+
throw notFound(url);
|
|
144
|
+
throw new AdditionsBudgetExceeded("replica object exceeds budget");
|
|
145
|
+
}
|
|
146
|
+
let staged;
|
|
147
|
+
try {
|
|
148
|
+
staged = await transfers.download({ url, maxBytes: budget.remaining }, call);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (error instanceof LiteReplicaTransferError) {
|
|
152
|
+
if (error.code === "not-found")
|
|
153
|
+
throw notFound(url);
|
|
154
|
+
if (error.code === "too-large")
|
|
155
|
+
throw new AdditionsBudgetExceeded("replica object exceeds budget");
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
budget.recordSpent(staged.length);
|
|
160
|
+
await attach(staged.stagingId, staged.length, staged.sha256);
|
|
161
|
+
try {
|
|
162
|
+
return await read(staged.stagingId);
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
await release(staged.stagingId);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
download: unsupported,
|
|
169
|
+
delete: unsupported,
|
|
170
|
+
exists: unsupported,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=replication-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replication-storage.js","sourceRoot":"","sources":["../src/replication-storage.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { DurableAdditionsService } from "@opendatalabs/personal-server-ts-core/additions";
|
|
2
2
|
import { type LegacyProjectionIssue } from "@opendatalabs/personal-server-ts-core/storage/legacy-projection";
|
|
3
3
|
import { type SessionTokenVerifierPort } from "@opendatalabs/personal-server-ts-core/auth";
|
|
4
|
-
import { type PersonalServerApiAuthPort, type PersonalServerReadAuthInput, type PersonalServerReadAuthResult, type PersonalServerReadFulfillmentReporter } from "@opendatalabs/personal-server-ts-core/api";
|
|
4
|
+
import { type PersonalServerApiAuthPort, type PersonalServerApiLogger, type PersonalServerReadAuthInput, type PersonalServerReadAuthResult, type PersonalServerReadFulfillmentReporter, type PreparedScopeUploadBatch } from "@opendatalabs/personal-server-ts-core/api";
|
|
5
5
|
import { type QuestionStore, type RecomputeScheduler } from "@opendatalabs/personal-server-ts-core/derivatives";
|
|
6
6
|
import type { LineageGatewayPort } from "@opendatalabs/personal-server-ts-core/lineage";
|
|
7
7
|
import { type DataListPolicyPorts, type DataWritePolicyPorts } from "@opendatalabs/personal-server-ts-core/policy";
|
|
@@ -14,13 +14,21 @@ import type { AccessLogReader } from "@opendatalabs/personal-server-ts-core/logg
|
|
|
14
14
|
import type { ServerSigner } from "@opendatalabs/personal-server-ts-core/signing";
|
|
15
15
|
import type { SyncManager } from "@opendatalabs/personal-server-ts-core/sync";
|
|
16
16
|
import { type McpConnectionStore, type McpOAuthAuthorizationStore, type McpScopeRequestApprovalUrlHook } from "@opendatalabs/personal-server-ts-core/mcp";
|
|
17
|
+
import type { LiteReplicationRuntime } from "./replication-runtime.js";
|
|
17
18
|
import { DiagnosticsRecorder } from "./diagnostics.js";
|
|
18
19
|
export interface PsLiteStorageAdapter {
|
|
19
20
|
kind: "indexeddb" | "opfs" | "custom";
|
|
20
21
|
}
|
|
21
22
|
export type PsLiteReadAuthInput = PersonalServerReadAuthInput;
|
|
22
23
|
export type PsLiteReadAuthResult = PersonalServerReadAuthResult;
|
|
23
|
-
export
|
|
24
|
+
export interface PsLiteAuthAdapter extends PersonalServerApiAuthPort {
|
|
25
|
+
/**
|
|
26
|
+
* Opt in only when owner authorization does not interpret application body
|
|
27
|
+
* fields. Direct uploads authenticate a digest commitment instead of items.
|
|
28
|
+
* Existing/custom adapters without this flag retain their HTTP body contract.
|
|
29
|
+
*/
|
|
30
|
+
supportsScopeUploadCommitments?: true;
|
|
31
|
+
}
|
|
24
32
|
export interface PsLiteRuntimeOptions {
|
|
25
33
|
storage: PsLiteStorageAdapter | DataStoragePort;
|
|
26
34
|
auth?: PsLiteAuthAdapter;
|
|
@@ -53,6 +61,8 @@ export interface PsLiteRuntimeOptions {
|
|
|
53
61
|
* alongside the sync manager, which keeps it current.
|
|
54
62
|
*/
|
|
55
63
|
scopeDeletions?: ScopeDeletionTracker;
|
|
64
|
+
/** Receives the cause of every 500 the runtime answers. */
|
|
65
|
+
logger?: PersonalServerApiLogger;
|
|
56
66
|
additions?: DurableAdditionsService;
|
|
57
67
|
accessLogReader?: AccessLogReader;
|
|
58
68
|
accessLogWriter?: AccessLogWriter;
|
|
@@ -125,6 +135,12 @@ export interface PsLiteRuntimeOptions {
|
|
|
125
135
|
* returns a structured snapshot useful for debugging stuck approval pages.
|
|
126
136
|
*/
|
|
127
137
|
diagnostics?: DiagnosticsRecorder;
|
|
138
|
+
/**
|
|
139
|
+
* Record replication (host contract §4.4). `activate` resumes it and
|
|
140
|
+
* `deactivate` pauses it; owner-only `GET /v1/replication/status` and
|
|
141
|
+
* `POST /v1/replication/sync` expose it. Absent means off.
|
|
142
|
+
*/
|
|
143
|
+
replication?: LiteReplicationRuntime;
|
|
128
144
|
/**
|
|
129
145
|
* Called when a legacy scope cannot be projected from stored PDPP records
|
|
130
146
|
* (the stored body is then served) or is projected with rows left out.
|
|
@@ -151,6 +167,8 @@ export interface PsLiteRuntime extends RuntimeAvailabilityPort {
|
|
|
151
167
|
activate(): void;
|
|
152
168
|
deactivate(): void;
|
|
153
169
|
fetch(request: Request): Promise<Response>;
|
|
170
|
+
/** Optional direct bulk transport; older/custom runtimes keep HTTP. */
|
|
171
|
+
appendScopeUpload?(request: Request, batch: PreparedScopeUploadBatch): Promise<Response>;
|
|
154
172
|
}
|
|
155
173
|
/**
|
|
156
174
|
* Delegated-write (Write API) wiring for a PS-Lite auth adapter.
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { importOuraBrowserRecords } from "./oura-import.js";
|
|
1
2
|
import { withLegacyProjection, } from "@opendatalabs/personal-server-ts-core/storage/legacy-projection";
|
|
2
3
|
import { GrantRequiredError, InvalidSignatureError, MissingAuthError, NotOwnerError, ProtocolError, PsUnavailableError, } from "@opendatalabs/personal-server-ts-core/errors";
|
|
3
4
|
import { authenticateRequest, } from "@opendatalabs/personal-server-ts-core/auth";
|
|
4
5
|
import { approveDeviceSessionContract, createMemoryDeviceSessionStore, initiateDeviceSessionContract, pollDeviceSessionContract, provisionDeviceTokenContract, revokeDeviceTokenContract, } from "@opendatalabs/personal-server-ts-core/contracts";
|
|
5
|
-
import { handlePersonalServerAccessLogsRequest, handlePersonalServerConfigRequest, handlePersonalServerDataRequest, handlePersonalServerGrantsRequest, handlePersonalServerOauthTokenRequest, handlePersonalServerSyncRequest, } from "@opendatalabs/personal-server-ts-core/api";
|
|
6
|
+
import { handlePersonalServerAccessLogsRequest, handlePersonalServerConfigRequest, handlePersonalServerDataRequest, handlePersonalServerScopeUploadAppend, createScopeUploadRegistry, handleOuraCollectionRequirementsRequest, handlePersonalServerGrantsRequest, handlePersonalServerOauthTokenRequest, handlePersonalServerSyncRequest, } from "@opendatalabs/personal-server-ts-core/api";
|
|
6
7
|
import { handlePersonalServerDerivativesRequest, } from "@opendatalabs/personal-server-ts-core/derivatives";
|
|
7
8
|
import { resolveDataListGrantScopes, verifyDataReadPolicy, } from "@opendatalabs/personal-server-ts-core/policy";
|
|
8
9
|
import { createInMemoryWriteProofReplayStore, createWriteSessionAuthorization, handleWriteSessionRequest, } from "@opendatalabs/personal-server-ts-core/write";
|
|
@@ -164,6 +165,7 @@ export function createBearerTokenPsLiteAuth(options) {
|
|
|
164
165
|
assertBearerToken(request, options.ownerToken, true);
|
|
165
166
|
};
|
|
166
167
|
return {
|
|
168
|
+
supportsScopeUploadCommitments: true,
|
|
167
169
|
authorizeOwner,
|
|
168
170
|
...(options.writeSessions
|
|
169
171
|
? writeSessionAuthMethods(options.writeSessions, authorizeOwner)
|
|
@@ -226,6 +228,7 @@ export function createWeb3SignedPsLiteAuth(options) {
|
|
|
226
228
|
}
|
|
227
229
|
};
|
|
228
230
|
return {
|
|
231
|
+
supportsScopeUploadCommitments: true,
|
|
229
232
|
authorizeOwner,
|
|
230
233
|
...(options.writeSessions
|
|
231
234
|
? writeSessionAuthMethods({
|
|
@@ -344,6 +347,11 @@ export function createPsLiteRuntime(options) {
|
|
|
344
347
|
const dataStorage = withLegacyProjection(toDataStoragePort(options.storage), {
|
|
345
348
|
onIssue: options.onLegacyProjectionIssue ?? warnLegacyProjectionIssue,
|
|
346
349
|
});
|
|
350
|
+
// Streamed scope writes need a file store that can append to an unindexed
|
|
351
|
+
// file; without one the upload routes answer 501.
|
|
352
|
+
const scopeUploads = dataStorage.openVersionWriter
|
|
353
|
+
? createScopeUploadRegistry()
|
|
354
|
+
: undefined;
|
|
347
355
|
// Wire diagnostics by default so GET /v1/diagnostics is always available.
|
|
348
356
|
const diagnostics = options.diagnostics ?? new DiagnosticsRecorder();
|
|
349
357
|
options = { ...options, diagnostics };
|
|
@@ -395,6 +403,12 @@ export function createPsLiteRuntime(options) {
|
|
|
395
403
|
if (err instanceof ProtocolError) {
|
|
396
404
|
return protocolErrorResponse(err);
|
|
397
405
|
}
|
|
406
|
+
options.logger?.error?.({
|
|
407
|
+
errorCode: "INTERNAL_ERROR",
|
|
408
|
+
err: err instanceof Error
|
|
409
|
+
? { name: err.name, message: err.message, stack: err.stack }
|
|
410
|
+
: { message: String(err) },
|
|
411
|
+
}, "Unhandled error in PS Lite runtime");
|
|
398
412
|
return errorResponse(500, "INTERNAL_ERROR", "Internal server error");
|
|
399
413
|
}
|
|
400
414
|
}
|
|
@@ -512,15 +526,26 @@ export function createPsLiteRuntime(options) {
|
|
|
512
526
|
active = true;
|
|
513
527
|
options.syncManager?.start?.();
|
|
514
528
|
options.derivatives?.scheduler.start();
|
|
529
|
+
options.replication?.resume();
|
|
515
530
|
},
|
|
516
531
|
deactivate() {
|
|
517
532
|
active = false;
|
|
518
533
|
void options.syncManager?.stop?.();
|
|
519
534
|
options.derivatives?.scheduler.stop();
|
|
535
|
+
void options.replication?.pause();
|
|
520
536
|
},
|
|
521
537
|
isAvailable() {
|
|
522
538
|
return active;
|
|
523
539
|
},
|
|
540
|
+
...(auth.supportsScopeUploadCommitments
|
|
541
|
+
? {
|
|
542
|
+
async appendScopeUpload(request, batch) {
|
|
543
|
+
if (!active)
|
|
544
|
+
return unavailableResponse();
|
|
545
|
+
return handlePersonalServerScopeUploadAppend(request, { storage: dataStorage, auth, accessLogWriter, scopeUploads }, batch);
|
|
546
|
+
},
|
|
547
|
+
}
|
|
548
|
+
: {}),
|
|
524
549
|
async fetch(request) {
|
|
525
550
|
return withProtocolErrors(async () => {
|
|
526
551
|
const url = new URL(request.url);
|
|
@@ -601,9 +626,61 @@ export function createPsLiteRuntime(options) {
|
|
|
601
626
|
});
|
|
602
627
|
return jsonResponse(snapshot);
|
|
603
628
|
}
|
|
629
|
+
if (url.pathname === "/v1/replication/status") {
|
|
630
|
+
if (request.method !== "GET")
|
|
631
|
+
return errorResponse(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
632
|
+
await auth.authorizeOwner(request);
|
|
633
|
+
return jsonResponse(options.replication?.status() ?? { state: "off" });
|
|
634
|
+
}
|
|
604
635
|
if (!active) {
|
|
605
636
|
return unavailableResponse();
|
|
606
637
|
}
|
|
638
|
+
if (url.pathname === "/v1/replication/sync") {
|
|
639
|
+
if (request.method !== "POST")
|
|
640
|
+
return errorResponse(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
641
|
+
await auth.authorizeOwner(request);
|
|
642
|
+
const status = options.replication?.status() ?? { state: "off" };
|
|
643
|
+
if (status.state !== "on")
|
|
644
|
+
return jsonResponse({
|
|
645
|
+
error: {
|
|
646
|
+
code: 409,
|
|
647
|
+
errorCode: "REPLICATION_NOT_RUNNING",
|
|
648
|
+
message: "Replication is not running",
|
|
649
|
+
},
|
|
650
|
+
status,
|
|
651
|
+
}, { status: 409 });
|
|
652
|
+
// "Sync now" starts a step and answers at once; the step may run
|
|
653
|
+
// up to its deadline. Its outcome shows in the status.
|
|
654
|
+
void options.replication.trigger("sync_now");
|
|
655
|
+
return jsonResponse({ accepted: true, status }, { status: 202 });
|
|
656
|
+
}
|
|
657
|
+
if (url.pathname === "/v1/import/oura-browser/requirements") {
|
|
658
|
+
return handleOuraCollectionRequirementsRequest(request, {
|
|
659
|
+
auth,
|
|
660
|
+
storage: toDataStoragePort(options.storage),
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
if (url.pathname === "/v1/import/oura-browser") {
|
|
664
|
+
await auth.authorizeOwner(request);
|
|
665
|
+
if (request.method !== "POST")
|
|
666
|
+
return errorResponse(405, "METHOD_NOT_ALLOWED", "Method not allowed");
|
|
667
|
+
let body;
|
|
668
|
+
try {
|
|
669
|
+
body = await request.json();
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
return errorResponse(400, "INVALID_BODY", "Body must be JSON");
|
|
673
|
+
}
|
|
674
|
+
const result = await importOuraBrowserRecords(toDataStoragePort(options.storage), body, {
|
|
675
|
+
additions: options.additions,
|
|
676
|
+
scopeDeletions: options.scopeDeletions,
|
|
677
|
+
syncManager: options.syncManager ?? null,
|
|
678
|
+
onDataWritten: options.derivatives
|
|
679
|
+
? (event) => options.derivatives?.scheduler.markSourceChanged(event.scope, { lineageSources: event.lineageSources })
|
|
680
|
+
: undefined,
|
|
681
|
+
});
|
|
682
|
+
return jsonResponse(result, { status: result.ok ? 200 : 409 });
|
|
683
|
+
}
|
|
607
684
|
const dataPrefix = "/v1/data";
|
|
608
685
|
if (url.pathname === dataPrefix ||
|
|
609
686
|
url.pathname.startsWith(`${dataPrefix}/`)) {
|
|
@@ -611,11 +688,13 @@ export function createPsLiteRuntime(options) {
|
|
|
611
688
|
return handlePersonalServerDataRequest(request, {
|
|
612
689
|
storage: dataStorage,
|
|
613
690
|
auth,
|
|
691
|
+
logger: options.logger,
|
|
614
692
|
accessLogWriter,
|
|
615
693
|
readFulfillmentReporter: options.readFulfillmentReporter,
|
|
616
694
|
additions: options.additions,
|
|
617
695
|
syncManager: options.syncManager ?? null,
|
|
618
696
|
scopeDeletions: options.scopeDeletions,
|
|
697
|
+
scopeUploads,
|
|
619
698
|
now,
|
|
620
699
|
createLogId,
|
|
621
700
|
// x402 payment enforcement for builder reads. Only engages with a
|