@earendil-works/pi-durable 1.3.0 → 1.5.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/CHANGELOG.md +227 -0
- package/README.md +287 -82
- package/dist/codemode/codemode.d.ts +4 -4
- package/dist/codemode/codemode.d.ts.map +1 -1
- package/dist/codemode/codemode.js +21 -16
- package/dist/codemode/codemode.js.map +1 -1
- package/dist/codemode/models.d.ts.map +1 -1
- package/dist/codemode/models.js +6 -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.map +1 -1
- package/dist/env/index.d.ts +12 -10
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js.map +1 -1
- package/dist/env/node-watch.d.ts +3 -3
- 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 +2 -2
- package/dist/env/node.d.ts.map +1 -1
- package/dist/env/node.js +12 -4
- 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 +13 -2
- package/dist/harness/agent.d.ts.map +1 -1
- package/dist/harness/agent.js +48 -6
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/compaction.d.ts +3 -1
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +38 -6
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/context.d.ts +23 -7
- 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 +7 -3
- 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 +38 -5
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +497 -108
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts +7 -2
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +147 -57
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +7 -3
- package/dist/harness/inbox.d.ts.map +1 -1
- package/dist/harness/inbox.js +7 -4
- package/dist/harness/inbox.js.map +1 -1
- package/dist/harness/json.d.ts +20 -4
- 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 +122 -16
- 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 +162 -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 +1 -1
- package/dist/harness/prompt.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 +86 -14
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +1459 -369
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +23 -11
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +104 -36
- package/dist/harness/submissions.js.map +1 -1
- package/dist/harness/task-graph.d.ts +28 -8
- package/dist/harness/task-graph.d.ts.map +1 -1
- package/dist/harness/task-graph.js +85 -36
- package/dist/harness/task-graph.js.map +1 -1
- package/dist/harness/telemetry.d.ts +307 -0
- package/dist/harness/telemetry.d.ts.map +1 -0
- package/dist/harness/telemetry.js +136 -0
- package/dist/harness/telemetry.js.map +1 -0
- package/dist/harness/tool.d.ts +2 -0
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +223 -61
- 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 +302 -48
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/util.d.ts +7 -1
- package/dist/harness/util.d.ts.map +1 -1
- package/dist/harness/util.js +13 -0
- package/dist/harness/util.js.map +1 -1
- package/dist/harness/view.d.ts +43 -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 +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- 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 +71 -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/keys.d.ts +68 -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 +181 -29
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +1073 -183
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts +86 -4
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +250 -38
- 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 +68 -0
- package/dist/storage/indexeddb.d.ts.map +1 -0
- package/dist/storage/indexeddb.js +881 -0
- package/dist/storage/indexeddb.js.map +1 -0
- package/dist/storage/jsonl/storage.d.ts +30 -2
- package/dist/storage/jsonl/storage.d.ts.map +1 -1
- package/dist/storage/jsonl/storage.js +88 -24
- package/dist/storage/jsonl/storage.js.map +1 -1
- package/dist/storage/memory.d.ts +7 -2
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +29 -3
- package/dist/storage/memory.js.map +1 -1
- package/dist/storage/sqlite/cloudflare.d.ts +2 -51
- package/dist/storage/sqlite/cloudflare.d.ts.map +1 -1
- package/dist/storage/sqlite/cloudflare.js +2 -133
- package/dist/storage/sqlite/cloudflare.js.map +1 -1
- package/dist/storage/sqlite/database.d.ts +1 -36
- package/dist/storage/sqlite/database.d.ts.map +1 -1
- package/dist/storage/sqlite/database.js.map +1 -1
- package/dist/storage/sqlite/index.d.ts +1 -1
- package/dist/storage/sqlite/index.d.ts.map +1 -1
- package/dist/storage/sqlite/index.js.map +1 -1
- package/dist/storage/sqlite/migrations.d.ts +2 -5
- package/dist/storage/sqlite/migrations.d.ts.map +1 -1
- package/dist/storage/sqlite/migrations.js +28 -28
- package/dist/storage/sqlite/migrations.js.map +1 -1
- package/dist/storage/sqlite/node.d.ts +2 -37
- package/dist/storage/sqlite/node.d.ts.map +1 -1
- package/dist/storage/sqlite/node.js +3 -174
- package/dist/storage/sqlite/node.js.map +1 -1
- package/dist/storage/sqlite/schema.d.ts +1 -3
- package/dist/storage/sqlite/schema.d.ts.map +1 -1
- package/dist/storage/sqlite/schema.js +2 -9
- package/dist/storage/sqlite/schema.js.map +1 -1
- package/dist/storage/sqlite/storage.d.ts +15 -3
- package/dist/storage/sqlite/storage.d.ts.map +1 -1
- package/dist/storage/sqlite/storage.js +110 -36
- 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 +59 -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 +369 -67
- package/dist/testing/storage-conformance.js.map +1 -1
- package/dist/timers.d.ts +21 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +72 -0
- package/dist/timers.js.map +1 -0
- package/dist/tool-search/tool-search.d.ts +6 -12
- package/dist/tool-search/tool-search.d.ts.map +1 -1
- package/dist/tool-search/tool-search.js +7 -7
- package/dist/tool-search/tool-search.js.map +1 -1
- package/dist/tools/bash.d.ts +12 -12
- 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/index.d.ts +32 -32
- 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 +331 -64
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +27 -10
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Context, type Draft, type JsonValue } from "@earendil-works/chord";
|
|
2
|
-
import { type Tracker } from "@earendil-works/chord/delta";
|
|
2
|
+
import { type Op, type PendingOps, type Tracker } from "@earendil-works/chord/delta";
|
|
3
3
|
import { type AnyDocDefinition } from "../documents.ts";
|
|
4
|
-
import type { ConversationDocFamilyToken, ConversationDocToken, ConversationId, ConversationOwnership, ConversationQuery, ConversationRecord, Cursor, DocumentAddress, DocumentCommitChange, DocumentId, DocumentRecord, Entry, EntryDraft, EntryId, EntryQuery, EntryRecord, JsonObject, Seq, SessionDocFamilyToken, SessionDocToken, Storage, StorageWrite, SubmissionCreate, SubmissionId, SubmissionRecord, SubmissionSettlement, Task, TaskDocFamilyToken, TaskDocToken, TaskId, TaskOptions, TaskQuery, TaskRecord, Tx, TypedEntry, TypedEntryDraft } from "../types.ts";
|
|
4
|
+
import type { ConversationDocFamilyToken, ConversationDocToken, ConversationId, ConversationOwnership, ConversationQuery, ConversationRecord, Cursor, DocumentAddress, DocumentCommitChange, DocumentContent, DocumentId, DocumentRecord, Entry, EntryDraft, EntryId, EntryQuery, EntryRecord, JsonObject, Seq, SessionDocFamilyToken, SessionDocToken, Storage, StorageWrite, SubmissionCreate, SubmissionId, SubmissionRecord, SubmissionSettlement, Task, TaskDocFamilyToken, TaskDocToken, TaskId, TaskOptions, TaskQuery, TaskRecord, Tx, TypedEntry, TypedEntryDraft } from "../types.ts";
|
|
5
5
|
type AnyTaskRecord = TaskRecord<JsonValue, JsonValue, JsonValue>;
|
|
6
6
|
/** One committed document incarnation owned by the Session tracker cache. */
|
|
7
7
|
export type LoadedDocument = {
|
|
@@ -15,9 +15,29 @@ export type LoadedDocument = {
|
|
|
15
15
|
deltasSinceBase: number;
|
|
16
16
|
readonly tracker: Tracker<JsonObject>;
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* The changes of a cached incarnation that deferred commits adopted in memory and the Session has not stored yet
|
|
20
|
+
* (`CommitPersistence`), folded. The Session owns it; a commit that stores them takes them.
|
|
21
|
+
*/
|
|
22
|
+
export type HeldDocument = {
|
|
23
|
+
readonly loaded: LoadedDocument;
|
|
24
|
+
readonly pending: PendingOps;
|
|
25
|
+
/** Set when a held commit selected a base (`checkpointWhen`): their store writes the whole value. */
|
|
26
|
+
base: boolean;
|
|
27
|
+
};
|
|
28
|
+
/** What adoption publishes: to the Session's own observers, and the stored changes to `observeCommits()`. */
|
|
29
|
+
export type AdoptedDocuments = {
|
|
30
|
+
/** This commit's own changes, as memory adopted them. */
|
|
31
|
+
readonly observed: readonly DocumentCommitChange[];
|
|
32
|
+
/** What Storage got: `observed`, unless the commit also stored held changes, which precede its own. */
|
|
33
|
+
readonly stored: readonly DocumentCommitChange[];
|
|
34
|
+
};
|
|
18
35
|
/** Session services used by a transaction while it holds the mutation line. */
|
|
19
36
|
export interface TransactionHost {
|
|
37
|
+
/** Reads wait while their key has an unpublished writer (`GatedStorage`). */
|
|
20
38
|
readonly storage: Storage;
|
|
39
|
+
/** Wait while `key` has an unpublished writer; `undefined` when it has none. */
|
|
40
|
+
touch(key: string): Promise<void> | undefined;
|
|
21
41
|
/** Wall clock for task lifecycle times. */
|
|
22
42
|
now(): number;
|
|
23
43
|
/** Return the cached current incarnation without loading. */
|
|
@@ -30,7 +50,21 @@ export interface TransactionHost {
|
|
|
30
50
|
evict(addressId: string, recordId: DocumentId): void;
|
|
31
51
|
/** Stage writes that belong to every newly created or forked conversation, in its creating transaction. */
|
|
32
52
|
conversationCreated(tx: Transaction, record: ConversationRecord): Promise<void>;
|
|
53
|
+
/** The newest entry ID visible from a conversation, known from the Session's commits. */
|
|
54
|
+
latestEntryId(conversationId: ConversationId, context: Context): Promise<EntryId | undefined>;
|
|
55
|
+
/**
|
|
56
|
+
* The current documents of a live task when the Session knows all of them (it created the task), else `undefined`.
|
|
57
|
+
*/
|
|
58
|
+
taskDocuments(taskId: TaskId): Iterable<DocumentRecord> | undefined;
|
|
59
|
+
/** The newest visible head marker of a conversation, known from the Session's commits. */
|
|
60
|
+
latestHeadMarker(conversationId: ConversationId, context: Context): Promise<(EntryRecord & {
|
|
61
|
+
readonly head: EntryId;
|
|
62
|
+
}) | undefined>;
|
|
33
63
|
}
|
|
64
|
+
/** Internal run creation resolves submission carriers against staged records before reading storage. */
|
|
65
|
+
export type TaskCreationOptions = TaskOptions & {
|
|
66
|
+
readonly submissionIds?: readonly SubmissionId[];
|
|
67
|
+
};
|
|
34
68
|
/** Defaults a commit binds to: `tx.createTask()` conversation and the task attributed to appended entries. */
|
|
35
69
|
export type TransactionScope = {
|
|
36
70
|
readonly conversationId?: ConversationId;
|
|
@@ -46,6 +80,15 @@ export type TransactionScope = {
|
|
|
46
80
|
export declare class Transaction implements Tx {
|
|
47
81
|
#private;
|
|
48
82
|
constructor(host: TransactionHost, context: Context, scope?: TransactionScope);
|
|
83
|
+
/** Internal: the context of the commit this transaction belongs to. */
|
|
84
|
+
get context(): Context;
|
|
85
|
+
/** Internal: whether a table write was staged, after which table reads throw `ReadAfterWrite`. */
|
|
86
|
+
get hasTableWrite(): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Internal: whether `tx` is a transaction of a commit of the Session behind `host`. A brand check, so a proxy or
|
|
89
|
+
* another wrapper of a transaction is not one.
|
|
90
|
+
*/
|
|
91
|
+
static ownedBy(tx: Tx, host: TransactionHost): tx is Transaction;
|
|
49
92
|
conversation(id: ConversationId): Promise<ConversationRecord | undefined>;
|
|
50
93
|
entry(id: EntryId): Promise<EntryRecord | undefined>;
|
|
51
94
|
entry<D extends JsonValue>(token: Entry<D>, id: EntryId): Promise<TypedEntry<D> | undefined>;
|
|
@@ -55,6 +98,7 @@ export declare class Transaction implements Tx {
|
|
|
55
98
|
latestHeadMarker(conversationId: ConversationId): Promise<(EntryRecord & {
|
|
56
99
|
readonly head: EntryId;
|
|
57
100
|
}) | undefined>;
|
|
101
|
+
latestEntryId(conversationId: ConversationId): Promise<EntryId | undefined>;
|
|
58
102
|
scanTasks(query: TaskQuery, limit: number, cursor?: Cursor): Promise<import("../types.ts").Page<TaskRecord<JsonValue, JsonValue, JsonValue>, Readonly<Record<string, JsonValue>>>>;
|
|
59
103
|
/** Internal: committed submission record. */
|
|
60
104
|
submission(id: SubmissionId): Promise<SubmissionRecord | undefined>;
|
|
@@ -72,7 +116,7 @@ export declare class Transaction implements Tx {
|
|
|
72
116
|
appendEntry<D extends JsonValue>(token: Entry<D>, conversationId: ConversationId, value: TypedEntryDraft<NoInfer<D>>): Promise<TypedEntry<D>>;
|
|
73
117
|
createTask<I, S extends {
|
|
74
118
|
phase: string;
|
|
75
|
-
}, R, H extends object>(task: Task<I, S, R, H>, input: I, options:
|
|
119
|
+
}, R, H extends object>(task: Task<I, S, R, H>, input: I, options: TaskCreationOptions): Promise<TaskId<R>>;
|
|
76
120
|
/** Create a raw submission record with a fresh ID; no admission rules apply. */
|
|
77
121
|
createSubmission(create: SubmissionCreate): Promise<SubmissionRecord>;
|
|
78
122
|
/**
|
|
@@ -86,6 +130,8 @@ export declare class Transaction implements Tx {
|
|
|
86
130
|
setTask(value: AnyTaskRecord): void;
|
|
87
131
|
/** Internal: candidate records of the tasks this transaction created or replaced so far. */
|
|
88
132
|
stagedTasks(): AnyTaskRecord[];
|
|
133
|
+
/** Internal: IDs of the tasks this transaction creates. */
|
|
134
|
+
createdTaskIds(): TaskId[];
|
|
89
135
|
/** Internal: conversations this transaction created or forked so far. */
|
|
90
136
|
stagedConversations(): ConversationRecord[];
|
|
91
137
|
doc<T extends JsonObject>(token: SessionDocToken<T>): Promise<Draft<T>>;
|
|
@@ -109,8 +155,44 @@ export declare class Transaction implements Tx {
|
|
|
109
155
|
settleSuccess(): Promise<readonly StorageWrite[]>;
|
|
110
156
|
/** Abort every prepared change after Storage failure or when no write is required. */
|
|
111
157
|
discard(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Internal: what a deferred commit holds in memory instead of storing (`CommitPersistence`), each changed incarnation
|
|
160
|
+
* with its operations and whether they selected a base; `undefined` when the commit must be stored. It may be held
|
|
161
|
+
* only when every write changes an existing `latest`, `initial`-fork conversation document at its stored version.
|
|
162
|
+
*/
|
|
163
|
+
holdable(): {
|
|
164
|
+
readonly loaded: LoadedDocument;
|
|
165
|
+
readonly ops: readonly Op[];
|
|
166
|
+
readonly base: boolean;
|
|
167
|
+
}[] | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* Internal: adopt a held commit (`holdable()`) in memory only. Trackers advance by pointer swap; stored versions and
|
|
170
|
+
* delta counts stay, as nothing was stored. Returns its publication for the Session's own observers.
|
|
171
|
+
*/
|
|
172
|
+
adoptHeld(): DocumentCommitChange[];
|
|
173
|
+
/**
|
|
174
|
+
* Internal: store the held changes of every incarnation this commit reads or writes in front of its own, so a stored
|
|
175
|
+
* document never misses an operation its later ones build on. Called right before Storage admission, after every
|
|
176
|
+
* fallible step, because it empties the holds: a failure earlier keeps them. Returns the holds it took.
|
|
177
|
+
*/
|
|
178
|
+
takeHeld<H extends HeldDocument>(held: (id: DocumentId) => H | undefined): H[];
|
|
179
|
+
/**
|
|
180
|
+
* Internal: the keys this commit writes, once settled (and after `takeHeld()`), for the Session's unpublished write
|
|
181
|
+
* set: its table records, and the address and incarnation of every document it creates, changes, or retires, with
|
|
182
|
+
* the scope of every incarnation it creates or retires.
|
|
183
|
+
*/
|
|
184
|
+
writeKeys(): string[];
|
|
112
185
|
/** Adopt every prepared change by pointer swap after Storage success and describe the publication. */
|
|
113
|
-
adopt(seq: Seq):
|
|
186
|
+
adopt(seq: Seq): AdoptedDocuments;
|
|
114
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Take a hold's changes after `ops`, a commit's own on top of them, as one stored content for an incarnation now at
|
|
190
|
+
* `value`, and the operations a reader of the stored state applies to reach it: the folded ones, or a root replacement
|
|
191
|
+
* after the queue overflowed, which stores a base, as does a hold whose commits selected one.
|
|
192
|
+
*/
|
|
193
|
+
export declare function storeHeld(hold: HeldDocument, ops: readonly Op[], value: JsonObject, version: number): {
|
|
194
|
+
readonly content: DocumentContent;
|
|
195
|
+
readonly ops: readonly Op[];
|
|
196
|
+
};
|
|
115
197
|
export {};
|
|
116
198
|
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/session/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAY,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/session/transaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { copyJson } from "@earendil-works/chord";
|
|
2
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
3
|
import { track } from "@earendil-works/chord/delta";
|
|
3
4
|
import { addressId, checkRecordScope, checkRecordVersion, documentCreate, materializeDocumentValue, resolveAddress, } from "../documents.js";
|
|
4
5
|
import { ReadAfterWrite } from "../errors.js";
|
|
5
6
|
import { ROOT_CONVERSATION_ID } from "../types.js";
|
|
6
7
|
import { prepareForkDocumentCopies } from "./forks.js";
|
|
8
|
+
import { documentKey, incarnationKey, scopeKey, tableKeys } from "./keys.js";
|
|
7
9
|
/**
|
|
8
|
-
* Complete record after applying one change. Placement turns a queued input `placed` and a queued write `done`;
|
|
9
|
-
* placed input can be answered. A settled record stays.
|
|
10
|
+
* Complete record after applying one change. Placement turns a queued input `placed` and a queued write `done`; a
|
|
11
|
+
* continue is never queued, so never placed. Only a placed input or continue can be answered. A settled record stays.
|
|
10
12
|
*/
|
|
11
13
|
function applySubmissionChange(current, change) {
|
|
12
14
|
if (current.status === "done" || current.status === "unanswered")
|
|
@@ -18,7 +20,7 @@ function applySubmissionChange(current, change) {
|
|
|
18
20
|
return { ...current, status, entry: change.entry };
|
|
19
21
|
}
|
|
20
22
|
if (change.status === "done" && current.status !== "placed") {
|
|
21
|
-
throw new Error(`Submission ${current.id} is not a placed input`);
|
|
23
|
+
throw new Error(`Submission ${current.id} is not a placed input or continue`);
|
|
22
24
|
}
|
|
23
25
|
// Queued and placed records carry no answer, reason, or detail; an unanswered input keeps its entry.
|
|
24
26
|
return { ...current, ...change };
|
|
@@ -61,6 +63,21 @@ export class Transaction {
|
|
|
61
63
|
this.#context = context;
|
|
62
64
|
this.#scope = scope;
|
|
63
65
|
}
|
|
66
|
+
/** Internal: the context of the commit this transaction belongs to. */
|
|
67
|
+
get context() {
|
|
68
|
+
return this.#context;
|
|
69
|
+
}
|
|
70
|
+
/** Internal: whether a table write was staged, after which table reads throw `ReadAfterWrite`. */
|
|
71
|
+
get hasTableWrite() {
|
|
72
|
+
return this.#hasTableWrite;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Internal: whether `tx` is a transaction of a commit of the Session behind `host`. A brand check, so a proxy or
|
|
76
|
+
* another wrapper of a transaction is not one.
|
|
77
|
+
*/
|
|
78
|
+
static ownedBy(tx, host) {
|
|
79
|
+
return #host in tx && tx.#host === host;
|
|
80
|
+
}
|
|
64
81
|
// ─── Table reads ────────────────────────────────────────────────────────
|
|
65
82
|
conversation(id) {
|
|
66
83
|
return this.#read("conversation", () => this.#host.storage.conversation(id, this.#context));
|
|
@@ -83,7 +100,10 @@ export class Transaction {
|
|
|
83
100
|
return this.#read("scanEntries", () => this.#host.storage.scanEntries(query, limit, cursor, this.#context));
|
|
84
101
|
}
|
|
85
102
|
latestHeadMarker(conversationId) {
|
|
86
|
-
return this.#read("latestHeadMarker", () => this.#host.
|
|
103
|
+
return this.#read("latestHeadMarker", () => this.#host.latestHeadMarker(conversationId, this.#context));
|
|
104
|
+
}
|
|
105
|
+
latestEntryId(conversationId) {
|
|
106
|
+
return this.#read("latestEntryId", () => this.#host.latestEntryId(conversationId, this.#context));
|
|
87
107
|
}
|
|
88
108
|
scanTasks(query, limit, cursor) {
|
|
89
109
|
return this.#read("scanTasks", () => this.#host.storage.scanTasks(query, limit, cursor, this.#context));
|
|
@@ -173,6 +193,21 @@ export class Transaction {
|
|
|
173
193
|
}
|
|
174
194
|
createTask(task, input, options) {
|
|
175
195
|
return this.#write(async () => {
|
|
196
|
+
if (options.submissionIds !== undefined) {
|
|
197
|
+
let trace;
|
|
198
|
+
let links;
|
|
199
|
+
for (let index = 0; index < options.submissionIds.length; index++) {
|
|
200
|
+
const id = options.submissionIds[index];
|
|
201
|
+
const submission = this.#submissions.get(id) ?? (await this.#host.storage.submission(id, this.#context));
|
|
202
|
+
if (index === 0)
|
|
203
|
+
trace = submission?.trace ?? "root";
|
|
204
|
+
else if (submission?.trace !== undefined) {
|
|
205
|
+
links ??= [];
|
|
206
|
+
links.push(submission.trace);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
options = { ...options, trace, links };
|
|
210
|
+
}
|
|
176
211
|
const ownership = options.ownership;
|
|
177
212
|
let owner;
|
|
178
213
|
if (ownership.kind === "task") {
|
|
@@ -202,6 +237,10 @@ export class Transaction {
|
|
|
202
237
|
kind: definition.name,
|
|
203
238
|
version: definition.version,
|
|
204
239
|
input,
|
|
240
|
+
trace: options.trace === "root"
|
|
241
|
+
? undefined
|
|
242
|
+
: (options.trace ?? this.#context.telemetry.propagation?.inject(this.#context.telemetry)),
|
|
243
|
+
links: options.links,
|
|
205
244
|
...(owner === undefined ? {} : { owner: owner.id }),
|
|
206
245
|
background: options.background ?? false,
|
|
207
246
|
abortRequested: false,
|
|
@@ -264,6 +303,14 @@ export class Transaction {
|
|
|
264
303
|
records.push(task.write.record);
|
|
265
304
|
return records;
|
|
266
305
|
}
|
|
306
|
+
/** Internal: IDs of the tasks this transaction creates. */
|
|
307
|
+
createdTaskIds() {
|
|
308
|
+
const ids = [];
|
|
309
|
+
for (const [id, task] of this.#tasksById)
|
|
310
|
+
if (task.write?.kind === "create")
|
|
311
|
+
ids.push(id);
|
|
312
|
+
return ids;
|
|
313
|
+
}
|
|
267
314
|
/** Internal: conversations this transaction created or forked so far. */
|
|
268
315
|
stagedConversations() {
|
|
269
316
|
const records = [];
|
|
@@ -394,6 +441,9 @@ export class Transaction {
|
|
|
394
441
|
return entry.change.state;
|
|
395
442
|
}
|
|
396
443
|
async #findRetirement(entry) {
|
|
444
|
+
const gate = this.#host.touch(documentKey(entry.addressId));
|
|
445
|
+
if (gate !== undefined)
|
|
446
|
+
await gate;
|
|
397
447
|
const record = this.#host.cached(entry.addressId)?.record ??
|
|
398
448
|
(await this.#host.storage.findDocument(entry.address, "current", this.#context));
|
|
399
449
|
this.#assertOpen();
|
|
@@ -408,6 +458,7 @@ export class Transaction {
|
|
|
408
458
|
this.#sealed = true;
|
|
409
459
|
this.#abortChanges();
|
|
410
460
|
await Promise.allSettled(this.#pendingOperations);
|
|
461
|
+
this.#context = BACKGROUND_CONTEXT;
|
|
411
462
|
}
|
|
412
463
|
/**
|
|
413
464
|
* Seal after callback success, prepare every open change, and assemble the atomic batch.
|
|
@@ -418,6 +469,7 @@ export class Transaction {
|
|
|
418
469
|
if (this.#pendingOperations.size > 0) {
|
|
419
470
|
this.#abortChanges();
|
|
420
471
|
await Promise.allSettled(this.#pendingOperations);
|
|
472
|
+
this.#context = BACKGROUND_CONTEXT;
|
|
421
473
|
throw new Error("Session commit callback settled before its pending Tx operations");
|
|
422
474
|
}
|
|
423
475
|
try {
|
|
@@ -432,14 +484,134 @@ export class Transaction {
|
|
|
432
484
|
this.#abortChanges();
|
|
433
485
|
throw error;
|
|
434
486
|
}
|
|
487
|
+
finally {
|
|
488
|
+
this.#context = BACKGROUND_CONTEXT;
|
|
489
|
+
}
|
|
435
490
|
}
|
|
436
491
|
/** Abort every prepared change after Storage failure or when no write is required. */
|
|
437
492
|
discard() {
|
|
438
493
|
this.#abortChanges();
|
|
439
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* Internal: what a deferred commit holds in memory instead of storing (`CommitPersistence`), each changed incarnation
|
|
497
|
+
* with its operations and whether they selected a base; `undefined` when the commit must be stored. It may be held
|
|
498
|
+
* only when every write changes an existing `latest`, `initial`-fork conversation document at its stored version.
|
|
499
|
+
*/
|
|
500
|
+
holdable() {
|
|
501
|
+
if (this.#writes.some((write) => write.type !== "document.change"))
|
|
502
|
+
return undefined;
|
|
503
|
+
const held = [];
|
|
504
|
+
for (const plan of this.#plans) {
|
|
505
|
+
const { content, change } = plan;
|
|
506
|
+
if (content === undefined && !plan.retire)
|
|
507
|
+
continue;
|
|
508
|
+
if (plan.retire || change?.loaded === undefined || content?.type !== "document.change")
|
|
509
|
+
return undefined;
|
|
510
|
+
const { loaded, prepared, version } = change;
|
|
511
|
+
const record = loaded.record;
|
|
512
|
+
if (record.scope.kind !== "conversation" || record.history !== "latest" || record.fork !== "initial") {
|
|
513
|
+
return undefined;
|
|
514
|
+
}
|
|
515
|
+
// A migration stores a base at once.
|
|
516
|
+
if (loaded.storedVersion !== version)
|
|
517
|
+
return undefined;
|
|
518
|
+
held.push({ loaded, ops: prepared.ops, base: content.content.kind === "base" });
|
|
519
|
+
}
|
|
520
|
+
return held;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Internal: adopt a held commit (`holdable()`) in memory only. Trackers advance by pointer swap; stored versions and
|
|
524
|
+
* delta counts stay, as nothing was stored. Returns its publication for the Session's own observers.
|
|
525
|
+
*/
|
|
526
|
+
adoptHeld() {
|
|
527
|
+
const publications = [];
|
|
528
|
+
for (const plan of this.#plans) {
|
|
529
|
+
// Every plan of a held commit changes or reads a loaded incarnation (`holdable()`).
|
|
530
|
+
const { tracker, prepared, version, loaded } = plan.change;
|
|
531
|
+
if (prepared.ops.length === 0) {
|
|
532
|
+
prepared.abort();
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
tracker.adopt(prepared);
|
|
536
|
+
const record = loaded.record;
|
|
537
|
+
const conversationId = plan.conversationId;
|
|
538
|
+
publications.push({
|
|
539
|
+
type: "document",
|
|
540
|
+
kind: "change",
|
|
541
|
+
record,
|
|
542
|
+
conversationId,
|
|
543
|
+
version,
|
|
544
|
+
value: prepared.value,
|
|
545
|
+
ops: prepared.ops,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return publications;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Internal: store the held changes of every incarnation this commit reads or writes in front of its own, so a stored
|
|
552
|
+
* document never misses an operation its later ones build on. Called right before Storage admission, after every
|
|
553
|
+
* fallible step, because it empties the holds: a failure earlier keeps them. Returns the holds it took.
|
|
554
|
+
*/
|
|
555
|
+
takeHeld(held) {
|
|
556
|
+
const taken = [];
|
|
557
|
+
for (const plan of this.#plans) {
|
|
558
|
+
// A new incarnation holds nothing yet.
|
|
559
|
+
if (!("createdAt" in plan.record))
|
|
560
|
+
continue;
|
|
561
|
+
const hold = held(plan.record.id);
|
|
562
|
+
if (hold === undefined)
|
|
563
|
+
continue;
|
|
564
|
+
taken.push(hold);
|
|
565
|
+
const own = plan.content?.type === "document.change" ? plan.content : undefined;
|
|
566
|
+
const change = plan.change;
|
|
567
|
+
const value = change?.prepared.value ?? hold.loaded.tracker.value;
|
|
568
|
+
const stored = storeHeld(hold, change?.prepared.ops ?? EMPTY_OPERATIONS, value, hold.loaded.valueVersion);
|
|
569
|
+
// A base this commit selected or must write covers what was held.
|
|
570
|
+
const content = own?.content.kind === "base" ? own.content : stored.content;
|
|
571
|
+
const write = { type: "document.change", id: plan.record.id, content };
|
|
572
|
+
if (own !== undefined)
|
|
573
|
+
this.#writes[this.#writes.indexOf(own)] = write;
|
|
574
|
+
else
|
|
575
|
+
this.#insertBeforeRetirement(write);
|
|
576
|
+
if (!plan.retire)
|
|
577
|
+
plan.held = { ops: stored.ops, observed: own !== undefined };
|
|
578
|
+
plan.content = write;
|
|
579
|
+
// Held documents are conversation documents; one this commit only read has no owner resolved yet.
|
|
580
|
+
if (plan.record.scope.kind === "conversation")
|
|
581
|
+
plan.conversationId = plan.record.scope.conversationId;
|
|
582
|
+
}
|
|
583
|
+
return taken;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Internal: the keys this commit writes, once settled (and after `takeHeld()`), for the Session's unpublished write
|
|
587
|
+
* set: its table records, and the address and incarnation of every document it creates, changes, or retires, with
|
|
588
|
+
* the scope of every incarnation it creates or retires.
|
|
589
|
+
*/
|
|
590
|
+
writeKeys() {
|
|
591
|
+
const keys = [];
|
|
592
|
+
tableKeys(this.#writes, keys);
|
|
593
|
+
for (const plan of this.#plans) {
|
|
594
|
+
if (plan.content === undefined && !plan.retire)
|
|
595
|
+
continue;
|
|
596
|
+
keys.push(documentKey(plan.addressId), incarnationKey(plan.record.id));
|
|
597
|
+
if (plan.retire || !("createdAt" in plan.record))
|
|
598
|
+
keys.push(scopeKey(plan.record.scope));
|
|
599
|
+
}
|
|
600
|
+
return keys;
|
|
601
|
+
}
|
|
602
|
+
/** Stage a content write for an incarnation, before its retirement when it retires. */
|
|
603
|
+
#insertBeforeRetirement(write) {
|
|
604
|
+
const at = this.#writes.findIndex((candidate) => candidate.type === "document.retire" && candidate.id === write.id);
|
|
605
|
+
if (at < 0)
|
|
606
|
+
this.#writes.push(write);
|
|
607
|
+
else
|
|
608
|
+
this.#writes.splice(at, 0, write);
|
|
609
|
+
}
|
|
440
610
|
/** Adopt every prepared change by pointer swap after Storage success and describe the publication. */
|
|
441
611
|
adopt(seq) {
|
|
442
612
|
const publications = [];
|
|
613
|
+
// Only when the commit stored held changes: then what Storage got differs from what memory adopted.
|
|
614
|
+
let stored;
|
|
443
615
|
for (const plan of this.#plans) {
|
|
444
616
|
const committed = "createdAt" in plan.record;
|
|
445
617
|
let record = committed ? plan.record : { ...plan.record, createdAt: seq };
|
|
@@ -474,34 +646,26 @@ export class Transaction {
|
|
|
474
646
|
});
|
|
475
647
|
}
|
|
476
648
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
record,
|
|
488
|
-
conversationId: conversationId,
|
|
489
|
-
source: plan.content.source,
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
else if (change !== undefined && publishes(plan)) {
|
|
493
|
-
const ops = change.loaded === undefined ? EMPTY_OPERATIONS : change.prepared.ops;
|
|
494
|
-
publications.push({
|
|
495
|
-
type: "document",
|
|
496
|
-
record,
|
|
497
|
-
conversationId,
|
|
498
|
-
version: change.version,
|
|
499
|
-
value: change.prepared.value,
|
|
500
|
-
ops,
|
|
501
|
-
});
|
|
649
|
+
if (plan.retire && committed)
|
|
650
|
+
this.#host.evict(plan.addressId, record.id);
|
|
651
|
+
const publication = describe(plan, record);
|
|
652
|
+
if (publication === undefined)
|
|
653
|
+
continue;
|
|
654
|
+
const held = plan.held;
|
|
655
|
+
if (held === undefined) {
|
|
656
|
+
publications.push(publication);
|
|
657
|
+
stored?.push(publication);
|
|
658
|
+
continue;
|
|
502
659
|
}
|
|
660
|
+
stored ??= [...publications];
|
|
661
|
+
if (held.observed)
|
|
662
|
+
publications.push(publication);
|
|
663
|
+
// Only a document change of a loaded incarnation carries held operations; a retirement is published alone.
|
|
664
|
+
stored.push(publication.type === "document" && publication.kind === "change"
|
|
665
|
+
? { ...publication, ops: held.ops }
|
|
666
|
+
: publication);
|
|
503
667
|
}
|
|
504
|
-
return publications;
|
|
668
|
+
return { observed: publications, stored: stored ?? publications };
|
|
505
669
|
}
|
|
506
670
|
async #assemble() {
|
|
507
671
|
const storage = this.#host.storage;
|
|
@@ -540,18 +704,30 @@ export class Transaction {
|
|
|
540
704
|
plan.retire = true;
|
|
541
705
|
retiring.add(plan.record.id);
|
|
542
706
|
}
|
|
707
|
+
const retire = (record) => {
|
|
708
|
+
if (retiring.has(record.id))
|
|
709
|
+
return;
|
|
710
|
+
plans.push({ addressId: addressId(record), record, retire: true });
|
|
711
|
+
retiring.add(record.id);
|
|
712
|
+
};
|
|
543
713
|
for (const taskId of terminalTaskIds) {
|
|
544
714
|
if (this.#tasksById.get(taskId)?.write?.kind === "create")
|
|
545
715
|
continue;
|
|
716
|
+
// The Session knows the documents of the tasks it created; any other task's are scanned.
|
|
717
|
+
const gate = this.#host.touch(scopeKey({ kind: "task", taskId }));
|
|
718
|
+
if (gate !== undefined)
|
|
719
|
+
await gate;
|
|
720
|
+
const known = this.#host.taskDocuments(taskId);
|
|
721
|
+
if (known !== undefined) {
|
|
722
|
+
for (const record of known)
|
|
723
|
+
retire(record);
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
546
726
|
let cursor;
|
|
547
727
|
do {
|
|
548
728
|
const page = await storage.scanDocuments({ scope: { kind: "task", taskId }, at: "current" }, INTERNAL_SCAN_PAGE_SIZE, cursor, this.#context);
|
|
549
|
-
for (const record of page.items)
|
|
550
|
-
|
|
551
|
-
continue;
|
|
552
|
-
plans.push({ addressId: addressId(record), record, retire: true });
|
|
553
|
-
retiring.add(record.id);
|
|
554
|
-
}
|
|
729
|
+
for (const record of page.items)
|
|
730
|
+
retire(record);
|
|
555
731
|
cursor = page.next;
|
|
556
732
|
} while (cursor !== undefined);
|
|
557
733
|
}
|
|
@@ -594,7 +770,7 @@ export class Transaction {
|
|
|
594
770
|
if (plan.content?.type === "document.change" && plan.content.content.kind === "delta" && change?.loaded) {
|
|
595
771
|
const { prepared, version } = change;
|
|
596
772
|
const info = { deltasSinceBase: change.loaded.deltasSinceBase };
|
|
597
|
-
if (change.definition
|
|
773
|
+
if (change.definition.checkpointWhen(prepared.value, prepared.ops, info)) {
|
|
598
774
|
plan.content = { ...plan.content, content: { version, kind: "base", value: prepared.value } };
|
|
599
775
|
}
|
|
600
776
|
}
|
|
@@ -677,7 +853,7 @@ export class Transaction {
|
|
|
677
853
|
try {
|
|
678
854
|
this.#assertOpen();
|
|
679
855
|
if (this.#hasTableWrite)
|
|
680
|
-
throw new ReadAfterWrite(method);
|
|
856
|
+
throw new ReadAfterWrite(`Tx.${method}()`);
|
|
681
857
|
return this.#track(read());
|
|
682
858
|
}
|
|
683
859
|
catch (error) {
|
|
@@ -785,6 +961,42 @@ function planDocument(document) {
|
|
|
785
961
|
}
|
|
786
962
|
}
|
|
787
963
|
}
|
|
964
|
+
/** The publication of one adopted plan, if it publishes (`publishes()`), with `record` as committed. */
|
|
965
|
+
function describe(plan, record) {
|
|
966
|
+
const conversationId = plan.conversationId;
|
|
967
|
+
if (plan.retire)
|
|
968
|
+
return { type: "document", kind: "retire", record, conversationId };
|
|
969
|
+
if (plan.content?.type === "document.copy") {
|
|
970
|
+
return { type: "document.copy", record, conversationId: conversationId, source: plan.content.source };
|
|
971
|
+
}
|
|
972
|
+
const change = plan.change;
|
|
973
|
+
if (change === undefined || !publishes(plan))
|
|
974
|
+
return undefined;
|
|
975
|
+
const ops = change.loaded === undefined ? EMPTY_OPERATIONS : change.prepared.ops;
|
|
976
|
+
return {
|
|
977
|
+
type: "document",
|
|
978
|
+
kind: "change",
|
|
979
|
+
record,
|
|
980
|
+
conversationId,
|
|
981
|
+
version: change.version,
|
|
982
|
+
value: change.prepared.value,
|
|
983
|
+
ops,
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Take a hold's changes after `ops`, a commit's own on top of them, as one stored content for an incarnation now at
|
|
988
|
+
* `value`, and the operations a reader of the stored state applies to reach it: the folded ones, or a root replacement
|
|
989
|
+
* after the queue overflowed, which stores a base, as does a hold whose commits selected one.
|
|
990
|
+
*/
|
|
991
|
+
export function storeHeld(hold, ops, value, version) {
|
|
992
|
+
hold.pending.push(ops);
|
|
993
|
+
const taken = hold.pending.take();
|
|
994
|
+
if (taken.kind === "replace")
|
|
995
|
+
return { content: { version, kind: "base", value }, ops: [["r", value]] };
|
|
996
|
+
if (hold.base)
|
|
997
|
+
return { content: { version, kind: "base", value }, ops: taken.ops };
|
|
998
|
+
return { content: { version, kind: "delta", ops: taken.ops }, ops: taken.ops };
|
|
999
|
+
}
|
|
788
1000
|
/**
|
|
789
1001
|
* Whether adoption publishes the plan: every creation, copy, and retirement, and a loaded incarnation that writes
|
|
790
1002
|
* content, which includes a migration-only base so observers of the older shape receive the new value.
|