@earendil-works/pi-durable 1.4.0 → 1.5.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/CHANGELOG.md +204 -0
- package/README.md +195 -85
- package/dist/codemode/codemode.d.ts +6 -5
- package/dist/codemode/codemode.d.ts.map +1 -1
- package/dist/codemode/codemode.js +10 -49
- package/dist/codemode/codemode.js.map +1 -1
- package/dist/codemode/models.d.ts +2 -1
- package/dist/codemode/models.d.ts.map +1 -1
- package/dist/codemode/models.js +4 -4
- package/dist/codemode/models.js.map +1 -1
- package/dist/documents.d.ts +1 -1
- package/dist/documents.d.ts.map +1 -1
- package/dist/documents.js +1 -1
- package/dist/documents.js.map +1 -1
- package/dist/entries.d.ts +1 -1
- package/dist/entries.d.ts.map +1 -1
- package/dist/entries.js.map +1 -1
- package/dist/env/index.d.ts +13 -11
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js.map +1 -1
- package/dist/env/node-watch.d.ts +4 -4
- package/dist/env/node-watch.d.ts.map +1 -1
- package/dist/env/node-watch.js +18 -16
- package/dist/env/node-watch.js.map +1 -1
- package/dist/env/node.d.ts +3 -3
- package/dist/env/node.d.ts.map +1 -1
- package/dist/env/node.js +1 -1
- package/dist/env/node.js.map +1 -1
- package/dist/errors.d.ts +18 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +26 -3
- package/dist/errors.js.map +1 -1
- package/dist/harness/agent.d.ts.map +1 -1
- package/dist/harness/agent.js +37 -3
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/compaction.d.ts +8 -3
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +40 -11
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/context.d.ts +24 -8
- package/dist/harness/context.d.ts.map +1 -1
- package/dist/harness/context.js +71 -25
- package/dist/harness/context.js.map +1 -1
- package/dist/harness/define.d.ts +8 -4
- package/dist/harness/define.d.ts.map +1 -1
- package/dist/harness/define.js +4 -0
- package/dist/harness/define.js.map +1 -1
- package/dist/harness/generation.d.ts +39 -6
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +451 -100
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts +3 -1
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +87 -62
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +7 -2
- package/dist/harness/inbox.d.ts.map +1 -1
- package/dist/harness/inbox.js +5 -2
- package/dist/harness/inbox.js.map +1 -1
- package/dist/harness/json.d.ts +21 -5
- package/dist/harness/json.d.ts.map +1 -1
- package/dist/harness/json.js +23 -5
- package/dist/harness/json.js.map +1 -1
- package/dist/harness/live.d.ts +124 -17
- package/dist/harness/live.d.ts.map +1 -1
- package/dist/harness/live.js +93 -12
- package/dist/harness/live.js.map +1 -1
- package/dist/harness/partial-changes.d.ts +54 -0
- package/dist/harness/partial-changes.d.ts.map +1 -0
- package/dist/harness/partial-changes.js +163 -0
- package/dist/harness/partial-changes.js.map +1 -0
- package/dist/harness/prompt.d.ts +1 -1
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/provider.d.ts +1 -1
- package/dist/harness/provider.d.ts.map +1 -1
- package/dist/harness/provider.js.map +1 -1
- package/dist/harness/registry-reader.d.ts +11 -0
- package/dist/harness/registry-reader.d.ts.map +1 -0
- package/dist/harness/registry-reader.js +25 -0
- package/dist/harness/registry-reader.js.map +1 -0
- package/dist/harness/scheduler.d.ts +48 -20
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +1006 -380
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +18 -11
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +63 -26
- package/dist/harness/submissions.js.map +1 -1
- package/dist/harness/task-graph.d.ts +14 -9
- package/dist/harness/task-graph.d.ts.map +1 -1
- package/dist/harness/task-graph.js +38 -28
- package/dist/harness/task-graph.js.map +1 -1
- package/dist/harness/telemetry.d.ts +11 -11
- package/dist/harness/telemetry.d.ts.map +1 -1
- package/dist/harness/telemetry.js +7 -7
- package/dist/harness/telemetry.js.map +1 -1
- package/dist/harness/tool.d.ts +3 -1
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +172 -56
- package/dist/harness/tool.js.map +1 -1
- package/dist/harness/transcript.d.ts +72 -0
- package/dist/harness/transcript.d.ts.map +1 -0
- package/dist/harness/transcript.js +264 -0
- package/dist/harness/transcript.js.map +1 -0
- package/dist/harness/types.d.ts +237 -61
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage.d.ts +2 -1
- package/dist/harness/usage.d.ts.map +1 -1
- package/dist/harness/usage.js +1 -1
- package/dist/harness/usage.js.map +1 -1
- package/dist/harness/util.d.ts +4 -2
- package/dist/harness/util.d.ts.map +1 -1
- package/dist/harness/util.js +9 -0
- package/dist/harness/util.js.map +1 -1
- package/dist/harness/view.d.ts +44 -22
- package/dist/harness/view.d.ts.map +1 -1
- package/dist/harness/view.js +130 -71
- package/dist/harness/view.js.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +19 -3
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +107 -44
- package/dist/search.js.map +1 -1
- package/dist/session/cached-storage.d.ts +72 -0
- package/dist/session/cached-storage.d.ts.map +1 -0
- package/dist/session/cached-storage.js +269 -0
- package/dist/session/cached-storage.js.map +1 -0
- package/dist/session/conversation-tails.d.ts +33 -0
- package/dist/session/conversation-tails.d.ts.map +1 -0
- package/dist/session/conversation-tails.js +101 -0
- package/dist/session/conversation-tails.js.map +1 -0
- package/dist/session/forks.d.ts +1 -1
- package/dist/session/forks.d.ts.map +1 -1
- package/dist/session/forks.js.map +1 -1
- package/dist/session/keys.d.ts +69 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +161 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/session.d.ts +169 -26
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +1029 -171
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts +84 -5
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +227 -40
- package/dist/session/transaction.js.map +1 -1
- package/dist/session/writer.d.ts +74 -0
- package/dist/session/writer.d.ts.map +1 -0
- package/dist/session/writer.js +294 -0
- package/dist/session/writer.js.map +1 -0
- package/dist/storage/indexeddb.d.ts +12 -3
- package/dist/storage/indexeddb.d.ts.map +1 -1
- package/dist/storage/indexeddb.js +91 -41
- package/dist/storage/indexeddb.js.map +1 -1
- package/dist/storage/jsonl/index.d.ts +1 -1
- package/dist/storage/jsonl/index.d.ts.map +1 -1
- package/dist/storage/jsonl/index.js +1 -1
- package/dist/storage/jsonl/index.js.map +1 -1
- package/dist/storage/jsonl/node.d.ts +3 -3
- package/dist/storage/jsonl/node.d.ts.map +1 -1
- package/dist/storage/jsonl/node.js +2 -2
- package/dist/storage/jsonl/node.js.map +1 -1
- package/dist/storage/jsonl/storage.d.ts +46 -5
- package/dist/storage/jsonl/storage.d.ts.map +1 -1
- package/dist/storage/jsonl/storage.js +158 -43
- package/dist/storage/jsonl/storage.js.map +1 -1
- package/dist/storage/memory.d.ts +9 -3
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +28 -2
- package/dist/storage/memory.js.map +1 -1
- package/dist/storage/sqlite/commit.d.ts +52 -0
- package/dist/storage/sqlite/commit.d.ts.map +1 -0
- package/dist/storage/sqlite/commit.js +371 -0
- package/dist/storage/sqlite/commit.js.map +1 -0
- package/dist/storage/sqlite/rows.d.ts +33 -0
- package/dist/storage/sqlite/rows.d.ts.map +1 -0
- package/dist/storage/sqlite/rows.js +53 -0
- package/dist/storage/sqlite/rows.js.map +1 -0
- package/dist/storage/sqlite/statements.d.ts +13 -0
- package/dist/storage/sqlite/statements.d.ts.map +1 -0
- package/dist/storage/sqlite/statements.js +88 -0
- package/dist/storage/sqlite/statements.js.map +1 -0
- package/dist/storage/sqlite/storage.d.ts +23 -10
- package/dist/storage/sqlite/storage.d.ts.map +1 -1
- package/dist/storage/sqlite/storage.js +120 -261
- package/dist/storage/sqlite/storage.js.map +1 -1
- package/dist/storage/store/commit.d.ts +33 -0
- package/dist/storage/store/commit.d.ts.map +1 -0
- package/dist/storage/store/commit.js +286 -0
- package/dist/storage/store/commit.js.map +1 -0
- package/dist/storage/store/documents.d.ts +43 -0
- package/dist/storage/store/documents.d.ts.map +1 -0
- package/dist/storage/store/documents.js +102 -0
- package/dist/storage/store/documents.js.map +1 -0
- package/dist/storage/store/index.d.ts +2 -0
- package/dist/storage/store/index.d.ts.map +1 -0
- package/dist/storage/store/index.js +2 -0
- package/dist/storage/store/index.js.map +1 -0
- package/dist/storage/store/queries.d.ts +49 -0
- package/dist/storage/store/queries.d.ts.map +1 -0
- package/dist/storage/store/queries.js +93 -0
- package/dist/storage/store/queries.js.map +1 -0
- package/dist/storage/store/storage.d.ts +60 -0
- package/dist/storage/store/storage.d.ts.map +1 -0
- package/dist/storage/store/storage.js +438 -0
- package/dist/storage/store/storage.js.map +1 -0
- package/dist/storage/store/tables.d.ts +54 -0
- package/dist/storage/store/tables.d.ts.map +1 -0
- package/dist/storage/store/tables.js +108 -0
- package/dist/storage/store/tables.js.map +1 -0
- package/dist/testing/commit-writes.d.ts +5 -0
- package/dist/testing/commit-writes.d.ts.map +1 -0
- package/dist/testing/commit-writes.js +12 -0
- package/dist/testing/commit-writes.js.map +1 -0
- package/dist/testing/env-conformance.js +7 -7
- package/dist/testing/env-conformance.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/storage-benchmark.d.ts.map +1 -1
- package/dist/testing/storage-benchmark.js +18 -17
- package/dist/testing/storage-benchmark.js.map +1 -1
- package/dist/testing/storage-conformance.d.ts.map +1 -1
- package/dist/testing/storage-conformance.js +354 -69
- package/dist/testing/storage-conformance.js.map +1 -1
- package/dist/tool-search/tool-search.d.ts +8 -14
- package/dist/tool-search/tool-search.d.ts.map +1 -1
- package/dist/tool-search/tool-search.js +25 -13
- package/dist/tool-search/tool-search.js.map +1 -1
- package/dist/tools/bash.d.ts +13 -13
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +16 -15
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +7 -7
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +9 -9
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/file-mutation-queue.d.ts +1 -1
- package/dist/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/tools/file-mutation-queue.js.map +1 -1
- package/dist/tools/index.d.ts +32 -32
- package/dist/tools/path-utils.d.ts +1 -1
- package/dist/tools/path-utils.d.ts.map +1 -1
- package/dist/tools/path-utils.js.map +1 -1
- package/dist/tools/read.d.ts +6 -6
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +19 -8
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +4 -4
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +5 -5
- package/dist/tools/write.js.map +1 -1
- package/dist/types.d.ts +228 -78
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +19 -12
- package/dist/harness/events.d.ts +0 -186
- package/dist/harness/events.d.ts.map +0 -1
- package/dist/harness/events.js +0 -373
- package/dist/harness/events.js.map +0 -1
- package/dist/session/observation.d.ts +0 -42
- package/dist/session/observation.d.ts.map +0 -1
- package/dist/session/observation.js +0 -281
- package/dist/session/observation.js.map +0 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
// Durable's `Storage` on Chord's store (slice 6b D1, D2, §2): opening under an owner name (claims, tables, the
|
|
2
|
+
// allocator), commits as one composite write of the store's commit step, and the reads, each one guarded read of the
|
|
3
|
+
// store (several queries at one state in a read transaction), its request errors in a tagged result told after it.
|
|
4
|
+
import { findDocumentEntry, listDocumentEntries, StoreOwnerTables, } from "@earendil-works/chord";
|
|
5
|
+
import { StorageRequestError } from "../../errors.js";
|
|
6
|
+
import { idFromNumber, seqFromNumber } from "../../ids.js";
|
|
7
|
+
import { nextCursor, scanStart } from "../scan.js";
|
|
8
|
+
import { DurableCommit } from "./commit.js";
|
|
9
|
+
import { addressOf, namespaceOf, readAt, recordOfEntry, SCOPE_NAMESPACES } from "./documents.js";
|
|
10
|
+
import { storageQueries } from "./queries.js";
|
|
11
|
+
import { Conversations, Entries, EntryHeads, encodeIndexed, RecordIds, Submissions, Tasks } from "./tables.js";
|
|
12
|
+
/** The id condition of a table scan from `start`. */
|
|
13
|
+
function scanFrom(start) {
|
|
14
|
+
return start.order === "ascending"
|
|
15
|
+
? ["id", "gt", start.after ?? -1]
|
|
16
|
+
: ["id", "lt", start.after ?? Number.MAX_SAFE_INTEGER];
|
|
17
|
+
}
|
|
18
|
+
function page(values, limit, order) {
|
|
19
|
+
const items = values.slice(0, limit);
|
|
20
|
+
if (values.length <= limit)
|
|
21
|
+
return { items };
|
|
22
|
+
return { items, next: nextCursor(items.at(-1).id, order) };
|
|
23
|
+
}
|
|
24
|
+
function cursorId(cursor) {
|
|
25
|
+
const after = cursor?.after;
|
|
26
|
+
if (after === undefined)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (typeof after !== "number" || !Number.isSafeInteger(after))
|
|
29
|
+
throw new StorageRequestError("Invalid storage cursor");
|
|
30
|
+
return after;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Durable's `Storage` on Chord's store (slice 6b D1, D2, §2): its records as declared tables under an owner name, its
|
|
34
|
+
* documents in the store's documents engine, its ids from the store's one allocator, each commit call as one series
|
|
35
|
+
* of the store's commit queue (one backend transaction, one seq per batch), published in the host's batch. Several may share a store under distinct owner names
|
|
36
|
+
* (claims); the app owns the store, and `close` leaves it open.
|
|
37
|
+
*/
|
|
38
|
+
export class StoreStorage {
|
|
39
|
+
#store;
|
|
40
|
+
#owner;
|
|
41
|
+
#claimant;
|
|
42
|
+
#tables;
|
|
43
|
+
#queries;
|
|
44
|
+
#closed = false;
|
|
45
|
+
#closing;
|
|
46
|
+
/** Calls underway, which `close` waits for before it releases the claims (`#drained` once they reach 0). */
|
|
47
|
+
#underway = 0;
|
|
48
|
+
#drained;
|
|
49
|
+
constructor(store, owner, claimant, tables) {
|
|
50
|
+
this.#store = store;
|
|
51
|
+
this.#owner = owner;
|
|
52
|
+
this.#claimant = claimant;
|
|
53
|
+
this.#tables = tables;
|
|
54
|
+
this.#queries = storageQueries(tables);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Opens Durable's storage in `store` under `owner` (a lowercase `[a-z0-9@/._~-]` name): claims its tables and its
|
|
58
|
+
* document namespaces (a second claim is refused `invalid/args`), creates or migrates its tables, and raises the
|
|
59
|
+
* store's allocator above every id it holds (one index read). A failure releases what it claimed.
|
|
60
|
+
*/
|
|
61
|
+
static async open(store, owner, context) {
|
|
62
|
+
// Chord's own: `openStore` or `importStore` made it.
|
|
63
|
+
const chord = store;
|
|
64
|
+
const claimant = { label: `StoreStorage(${owner})` };
|
|
65
|
+
try {
|
|
66
|
+
const declared = new StoreOwnerTables(chord, owner, claimant);
|
|
67
|
+
const tables = {
|
|
68
|
+
recordIds: declared.declare(RecordIds),
|
|
69
|
+
conversations: declared.declare(Conversations),
|
|
70
|
+
entries: declared.declare(Entries),
|
|
71
|
+
entryHeads: declared.declare(EntryHeads),
|
|
72
|
+
tasks: declared.declare(Tasks),
|
|
73
|
+
submissions: declared.declare(Submissions),
|
|
74
|
+
};
|
|
75
|
+
for (const namespace of SCOPE_NAMESPACES)
|
|
76
|
+
chord.claims.documents(owner, namespace, claimant);
|
|
77
|
+
await declared.prepare(context);
|
|
78
|
+
const highest = await chord.read((executor) => executor.get(`SELECT max("id") AS id FROM "${tables.recordIds.sql.table}"`), context);
|
|
79
|
+
if (highest?.id != null)
|
|
80
|
+
chord.ids.raise(highest.id);
|
|
81
|
+
return new StoreStorage(chord, owner, claimant, tables);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
chord.claims.release(claimant);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Commit `batches` as one series of the store (`ChordStore.commitSeries`): one backend transaction, one seq per
|
|
90
|
+
* batch, each batch's checks (at staging, then against the state the earlier ones left) before its writes.
|
|
91
|
+
*/
|
|
92
|
+
commit(batches, receive, context) {
|
|
93
|
+
return this.#call(() => {
|
|
94
|
+
const store = this.#store;
|
|
95
|
+
const raise = (id) => store.ids.raise(id);
|
|
96
|
+
const commits = [];
|
|
97
|
+
for (const writes of batches) {
|
|
98
|
+
try {
|
|
99
|
+
commits.push(new DurableCommit(writes, this.#owner, this.#tables, raise, context));
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
// Staging runs Durable's checks of the batch itself: a refusal in its turn, the batches before it stored.
|
|
103
|
+
commits.push({ check: () => Promise.reject(error), writes: [] });
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return store.commitSeries(commits, (index, seq) => receive(index, seqFromNumber(seq)), context);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Run a commit's publication in the attached host's batch (`batch.within`: it joins a running batch, opens one, or
|
|
112
|
+
* runs next while one sends): Chord sources over Durable's views are marked in one batch per commit. Plainly without
|
|
113
|
+
* a host.
|
|
114
|
+
*/
|
|
115
|
+
publishing(publish, context) {
|
|
116
|
+
const batch = this.#store.batch;
|
|
117
|
+
if (batch === undefined)
|
|
118
|
+
publish();
|
|
119
|
+
else
|
|
120
|
+
batch.within(publish, context);
|
|
121
|
+
}
|
|
122
|
+
mintId() {
|
|
123
|
+
return this.#call(async () => idFromNumber(this.#store.mintId()));
|
|
124
|
+
}
|
|
125
|
+
conversation(id, context) {
|
|
126
|
+
return this.#read((executor) => this.#conversation(executor, id, context), context);
|
|
127
|
+
}
|
|
128
|
+
scanConversations(query, limit, cursor, context) {
|
|
129
|
+
return this.#reading(() => {
|
|
130
|
+
const start = scanStart(query.order, cursor, "ascending");
|
|
131
|
+
const conditions = [scanFrom(start)];
|
|
132
|
+
if (query.ownerConversationId !== undefined) {
|
|
133
|
+
conditions.push(["owner_conversation_id", "eq", query.ownerConversationId]);
|
|
134
|
+
}
|
|
135
|
+
if (query.ownerTaskId !== undefined)
|
|
136
|
+
conditions.push(["owner_task_id", "eq", query.ownerTaskId]);
|
|
137
|
+
return this.#scan(this.#queries.conversations, conditions, start, limit, context);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
entry(idOrConversationId, idOrContext, maybeContext) {
|
|
141
|
+
if (maybeContext === undefined) {
|
|
142
|
+
const context = idOrContext;
|
|
143
|
+
return this.#read((executor) => this.#entry(executor, idOrConversationId, context), context);
|
|
144
|
+
}
|
|
145
|
+
const context = maybeContext;
|
|
146
|
+
const id = typeof idOrContext === "number" ? idFromNumber(idOrContext) : undefined;
|
|
147
|
+
return this.#reading(() => {
|
|
148
|
+
if (id === undefined)
|
|
149
|
+
throw new StorageRequestError("Storage.entry() requires an entry ID");
|
|
150
|
+
const conversationId = idOrConversationId;
|
|
151
|
+
return this.#store
|
|
152
|
+
.read((executor) => this.#visibleEntry(executor, conversationId, id, context), context)
|
|
153
|
+
.then(told);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
findLatestHeadMarker(conversationId, atOrBeforeEntryId, context) {
|
|
157
|
+
return this.#reading(() => this.#store
|
|
158
|
+
.read((executor) => this.#latestHeadMarker(executor, conversationId, atOrBeforeEntryId, context), context)
|
|
159
|
+
.then(told));
|
|
160
|
+
}
|
|
161
|
+
scanEntries(query, limit, cursor, context) {
|
|
162
|
+
return this.#reading(() => {
|
|
163
|
+
const { order, after } = scanStart(query.order, cursor, "descending");
|
|
164
|
+
const read = order === "ascending"
|
|
165
|
+
? (executor) => this.#entriesAscending(executor, query, limit, after, context)
|
|
166
|
+
: (executor) => this.#entriesDescending(executor, query, limit, after, context);
|
|
167
|
+
return this.#store.read(read, context).then(told);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
task(id, context) {
|
|
171
|
+
const tasks = this.#queries.tasks;
|
|
172
|
+
return this.#read(async (executor) => {
|
|
173
|
+
const row = await tasks.byId(executor, id);
|
|
174
|
+
return row === undefined ? undefined : tasks.record(row, context);
|
|
175
|
+
}, context);
|
|
176
|
+
}
|
|
177
|
+
scanTasks(query, limit, cursor, context) {
|
|
178
|
+
return this.#reading(() => {
|
|
179
|
+
const start = scanStart(query.order, cursor, "ascending");
|
|
180
|
+
const conditions = [scanFrom(start)];
|
|
181
|
+
if (query.conversationId !== undefined)
|
|
182
|
+
conditions.push(["conversation_id", "eq", query.conversationId]);
|
|
183
|
+
if (query.kind !== undefined)
|
|
184
|
+
conditions.push(["kind", "eq", encodeIndexed(query.kind)]);
|
|
185
|
+
if (query.status !== undefined)
|
|
186
|
+
conditions.push(["status", "eq", query.status]);
|
|
187
|
+
if (query.abortRequested !== undefined)
|
|
188
|
+
conditions.push(["abort_requested", "eq", query.abortRequested ? 1 : 0]);
|
|
189
|
+
if (query.background !== undefined)
|
|
190
|
+
conditions.push(["background", "eq", query.background ? 1 : 0]);
|
|
191
|
+
return this.#scan(this.#queries.tasks, conditions, start, limit, context);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
submission(id, context) {
|
|
195
|
+
const submissions = this.#queries.submissions;
|
|
196
|
+
return this.#read(async (executor) => {
|
|
197
|
+
const row = await submissions.byId(executor, id);
|
|
198
|
+
return row === undefined ? undefined : submissions.record(row, context);
|
|
199
|
+
}, context);
|
|
200
|
+
}
|
|
201
|
+
scanSubmissions(query, limit, cursor, context) {
|
|
202
|
+
return this.#reading(() => {
|
|
203
|
+
const start = scanStart(query.order, cursor, "ascending");
|
|
204
|
+
const conditions = [scanFrom(start)];
|
|
205
|
+
if (query.conversationId !== undefined)
|
|
206
|
+
conditions.push(["conversation_id", "eq", query.conversationId]);
|
|
207
|
+
if (query.status !== undefined)
|
|
208
|
+
conditions.push(["status", "eq", query.status]);
|
|
209
|
+
return this.#scan(this.#queries.submissions, conditions, start, limit, context);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
submissionByRequest(conversationId, requestId, context) {
|
|
213
|
+
const submissions = this.#queries.submissions;
|
|
214
|
+
const conditions = [
|
|
215
|
+
["conversation_id", "eq", conversationId],
|
|
216
|
+
["request_id", "eq", encodeIndexed(requestId)],
|
|
217
|
+
];
|
|
218
|
+
return this.#read(async (executor) => {
|
|
219
|
+
const row = await submissions.first(executor, conditions, "ascending");
|
|
220
|
+
return row === undefined ? undefined : submissions.record(row, context);
|
|
221
|
+
}, context);
|
|
222
|
+
}
|
|
223
|
+
findDocument(address, at, context) {
|
|
224
|
+
return this.#read(async (executor) => {
|
|
225
|
+
const entry = await findDocumentEntry(executor, addressOf(address, this.#owner), at);
|
|
226
|
+
return entry === undefined ? undefined : recordOfEntry(entry);
|
|
227
|
+
}, context);
|
|
228
|
+
}
|
|
229
|
+
document(id, at, context) {
|
|
230
|
+
// The record and its revisions must come from one committed state (S4).
|
|
231
|
+
return this.#reading(() => this.#store.readTransaction((executor) => readAt(executor, id, at, this.#owner), context).then(documentOf));
|
|
232
|
+
}
|
|
233
|
+
scanDocuments(query, limit, cursor, context) {
|
|
234
|
+
return this.#reading(() => {
|
|
235
|
+
const after = cursorId(cursor) ?? -1;
|
|
236
|
+
const scope = {
|
|
237
|
+
owner: this.#owner,
|
|
238
|
+
namespace: namespaceOf(query.scope),
|
|
239
|
+
...(query.kind === undefined ? {} : { kind: encodeIndexed(query.kind) }),
|
|
240
|
+
};
|
|
241
|
+
return this.#store
|
|
242
|
+
.read((executor) => listDocumentEntries(executor, scope, query.at, after, limit + 1), context)
|
|
243
|
+
.then((found) => page(found.map(recordOfEntry), limit, "ascending"));
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Refuses new calls, waits for its commits underway, then releases its claims; the store stays open (the app's),
|
|
248
|
+
* and finishes the reads underway, which change nothing.
|
|
249
|
+
*/
|
|
250
|
+
close(_context) {
|
|
251
|
+
if (this.#closing === undefined) {
|
|
252
|
+
this.#closed = true;
|
|
253
|
+
this.#closing = (async () => {
|
|
254
|
+
if (this.#underway > 0) {
|
|
255
|
+
await new Promise((resolve) => {
|
|
256
|
+
this.#drained = resolve;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
this.#store.claims.release(this.#claimant);
|
|
260
|
+
})();
|
|
261
|
+
}
|
|
262
|
+
return this.#closing;
|
|
263
|
+
}
|
|
264
|
+
/** Runs one commit or mint of this storage: refused once it closed, counted until it settles (`close` waits). */
|
|
265
|
+
async #call(run) {
|
|
266
|
+
if (this.#closed)
|
|
267
|
+
throw new Error("StoreStorage is closed");
|
|
268
|
+
this.#underway++;
|
|
269
|
+
try {
|
|
270
|
+
return await run();
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
if (--this.#underway === 0)
|
|
274
|
+
this.#drained?.();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* A call that is one guarded read of the store: refused once closed; not waited for by `close` (a read changes
|
|
279
|
+
* nothing, and the store, which stays open, finishes it).
|
|
280
|
+
*/
|
|
281
|
+
#read(read, context) {
|
|
282
|
+
return this.#reading(() => this.#store.read(read, context));
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* A read call: `read` prepares its guarded read (a request error thrown then, before it) and returns it. Refused
|
|
286
|
+
* once closed; one promise per call besides the guard's (no async wrapper).
|
|
287
|
+
*/
|
|
288
|
+
#reading(read) {
|
|
289
|
+
try {
|
|
290
|
+
if (this.#closed)
|
|
291
|
+
throw new Error("StoreStorage is closed");
|
|
292
|
+
return read();
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
return Promise.reject(error);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async #conversation(executor, id, context) {
|
|
299
|
+
const conversations = this.#queries.conversations;
|
|
300
|
+
const row = await conversations.byId(executor, id);
|
|
301
|
+
return row === undefined ? undefined : conversations.record(row, context);
|
|
302
|
+
}
|
|
303
|
+
#entry(executor, id, context) {
|
|
304
|
+
const entries = this.#queries.entries;
|
|
305
|
+
return entries.byId(executor, id).then((row) => {
|
|
306
|
+
if (row === undefined)
|
|
307
|
+
return undefined;
|
|
308
|
+
return { entry: entries.record(row, context), commitSeq: seqFromNumber(row.commit_seq) };
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/** Entry `id` when visible through `conversationId`'s fork chain (`SqliteStorage.readEntry`). */
|
|
312
|
+
async #visibleEntry(executor, conversationId, id, context) {
|
|
313
|
+
let conversation = await this.#conversation(executor, conversationId, context);
|
|
314
|
+
if (conversation === undefined)
|
|
315
|
+
return unknownConversation(conversationId);
|
|
316
|
+
const stored = await this.#entry(executor, id, context);
|
|
317
|
+
if (stored === undefined)
|
|
318
|
+
return NOTHING_FOUND;
|
|
319
|
+
let upper = Number.POSITIVE_INFINITY;
|
|
320
|
+
while (conversation.id !== stored.entry.conversationId) {
|
|
321
|
+
if (conversation.parent === undefined)
|
|
322
|
+
return NOTHING_FOUND;
|
|
323
|
+
upper = Math.min(upper, conversation.parent.at);
|
|
324
|
+
conversation = (await this.#conversation(executor, conversation.parent.conversationId, context));
|
|
325
|
+
}
|
|
326
|
+
return stored.entry.id > upper ? NOTHING_FOUND : { kind: "found", value: stored };
|
|
327
|
+
}
|
|
328
|
+
async #latestHeadMarker(executor, conversationId, atOrBeforeEntryId, context) {
|
|
329
|
+
let conversation = await this.#conversation(executor, conversationId, context);
|
|
330
|
+
if (conversation === undefined)
|
|
331
|
+
return unknownConversation(conversationId);
|
|
332
|
+
let upper = atOrBeforeEntryId;
|
|
333
|
+
while (true) {
|
|
334
|
+
const { latestHead } = this.#queries;
|
|
335
|
+
const head = upper === undefined
|
|
336
|
+
? await executor.get(latestHead.any, conversation.id)
|
|
337
|
+
: await executor.get(latestHead.atOrBefore, conversation.id, upper);
|
|
338
|
+
if (head !== undefined) {
|
|
339
|
+
// Written with its entry, in the same commit.
|
|
340
|
+
const row = (await this.#queries.entries.byId(executor, head.id));
|
|
341
|
+
const value = this.#queries.entries.record(row, context);
|
|
342
|
+
return { kind: "found", value };
|
|
343
|
+
}
|
|
344
|
+
if (conversation.parent === undefined)
|
|
345
|
+
return NOTHING_FOUND;
|
|
346
|
+
upper = upper === undefined ? conversation.parent.at : Math.min(upper, conversation.parent.at);
|
|
347
|
+
conversation = (await this.#conversation(executor, conversation.parent.conversationId, context));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/** Newest first: each conversation of the fork chain up to its fork point (`SqliteStorage.readEntries`). */
|
|
351
|
+
async #entriesDescending(executor, query, limit, after, context) {
|
|
352
|
+
let conversation = await this.#conversation(executor, query.conversationId, context);
|
|
353
|
+
if (conversation === undefined)
|
|
354
|
+
return unknownConversation(query.conversationId);
|
|
355
|
+
let upper = query.maxEntryId;
|
|
356
|
+
if (after !== undefined)
|
|
357
|
+
upper = Math.min(upper ?? Number.MAX_SAFE_INTEGER, after - 1);
|
|
358
|
+
const values = [];
|
|
359
|
+
while (true) {
|
|
360
|
+
const range = this.#range(conversation.id, query.minEntryId, upper);
|
|
361
|
+
const rows = await this.#queries.entries.select(executor, range, "descending", limit + 1 - values.length);
|
|
362
|
+
this.#queries.entries.records(rows, values, context);
|
|
363
|
+
if (values.length > limit || conversation.parent === undefined)
|
|
364
|
+
break;
|
|
365
|
+
upper = upper === undefined ? conversation.parent.at : Math.min(upper, conversation.parent.at);
|
|
366
|
+
if (query.minEntryId !== undefined && upper < query.minEntryId)
|
|
367
|
+
break;
|
|
368
|
+
conversation = (await this.#conversation(executor, conversation.parent.conversationId, context));
|
|
369
|
+
}
|
|
370
|
+
return { kind: "found", value: page(values, limit, "descending") };
|
|
371
|
+
}
|
|
372
|
+
/** Oldest first: the fork chain's segments from the root forward, each up to its fork point. */
|
|
373
|
+
async #entriesAscending(executor, query, limit, after, context) {
|
|
374
|
+
const segments = [];
|
|
375
|
+
let conversation = await this.#conversation(executor, query.conversationId, context);
|
|
376
|
+
if (conversation === undefined)
|
|
377
|
+
return unknownConversation(query.conversationId);
|
|
378
|
+
let upper = query.maxEntryId;
|
|
379
|
+
while (true) {
|
|
380
|
+
segments.push({ conversationId: conversation.id, upper });
|
|
381
|
+
if (conversation.parent === undefined)
|
|
382
|
+
break;
|
|
383
|
+
upper = upper === undefined ? conversation.parent.at : Math.min(upper, conversation.parent.at);
|
|
384
|
+
if (query.minEntryId !== undefined && upper < query.minEntryId)
|
|
385
|
+
break;
|
|
386
|
+
conversation = (await this.#conversation(executor, conversation.parent.conversationId, context));
|
|
387
|
+
}
|
|
388
|
+
let lower = query.minEntryId;
|
|
389
|
+
if (after !== undefined)
|
|
390
|
+
lower = Math.max(lower ?? after + 1, after + 1);
|
|
391
|
+
const values = [];
|
|
392
|
+
for (const segment of segments.reverse()) {
|
|
393
|
+
const range = this.#range(segment.conversationId, lower, segment.upper);
|
|
394
|
+
const rows = await this.#queries.entries.select(executor, range, "ascending", limit + 1 - values.length);
|
|
395
|
+
this.#queries.entries.records(rows, values, context);
|
|
396
|
+
if (values.length > limit)
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
return { kind: "found", value: page(values, limit, "ascending") };
|
|
400
|
+
}
|
|
401
|
+
/** One conversation's entries with ids from `lower` to `upper` (inclusive, each optional). */
|
|
402
|
+
#range(conversationId, lower, upper) {
|
|
403
|
+
const conditions = [["conversation_id", "eq", conversationId]];
|
|
404
|
+
if (lower !== undefined)
|
|
405
|
+
conditions.push(["id", "gte", lower]);
|
|
406
|
+
if (upper !== undefined)
|
|
407
|
+
conditions.push(["id", "lte", upper]);
|
|
408
|
+
return conditions;
|
|
409
|
+
}
|
|
410
|
+
/** A page of a table scan: up to `limit` records of `queries`' table whose `conditions` hold, from `start`. */
|
|
411
|
+
#scan(queries, conditions, start, limit, context) {
|
|
412
|
+
return this.#store
|
|
413
|
+
.read((executor) => queries.select(executor, conditions, start.order, limit + 1), context)
|
|
414
|
+
.then((rows) => {
|
|
415
|
+
const values = [];
|
|
416
|
+
queries.records(rows, values, context);
|
|
417
|
+
return page(values, limit, start.order);
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/** A read that found nothing. */
|
|
422
|
+
const NOTHING_FOUND = { kind: "found", value: undefined };
|
|
423
|
+
function unknownConversation(id) {
|
|
424
|
+
return { kind: "refused", message: `Unknown conversation: ${id}` };
|
|
425
|
+
}
|
|
426
|
+
/** A read's data, its request error thrown now that the guarded read returned (slice 6b §1.4). */
|
|
427
|
+
function told(read) {
|
|
428
|
+
if (read.kind === "refused")
|
|
429
|
+
throw new StorageRequestError(read.message);
|
|
430
|
+
return read.value;
|
|
431
|
+
}
|
|
432
|
+
/** A document read's result, a record that keeps no history at the point thrown as Durable's request error. */
|
|
433
|
+
function documentOf(read) {
|
|
434
|
+
if (read.kind === "current_only")
|
|
435
|
+
throw new StorageRequestError(`Document ${read.id} does not retain historical content`);
|
|
436
|
+
return read.document;
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/storage/store/storage.ts"],"names":[],"mappings":"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","sourcesContent":["// Durable's `Storage` on Chord's store (slice 6b D1, D2, §2): opening under an owner name (claims, tables, the\n// allocator), commits as one composite write of the store's commit step, and the reads, each one guarded read of the\n// store (several queries at one state in a read transaction), its request errors in a tagged result told after it.\n\nimport {\n\ttype ChordStore,\n\ttype Claimant,\n\tfindDocumentEntry,\n\tlistDocumentEntries,\n\ttype SeriesCommit,\n\ttype Store,\n\tStoreOwnerTables,\n} from \"@earendil-works/chord\";\nimport type { Context } from \"@earendil-works/chord/context\";\nimport type { JsonValue } from \"@earendil-works/chord/json\";\nimport type { SqliteExecutor } from \"@earendil-works/chord/sqlite\";\nimport { StorageRequestError } from \"../../errors.ts\";\nimport { idFromNumber, seqFromNumber } from \"../../ids.ts\";\nimport type {\n\tCommitResult,\n\tConversationId,\n\tConversationQuery,\n\tConversationRecord,\n\tCursor,\n\tDocumentAddress,\n\tDocumentId,\n\tDocumentPoint,\n\tDocumentQuery,\n\tDocumentRecord,\n\tEntryId,\n\tEntryQuery,\n\tEntryRecord,\n\tId,\n\tPage,\n\tScanOrder,\n\tSeq,\n\tStorage,\n\tStorageWrite,\n\tStoredDocument,\n\tSubmissionId,\n\tSubmissionQuery,\n\tSubmissionRecord,\n\tTaskId,\n\tTaskQuery,\n\tTaskRecord,\n} from \"../../types.ts\";\nimport { nextCursor, type ScanStart, scanStart } from \"../scan.ts\";\nimport { type CommitTables, DurableCommit } from \"./commit.ts\";\nimport { addressOf, type DocumentRead, namespaceOf, readAt, recordOfEntry, SCOPE_NAMESPACES } from \"./documents.ts\";\nimport { type Condition, type StorageQueries, storageQueries, type TableQueries } from \"./queries.ts\";\nimport { Conversations, Entries, EntryHeads, encodeIndexed, RecordIds, Submissions, Tasks } from \"./tables.ts\";\n\ntype StoredTask = TaskRecord<JsonValue, JsonValue, JsonValue>;\ntype StoredEntry = { readonly entry: EntryRecord; readonly commitSeq: Seq };\n\n/**\n * A guarded read's result: its data, or its request error, which is thrown after the guarded read (slice 6b §1.4),\n * never inside it.\n */\ntype Read<T> = { readonly kind: \"found\"; readonly value: T } | { readonly kind: \"refused\"; readonly message: string };\n\n/** The id condition of a table scan from `start`. */\nfunction scanFrom(start: ScanStart): Condition {\n\treturn start.order === \"ascending\"\n\t\t? [\"id\", \"gt\", start.after ?? -1]\n\t\t: [\"id\", \"lt\", start.after ?? Number.MAX_SAFE_INTEGER];\n}\n\nfunction page<T extends { readonly id: Id<string> }>(\n\tvalues: readonly T[],\n\tlimit: number,\n\torder: ScanOrder,\n): Page<T, Cursor> {\n\tconst items = values.slice(0, limit);\n\tif (values.length <= limit) return { items };\n\treturn { items, next: nextCursor(items.at(-1)!.id, order) };\n}\n\nfunction cursorId(cursor: Cursor | undefined): number | undefined {\n\tconst after = cursor?.after;\n\tif (after === undefined) return undefined;\n\tif (typeof after !== \"number\" || !Number.isSafeInteger(after))\n\t\tthrow new StorageRequestError(\"Invalid storage cursor\");\n\treturn after;\n}\n\n/**\n * Durable's `Storage` on Chord's store (slice 6b D1, D2, §2): its records as declared tables under an owner name, its\n * documents in the store's documents engine, its ids from the store's one allocator, each commit call as one series\n * of the store's commit queue (one backend transaction, one seq per batch), published in the host's batch. Several may share a store under distinct owner names\n * (claims); the app owns the store, and `close` leaves it open.\n */\nexport class StoreStorage implements Storage {\n\treadonly #store: ChordStore;\n\treadonly #owner: string;\n\treadonly #claimant: Claimant;\n\treadonly #tables: CommitTables;\n\treadonly #queries: StorageQueries;\n\t#closed = false;\n\t#closing: Promise<void> | undefined;\n\t/** Calls underway, which `close` waits for before it releases the claims (`#drained` once they reach 0). */\n\t#underway = 0;\n\t#drained: (() => void) | undefined;\n\n\tprivate constructor(store: ChordStore, owner: string, claimant: Claimant, tables: CommitTables) {\n\t\tthis.#store = store;\n\t\tthis.#owner = owner;\n\t\tthis.#claimant = claimant;\n\t\tthis.#tables = tables;\n\t\tthis.#queries = storageQueries(tables);\n\t}\n\n\t/**\n\t * Opens Durable's storage in `store` under `owner` (a lowercase `[a-z0-9@/._~-]` name): claims its tables and its\n\t * document namespaces (a second claim is refused `invalid/args`), creates or migrates its tables, and raises the\n\t * store's allocator above every id it holds (one index read). A failure releases what it claimed.\n\t */\n\tstatic async open(store: Store, owner: string, context: Context): Promise<StoreStorage> {\n\t\t// Chord's own: `openStore` or `importStore` made it.\n\t\tconst chord = store as ChordStore;\n\t\tconst claimant: Claimant = { label: `StoreStorage(${owner})` };\n\t\ttry {\n\t\t\tconst declared = new StoreOwnerTables(chord, owner, claimant);\n\t\t\tconst tables: CommitTables = {\n\t\t\t\trecordIds: declared.declare(RecordIds),\n\t\t\t\tconversations: declared.declare(Conversations),\n\t\t\t\tentries: declared.declare(Entries),\n\t\t\t\tentryHeads: declared.declare(EntryHeads),\n\t\t\t\ttasks: declared.declare(Tasks),\n\t\t\t\tsubmissions: declared.declare(Submissions),\n\t\t\t};\n\t\t\tfor (const namespace of SCOPE_NAMESPACES) chord.claims.documents(owner, namespace, claimant);\n\t\t\tawait declared.prepare(context);\n\t\t\tconst highest = await chord.read(\n\t\t\t\t(executor) =>\n\t\t\t\t\texecutor.get<{ readonly id: number | null }>(\n\t\t\t\t\t\t`SELECT max(\"id\") AS id FROM \"${tables.recordIds.sql.table}\"`,\n\t\t\t\t\t),\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (highest?.id != null) chord.ids.raise(highest.id);\n\t\t\treturn new StoreStorage(chord, owner, claimant, tables);\n\t\t} catch (error) {\n\t\t\tchord.claims.release(claimant);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Commit `batches` as one series of the store (`ChordStore.commitSeries`): one backend transaction, one seq per\n\t * batch, each batch's checks (at staging, then against the state the earlier ones left) before its writes.\n\t */\n\tcommit(\n\t\tbatches: readonly (readonly StorageWrite[])[],\n\t\treceive: (index: number, seq: Seq) => void,\n\t\tcontext: Context,\n\t): Promise<CommitResult> {\n\t\treturn this.#call(() => {\n\t\t\tconst store = this.#store;\n\t\t\tconst raise = (id: number): void => store.ids.raise(id);\n\t\t\tconst commits: SeriesCommit[] = [];\n\t\t\tfor (const writes of batches) {\n\t\t\t\ttry {\n\t\t\t\t\tcommits.push(new DurableCommit(writes, this.#owner, this.#tables, raise, context));\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Staging runs Durable's checks of the batch itself: a refusal in its turn, the batches before it stored.\n\t\t\t\t\tcommits.push({ check: () => Promise.reject(error), writes: [] });\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn store.commitSeries(commits, (index, seq) => receive(index, seqFromNumber(seq)), context);\n\t\t});\n\t}\n\n\t/**\n\t * Run a commit's publication in the attached host's batch (`batch.within`: it joins a running batch, opens one, or\n\t * runs next while one sends): Chord sources over Durable's views are marked in one batch per commit. Plainly without\n\t * a host.\n\t */\n\tpublishing(publish: () => void, context: Context): void {\n\t\tconst batch = this.#store.batch;\n\t\tif (batch === undefined) publish();\n\t\telse batch.within(publish, context);\n\t}\n\n\tmintId<I extends Id<string>>(): Promise<I> {\n\t\treturn this.#call(async () => idFromNumber<I>(this.#store.mintId()));\n\t}\n\n\tconversation(id: ConversationId, context: Context): Promise<ConversationRecord | undefined> {\n\t\treturn this.#read((executor) => this.#conversation(executor, id, context), context);\n\t}\n\n\tscanConversations(\n\t\tquery: ConversationQuery,\n\t\tlimit: number,\n\t\tcursor: Cursor | undefined,\n\t\tcontext: Context,\n\t): Promise<Page<ConversationRecord, Cursor>> {\n\t\treturn this.#reading(() => {\n\t\t\tconst start = scanStart(query.order, cursor, \"ascending\");\n\t\t\tconst conditions: Condition[] = [scanFrom(start)];\n\t\t\tif (query.ownerConversationId !== undefined) {\n\t\t\t\tconditions.push([\"owner_conversation_id\", \"eq\", query.ownerConversationId]);\n\t\t\t}\n\t\t\tif (query.ownerTaskId !== undefined) conditions.push([\"owner_task_id\", \"eq\", query.ownerTaskId]);\n\t\t\treturn this.#scan<ConversationRecord>(this.#queries.conversations, conditions, start, limit, context);\n\t\t});\n\t}\n\n\tentry(id: EntryId, context: Context): Promise<StoredEntry | undefined>;\n\tentry(conversationId: ConversationId, id: EntryId, context: Context): Promise<StoredEntry | undefined>;\n\tentry(\n\t\tidOrConversationId: EntryId | ConversationId,\n\t\tidOrContext: EntryId | Context,\n\t\tmaybeContext?: Context,\n\t): Promise<StoredEntry | undefined> {\n\t\tif (maybeContext === undefined) {\n\t\t\tconst context = idOrContext as Context;\n\t\t\treturn this.#read((executor) => this.#entry(executor, idOrConversationId as EntryId, context), context);\n\t\t}\n\t\tconst context = maybeContext;\n\t\tconst id = typeof idOrContext === \"number\" ? idFromNumber<EntryId>(idOrContext) : undefined;\n\t\treturn this.#reading(() => {\n\t\t\tif (id === undefined) throw new StorageRequestError(\"Storage.entry() requires an entry ID\");\n\t\t\tconst conversationId = idOrConversationId as ConversationId;\n\t\t\treturn this.#store\n\t\t\t\t.read((executor) => this.#visibleEntry(executor, conversationId, id, context), context)\n\t\t\t\t.then(told);\n\t\t});\n\t}\n\n\tfindLatestHeadMarker(\n\t\tconversationId: ConversationId,\n\t\tatOrBeforeEntryId: EntryId | undefined,\n\t\tcontext: Context,\n\t): Promise<(EntryRecord & { readonly head: EntryId }) | undefined> {\n\t\treturn this.#reading(() =>\n\t\t\tthis.#store\n\t\t\t\t.read((executor) => this.#latestHeadMarker(executor, conversationId, atOrBeforeEntryId, context), context)\n\t\t\t\t.then(told),\n\t\t);\n\t}\n\n\tscanEntries(\n\t\tquery: EntryQuery,\n\t\tlimit: number,\n\t\tcursor: Cursor | undefined,\n\t\tcontext: Context,\n\t): Promise<Page<EntryRecord, Cursor>> {\n\t\treturn this.#reading(() => {\n\t\t\tconst { order, after } = scanStart(query.order, cursor, \"descending\");\n\t\t\tconst read =\n\t\t\t\torder === \"ascending\"\n\t\t\t\t\t? (executor: SqliteExecutor) => this.#entriesAscending(executor, query, limit, after, context)\n\t\t\t\t\t: (executor: SqliteExecutor) => this.#entriesDescending(executor, query, limit, after, context);\n\t\t\treturn this.#store.read(read, context).then(told);\n\t\t});\n\t}\n\n\ttask(id: TaskId, context: Context): Promise<StoredTask | undefined> {\n\t\tconst tasks = this.#queries.tasks;\n\t\treturn this.#read(async (executor) => {\n\t\t\tconst row = await tasks.byId(executor, id);\n\t\t\treturn row === undefined ? undefined : tasks.record<StoredTask>(row, context);\n\t\t}, context);\n\t}\n\n\tscanTasks(\n\t\tquery: TaskQuery,\n\t\tlimit: number,\n\t\tcursor: Cursor | undefined,\n\t\tcontext: Context,\n\t): Promise<Page<StoredTask, Cursor>> {\n\t\treturn this.#reading(() => {\n\t\t\tconst start = scanStart(query.order, cursor, \"ascending\");\n\t\t\tconst conditions: Condition[] = [scanFrom(start)];\n\t\t\tif (query.conversationId !== undefined) conditions.push([\"conversation_id\", \"eq\", query.conversationId]);\n\t\t\tif (query.kind !== undefined) conditions.push([\"kind\", \"eq\", encodeIndexed(query.kind)]);\n\t\t\tif (query.status !== undefined) conditions.push([\"status\", \"eq\", query.status]);\n\t\t\tif (query.abortRequested !== undefined)\n\t\t\t\tconditions.push([\"abort_requested\", \"eq\", query.abortRequested ? 1 : 0]);\n\t\t\tif (query.background !== undefined) conditions.push([\"background\", \"eq\", query.background ? 1 : 0]);\n\t\t\treturn this.#scan<StoredTask>(this.#queries.tasks, conditions, start, limit, context);\n\t\t});\n\t}\n\n\tsubmission(id: SubmissionId, context: Context): Promise<SubmissionRecord | undefined> {\n\t\tconst submissions = this.#queries.submissions;\n\t\treturn this.#read(async (executor) => {\n\t\t\tconst row = await submissions.byId(executor, id);\n\t\t\treturn row === undefined ? undefined : submissions.record<SubmissionRecord>(row, context);\n\t\t}, context);\n\t}\n\n\tscanSubmissions(\n\t\tquery: SubmissionQuery,\n\t\tlimit: number,\n\t\tcursor: Cursor | undefined,\n\t\tcontext: Context,\n\t): Promise<Page<SubmissionRecord, Cursor>> {\n\t\treturn this.#reading(() => {\n\t\t\tconst start = scanStart(query.order, cursor, \"ascending\");\n\t\t\tconst conditions: Condition[] = [scanFrom(start)];\n\t\t\tif (query.conversationId !== undefined) conditions.push([\"conversation_id\", \"eq\", query.conversationId]);\n\t\t\tif (query.status !== undefined) conditions.push([\"status\", \"eq\", query.status]);\n\t\t\treturn this.#scan<SubmissionRecord>(this.#queries.submissions, conditions, start, limit, context);\n\t\t});\n\t}\n\n\tsubmissionByRequest(\n\t\tconversationId: ConversationId,\n\t\trequestId: string,\n\t\tcontext: Context,\n\t): Promise<SubmissionRecord | undefined> {\n\t\tconst submissions = this.#queries.submissions;\n\t\tconst conditions: Condition[] = [\n\t\t\t[\"conversation_id\", \"eq\", conversationId],\n\t\t\t[\"request_id\", \"eq\", encodeIndexed(requestId)],\n\t\t];\n\t\treturn this.#read(async (executor) => {\n\t\t\tconst row = await submissions.first(executor, conditions, \"ascending\");\n\t\t\treturn row === undefined ? undefined : submissions.record<SubmissionRecord>(row, context);\n\t\t}, context);\n\t}\n\n\tfindDocument(address: DocumentAddress, at: DocumentPoint, context: Context): Promise<DocumentRecord | undefined> {\n\t\treturn this.#read(async (executor) => {\n\t\t\tconst entry = await findDocumentEntry(executor, addressOf(address, this.#owner), at);\n\t\t\treturn entry === undefined ? undefined : recordOfEntry(entry);\n\t\t}, context);\n\t}\n\n\tdocument(id: DocumentId, at: DocumentPoint, context: Context): Promise<StoredDocument | undefined> {\n\t\t// The record and its revisions must come from one committed state (S4).\n\t\treturn this.#reading(() =>\n\t\t\tthis.#store.readTransaction((executor) => readAt(executor, id, at, this.#owner), context).then(documentOf),\n\t\t);\n\t}\n\n\tscanDocuments(\n\t\tquery: DocumentQuery,\n\t\tlimit: number,\n\t\tcursor: Cursor | undefined,\n\t\tcontext: Context,\n\t): Promise<Page<DocumentRecord, Cursor>> {\n\t\treturn this.#reading(() => {\n\t\t\tconst after = cursorId(cursor) ?? -1;\n\t\t\tconst scope = {\n\t\t\t\towner: this.#owner,\n\t\t\t\tnamespace: namespaceOf(query.scope),\n\t\t\t\t...(query.kind === undefined ? {} : { kind: encodeIndexed(query.kind) }),\n\t\t\t};\n\t\t\treturn this.#store\n\t\t\t\t.read((executor) => listDocumentEntries(executor, scope, query.at, after, limit + 1), context)\n\t\t\t\t.then((found) => page(found.map(recordOfEntry), limit, \"ascending\"));\n\t\t});\n\t}\n\n\t/**\n\t * Refuses new calls, waits for its commits underway, then releases its claims; the store stays open (the app's),\n\t * and finishes the reads underway, which change nothing.\n\t */\n\tclose(_context: Context): Promise<void> {\n\t\tif (this.#closing === undefined) {\n\t\t\tthis.#closed = true;\n\t\t\tthis.#closing = (async () => {\n\t\t\t\tif (this.#underway > 0) {\n\t\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\t\tthis.#drained = resolve;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthis.#store.claims.release(this.#claimant);\n\t\t\t})();\n\t\t}\n\t\treturn this.#closing;\n\t}\n\n\t/** Runs one commit or mint of this storage: refused once it closed, counted until it settles (`close` waits). */\n\tasync #call<T>(run: () => Promise<T>): Promise<T> {\n\t\tif (this.#closed) throw new Error(\"StoreStorage is closed\");\n\t\tthis.#underway++;\n\t\ttry {\n\t\t\treturn await run();\n\t\t} finally {\n\t\t\tif (--this.#underway === 0) this.#drained?.();\n\t\t}\n\t}\n\n\t/**\n\t * A call that is one guarded read of the store: refused once closed; not waited for by `close` (a read changes\n\t * nothing, and the store, which stays open, finishes it).\n\t */\n\t#read<T>(read: (executor: SqliteExecutor) => Promise<T>, context: Context): Promise<T> {\n\t\treturn this.#reading(() => this.#store.read(read, context));\n\t}\n\n\t/**\n\t * A read call: `read` prepares its guarded read (a request error thrown then, before it) and returns it. Refused\n\t * once closed; one promise per call besides the guard's (no async wrapper).\n\t */\n\t#reading<T>(read: () => Promise<T>): Promise<T> {\n\t\ttry {\n\t\t\tif (this.#closed) throw new Error(\"StoreStorage is closed\");\n\t\t\treturn read();\n\t\t} catch (error) {\n\t\t\treturn Promise.reject(error);\n\t\t}\n\t}\n\n\tasync #conversation(\n\t\texecutor: SqliteExecutor,\n\t\tid: ConversationId,\n\t\tcontext: Context,\n\t): Promise<ConversationRecord | undefined> {\n\t\tconst conversations = this.#queries.conversations;\n\t\tconst row = await conversations.byId(executor, id);\n\t\treturn row === undefined ? undefined : conversations.record<ConversationRecord>(row, context);\n\t}\n\n\t#entry(executor: SqliteExecutor, id: EntryId, context: Context): Promise<StoredEntry | undefined> {\n\t\tconst entries = this.#queries.entries;\n\t\treturn entries.byId(executor, id).then((row) => {\n\t\t\tif (row === undefined) return undefined;\n\t\t\treturn { entry: entries.record<EntryRecord>(row, context), commitSeq: seqFromNumber(row.commit_seq!) };\n\t\t});\n\t}\n\n\t/** Entry `id` when visible through `conversationId`'s fork chain (`SqliteStorage.readEntry`). */\n\tasync #visibleEntry(\n\t\texecutor: SqliteExecutor,\n\t\tconversationId: ConversationId,\n\t\tid: EntryId,\n\t\tcontext: Context,\n\t): Promise<Read<StoredEntry | undefined>> {\n\t\tlet conversation = await this.#conversation(executor, conversationId, context);\n\t\tif (conversation === undefined) return unknownConversation(conversationId);\n\t\tconst stored = await this.#entry(executor, id, context);\n\t\tif (stored === undefined) return NOTHING_FOUND;\n\t\tlet upper = Number.POSITIVE_INFINITY;\n\t\twhile (conversation.id !== stored.entry.conversationId) {\n\t\t\tif (conversation.parent === undefined) return NOTHING_FOUND;\n\t\t\tupper = Math.min(upper, conversation.parent.at);\n\t\t\tconversation = (await this.#conversation(executor, conversation.parent.conversationId, context))!;\n\t\t}\n\t\treturn stored.entry.id > upper ? NOTHING_FOUND : { kind: \"found\", value: stored };\n\t}\n\n\tasync #latestHeadMarker(\n\t\texecutor: SqliteExecutor,\n\t\tconversationId: ConversationId,\n\t\tatOrBeforeEntryId: EntryId | undefined,\n\t\tcontext: Context,\n\t): Promise<Read<(EntryRecord & { readonly head: EntryId }) | undefined>> {\n\t\tlet conversation = await this.#conversation(executor, conversationId, context);\n\t\tif (conversation === undefined) return unknownConversation(conversationId);\n\t\tlet upper: number | undefined = atOrBeforeEntryId;\n\t\twhile (true) {\n\t\t\tconst { latestHead } = this.#queries;\n\t\t\tconst head =\n\t\t\t\tupper === undefined\n\t\t\t\t\t? await executor.get<{ readonly id: number }>(latestHead.any, conversation.id)\n\t\t\t\t\t: await executor.get<{ readonly id: number }>(latestHead.atOrBefore, conversation.id, upper);\n\t\t\tif (head !== undefined) {\n\t\t\t\t// Written with its entry, in the same commit.\n\t\t\t\tconst row = (await this.#queries.entries.byId(executor, head.id))!;\n\t\t\t\tconst value = this.#queries.entries.record<EntryRecord & { readonly head: EntryId }>(row, context);\n\t\t\t\treturn { kind: \"found\", value };\n\t\t\t}\n\t\t\tif (conversation.parent === undefined) return NOTHING_FOUND;\n\t\t\tupper = upper === undefined ? conversation.parent.at : Math.min(upper, conversation.parent.at);\n\t\t\tconversation = (await this.#conversation(executor, conversation.parent.conversationId, context))!;\n\t\t}\n\t}\n\n\t/** Newest first: each conversation of the fork chain up to its fork point (`SqliteStorage.readEntries`). */\n\tasync #entriesDescending(\n\t\texecutor: SqliteExecutor,\n\t\tquery: EntryQuery,\n\t\tlimit: number,\n\t\tafter: number | undefined,\n\t\tcontext: Context,\n\t): Promise<Read<Page<EntryRecord, Cursor>>> {\n\t\tlet conversation = await this.#conversation(executor, query.conversationId, context);\n\t\tif (conversation === undefined) return unknownConversation(query.conversationId);\n\t\tlet upper: number | undefined = query.maxEntryId;\n\t\tif (after !== undefined) upper = Math.min(upper ?? Number.MAX_SAFE_INTEGER, after - 1);\n\t\tconst values: EntryRecord[] = [];\n\t\twhile (true) {\n\t\t\tconst range = this.#range(conversation.id, query.minEntryId, upper);\n\t\t\tconst rows = await this.#queries.entries.select(executor, range, \"descending\", limit + 1 - values.length);\n\t\t\tthis.#queries.entries.records(rows, values, context);\n\t\t\tif (values.length > limit || conversation.parent === undefined) break;\n\t\t\tupper = upper === undefined ? conversation.parent.at : Math.min(upper, conversation.parent.at);\n\t\t\tif (query.minEntryId !== undefined && upper < query.minEntryId) break;\n\t\t\tconversation = (await this.#conversation(executor, conversation.parent.conversationId, context))!;\n\t\t}\n\t\treturn { kind: \"found\", value: page(values, limit, \"descending\") };\n\t}\n\n\t/** Oldest first: the fork chain's segments from the root forward, each up to its fork point. */\n\tasync #entriesAscending(\n\t\texecutor: SqliteExecutor,\n\t\tquery: EntryQuery,\n\t\tlimit: number,\n\t\tafter: number | undefined,\n\t\tcontext: Context,\n\t): Promise<Read<Page<EntryRecord, Cursor>>> {\n\t\tconst segments: { readonly conversationId: ConversationId; readonly upper: number | undefined }[] = [];\n\t\tlet conversation = await this.#conversation(executor, query.conversationId, context);\n\t\tif (conversation === undefined) return unknownConversation(query.conversationId);\n\t\tlet upper: number | undefined = query.maxEntryId;\n\t\twhile (true) {\n\t\t\tsegments.push({ conversationId: conversation.id, upper });\n\t\t\tif (conversation.parent === undefined) break;\n\t\t\tupper = upper === undefined ? conversation.parent.at : Math.min(upper, conversation.parent.at);\n\t\t\tif (query.minEntryId !== undefined && upper < query.minEntryId) break;\n\t\t\tconversation = (await this.#conversation(executor, conversation.parent.conversationId, context))!;\n\t\t}\n\t\tlet lower: number | undefined = query.minEntryId;\n\t\tif (after !== undefined) lower = Math.max(lower ?? after + 1, after + 1);\n\t\tconst values: EntryRecord[] = [];\n\t\tfor (const segment of segments.reverse()) {\n\t\t\tconst range = this.#range(segment.conversationId, lower, segment.upper);\n\t\t\tconst rows = await this.#queries.entries.select(executor, range, \"ascending\", limit + 1 - values.length);\n\t\t\tthis.#queries.entries.records(rows, values, context);\n\t\t\tif (values.length > limit) break;\n\t\t}\n\t\treturn { kind: \"found\", value: page(values, limit, \"ascending\") };\n\t}\n\n\t/** One conversation's entries with ids from `lower` to `upper` (inclusive, each optional). */\n\t#range(conversationId: ConversationId, lower: number | undefined, upper: number | undefined): Condition[] {\n\t\tconst conditions: Condition[] = [[\"conversation_id\", \"eq\", conversationId]];\n\t\tif (lower !== undefined) conditions.push([\"id\", \"gte\", lower]);\n\t\tif (upper !== undefined) conditions.push([\"id\", \"lte\", upper]);\n\t\treturn conditions;\n\t}\n\n\t/** A page of a table scan: up to `limit` records of `queries`' table whose `conditions` hold, from `start`. */\n\t#scan<T extends { readonly id: Id<string> }>(\n\t\tqueries: TableQueries,\n\t\tconditions: readonly Condition[],\n\t\tstart: ScanStart,\n\t\tlimit: number,\n\t\tcontext: Context,\n\t): Promise<Page<T, Cursor>> {\n\t\treturn this.#store\n\t\t\t.read((executor) => queries.select(executor, conditions, start.order, limit + 1), context)\n\t\t\t.then((rows) => {\n\t\t\t\tconst values: T[] = [];\n\t\t\t\tqueries.records(rows, values, context);\n\t\t\t\treturn page(values, limit, start.order);\n\t\t\t});\n\t}\n}\n\n/** A read that found nothing. */\nconst NOTHING_FOUND: Read<undefined> = { kind: \"found\", value: undefined };\n\nfunction unknownConversation(id: ConversationId): Read<never> {\n\treturn { kind: \"refused\", message: `Unknown conversation: ${id}` };\n}\n\n/** A read's data, its request error thrown now that the guarded read returned (slice 6b §1.4). */\nfunction told<T>(read: Read<T>): T {\n\tif (read.kind === \"refused\") throw new StorageRequestError(read.message);\n\treturn read.value;\n}\n\n/** A document read's result, a record that keeps no history at the point thrown as Durable's request error. */\nfunction documentOf(read: DocumentRead): StoredDocument | undefined {\n\tif (read.kind === \"current_only\")\n\t\tthrow new StorageRequestError(`Document ${read.id} does not retain historical content`);\n\treturn read.document;\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { JsonValue } from "@earendil-works/chord/json";
|
|
2
|
+
import type { ConversationRecord, EntryRecord, SubmissionRecord, TaskRecord } from "../../types.ts";
|
|
3
|
+
/** Which record type owns an id: Durable's one namespace across its five record types. */
|
|
4
|
+
export declare const RecordIds: import("@earendil-works/chord").TableDefinition<{
|
|
5
|
+
id: import("@earendil-works/chord").IntegerSchema;
|
|
6
|
+
record_type: import("@earendil-works/chord").StringSchema;
|
|
7
|
+
}, readonly ["id"], 1>;
|
|
8
|
+
export declare const Conversations: import("@earendil-works/chord").TableDefinition<{
|
|
9
|
+
id: import("@earendil-works/chord").IntegerSchema;
|
|
10
|
+
owner_conversation_id: import("@earendil-works/chord").IntegerSchema;
|
|
11
|
+
owner_task_id: import("@earendil-works/chord").IntegerSchema;
|
|
12
|
+
record: import("@earendil-works/chord").JsonColumnSchema<unknown>;
|
|
13
|
+
}, readonly ["id"], 1>;
|
|
14
|
+
export declare const Entries: import("@earendil-works/chord").TableDefinition<{
|
|
15
|
+
id: import("@earendil-works/chord").IntegerSchema;
|
|
16
|
+
conversation_id: import("@earendil-works/chord").IntegerSchema;
|
|
17
|
+
commit_seq: import("@earendil-works/chord").IntegerSchema;
|
|
18
|
+
record: import("@earendil-works/chord").JsonColumnSchema<unknown>;
|
|
19
|
+
}, readonly ["id"], 1>;
|
|
20
|
+
/**
|
|
21
|
+
* The entries with a head marker, by conversation: what `SqliteStorage`'s partial index on `head IS NOT NULL` is,
|
|
22
|
+
* as rows written only with such an entry, so a commit of an entry without one updates no second index.
|
|
23
|
+
*/
|
|
24
|
+
export declare const EntryHeads: import("@earendil-works/chord").TableDefinition<{
|
|
25
|
+
id: import("@earendil-works/chord").IntegerSchema;
|
|
26
|
+
conversation_id: import("@earendil-works/chord").IntegerSchema;
|
|
27
|
+
}, readonly ["id"], 1>;
|
|
28
|
+
export declare const Tasks: import("@earendil-works/chord").TableDefinition<{
|
|
29
|
+
id: import("@earendil-works/chord").IntegerSchema;
|
|
30
|
+
conversation_id: import("@earendil-works/chord").IntegerSchema;
|
|
31
|
+
kind: import("@earendil-works/chord").StringSchema;
|
|
32
|
+
status: import("@earendil-works/chord").StringSchema;
|
|
33
|
+
abort_requested: import("@earendil-works/chord").IntegerSchema;
|
|
34
|
+
background: import("@earendil-works/chord").IntegerSchema;
|
|
35
|
+
record: import("@earendil-works/chord").JsonColumnSchema<unknown>;
|
|
36
|
+
}, readonly ["id"], 1>;
|
|
37
|
+
export declare const Submissions: import("@earendil-works/chord").TableDefinition<{
|
|
38
|
+
id: import("@earendil-works/chord").IntegerSchema;
|
|
39
|
+
conversation_id: import("@earendil-works/chord").IntegerSchema;
|
|
40
|
+
request_id: import("@earendil-works/chord").StringSchema;
|
|
41
|
+
status: import("@earendil-works/chord").StringSchema;
|
|
42
|
+
record: import("@earendil-works/chord").JsonColumnSchema<unknown>;
|
|
43
|
+
}, readonly ["id"], 1>;
|
|
44
|
+
/** Durable's JSON encoding of an indexed string: lossless whatever the string (lone surrogates, NUL). */
|
|
45
|
+
export declare const encodeIndexed: (value: string) => string;
|
|
46
|
+
/** The row of a conversation record. */
|
|
47
|
+
export declare function conversationRow(value: ConversationRecord): object;
|
|
48
|
+
/** The row of an entry record; `commit_seq` is stamped by the step. */
|
|
49
|
+
export declare function entryRow(value: EntryRecord): object;
|
|
50
|
+
/** The row of a task record. */
|
|
51
|
+
export declare function taskRow(value: TaskRecord<JsonValue, JsonValue, JsonValue>): object;
|
|
52
|
+
/** The row of a submission record. */
|
|
53
|
+
export declare function submissionRow(value: SubmissionRecord): object;
|
|
54
|
+
//# sourceMappingURL=tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../src/storage/store/tables.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAKpG,0FAA0F;AAC1F,eAAO,MAAM,SAAS;;;sBAIpB,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;sBAKxB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;sBAKlB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,UAAU;;;sBAKrB,CAAC;AAEH,eAAO,MAAM,KAAK;;;;;;;;sBAmBhB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;sBAStB,CAAC;AAEH,yGAAyG;AACzG,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,MAA+B,CAAC;AAE9E,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAOjE;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAOnD;AAED,gCAAgC;AAChC,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,MAAM,CAUlF;AAED,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAQ7D"}
|