@ny4n/durable 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +711 -2
- package/dist/documents.d.ts +66 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +98 -0
- package/dist/documents.js.map +1 -0
- package/dist/entries.d.ts +31 -0
- package/dist/entries.d.ts.map +1 -0
- package/dist/entries.js +31 -0
- package/dist/entries.js.map +1 -0
- package/dist/env/decode.d.ts +16 -0
- package/dist/env/decode.d.ts.map +1 -0
- package/dist/env/decode.js +28 -0
- package/dist/env/decode.js.map +1 -0
- package/dist/env/index.d.ts +263 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +49 -0
- package/dist/env/index.js.map +1 -0
- package/dist/env/line-scan.d.ts +13 -0
- package/dist/env/line-scan.d.ts.map +1 -0
- package/dist/env/line-scan.js +147 -0
- package/dist/env/line-scan.js.map +1 -0
- package/dist/env/node-watch.d.ts +29 -0
- package/dist/env/node-watch.d.ts.map +1 -0
- package/dist/env/node-watch.js +485 -0
- package/dist/env/node-watch.js.map +1 -0
- package/dist/env/node.d.ts +56 -0
- package/dist/env/node.d.ts.map +1 -0
- package/dist/env/node.js +1166 -0
- package/dist/env/node.js.map +1 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/harness/agent.d.ts +33 -0
- package/dist/harness/agent.d.ts.map +1 -0
- package/dist/harness/agent.js +235 -0
- package/dist/harness/agent.js.map +1 -0
- package/dist/harness/assistant.d.ts +15 -0
- package/dist/harness/assistant.d.ts.map +1 -0
- package/dist/harness/assistant.js +23 -0
- package/dist/harness/assistant.js.map +1 -0
- package/dist/harness/compaction.d.ts +56 -0
- package/dist/harness/compaction.d.ts.map +1 -0
- package/dist/harness/compaction.js +384 -0
- package/dist/harness/compaction.js.map +1 -0
- package/dist/harness/context.d.ts +63 -0
- package/dist/harness/context.d.ts.map +1 -0
- package/dist/harness/context.js +221 -0
- package/dist/harness/context.js.map +1 -0
- package/dist/harness/define.d.ts +18 -0
- package/dist/harness/define.d.ts.map +1 -0
- package/dist/harness/define.js +25 -0
- package/dist/harness/define.js.map +1 -0
- package/dist/harness/events.d.ts +180 -0
- package/dist/harness/events.d.ts.map +1 -0
- package/dist/harness/events.js +370 -0
- package/dist/harness/events.js.map +1 -0
- package/dist/harness/generation.d.ts +54 -0
- package/dist/harness/generation.d.ts.map +1 -0
- package/dist/harness/generation.js +514 -0
- package/dist/harness/generation.js.map +1 -0
- package/dist/harness/harness.d.ts +17 -0
- package/dist/harness/harness.d.ts.map +1 -0
- package/dist/harness/harness.js +332 -0
- package/dist/harness/harness.js.map +1 -0
- package/dist/harness/inbox.d.ts +59 -0
- package/dist/harness/inbox.d.ts.map +1 -0
- package/dist/harness/inbox.js +97 -0
- package/dist/harness/inbox.js.map +1 -0
- package/dist/harness/json.d.ts +10 -0
- package/dist/harness/json.d.ts.map +1 -0
- package/dist/harness/json.js +33 -0
- package/dist/harness/json.js.map +1 -0
- package/dist/harness/live.d.ts +142 -0
- package/dist/harness/live.d.ts.map +1 -0
- package/dist/harness/live.js +149 -0
- package/dist/harness/live.js.map +1 -0
- package/dist/harness/output.d.ts +69 -0
- package/dist/harness/output.d.ts.map +1 -0
- package/dist/harness/output.js +318 -0
- package/dist/harness/output.js.map +1 -0
- package/dist/harness/prompt.d.ts +27 -0
- package/dist/harness/prompt.d.ts.map +1 -0
- package/dist/harness/prompt.js +131 -0
- package/dist/harness/prompt.js.map +1 -0
- package/dist/harness/provider.d.ts +14 -0
- package/dist/harness/provider.d.ts.map +1 -0
- package/dist/harness/provider.js +30 -0
- package/dist/harness/provider.js.map +1 -0
- package/dist/harness/registry.d.ts +6 -0
- package/dist/harness/registry.d.ts.map +1 -0
- package/dist/harness/registry.js +101 -0
- package/dist/harness/registry.js.map +1 -0
- package/dist/harness/run.d.ts +17 -0
- package/dist/harness/run.d.ts.map +1 -0
- package/dist/harness/run.js +26 -0
- package/dist/harness/run.js.map +1 -0
- package/dist/harness/scheduler.d.ts +106 -0
- package/dist/harness/scheduler.d.ts.map +1 -0
- package/dist/harness/scheduler.js +1743 -0
- package/dist/harness/scheduler.js.map +1 -0
- package/dist/harness/submissions.d.ts +29 -0
- package/dist/harness/submissions.d.ts.map +1 -0
- package/dist/harness/submissions.js +175 -0
- package/dist/harness/submissions.js.map +1 -0
- package/dist/harness/task-graph.d.ts +49 -0
- package/dist/harness/task-graph.d.ts.map +1 -0
- package/dist/harness/task-graph.js +168 -0
- package/dist/harness/task-graph.js.map +1 -0
- package/dist/harness/tool.d.ts +76 -0
- package/dist/harness/tool.d.ts.map +1 -0
- package/dist/harness/tool.js +736 -0
- package/dist/harness/tool.js.map +1 -0
- package/dist/harness/types.d.ts +713 -0
- package/dist/harness/types.d.ts.map +1 -0
- package/dist/harness/types.js +2 -0
- package/dist/harness/types.js.map +1 -0
- package/dist/harness/usage.d.ts +18 -0
- package/dist/harness/usage.d.ts.map +1 -0
- package/dist/harness/usage.js +57 -0
- package/dist/harness/usage.js.map +1 -0
- package/dist/harness/util.d.ts +19 -0
- package/dist/harness/util.d.ts.map +1 -0
- package/dist/harness/util.js +58 -0
- package/dist/harness/util.js.map +1 -0
- package/dist/harness/view.d.ts +47 -0
- package/dist/harness/view.d.ts.map +1 -0
- package/dist/harness/view.js +206 -0
- package/dist/harness/view.js.map +1 -0
- package/dist/ids.d.ts +6 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +9 -0
- package/dist/ids.js.map +1 -0
- package/dist/images/cloudflare.d.ts +4 -0
- package/dist/images/cloudflare.d.ts.map +1 -0
- package/dist/images/cloudflare.js +9 -0
- package/dist/images/cloudflare.js.map +1 -0
- package/dist/images/exif.d.ts +3 -0
- package/dist/images/exif.d.ts.map +1 -0
- package/dist/images/exif.js +71 -0
- package/dist/images/exif.js.map +1 -0
- package/dist/images/index.d.ts +18 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +125 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/node-worker.d.ts +17 -0
- package/dist/images/node-worker.d.ts.map +1 -0
- package/dist/images/node-worker.js +16 -0
- package/dist/images/node-worker.js.map +1 -0
- package/dist/images/node.d.ts +21 -0
- package/dist/images/node.d.ts.map +1 -0
- package/dist/images/node.js +121 -0
- package/dist/images/node.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/session/forks.d.ts +10 -0
- package/dist/session/forks.d.ts.map +1 -0
- package/dist/session/forks.js +42 -0
- package/dist/session/forks.js.map +1 -0
- package/dist/session/observation.d.ts +42 -0
- package/dist/session/observation.d.ts.map +1 -0
- package/dist/session/observation.js +281 -0
- package/dist/session/observation.js.map +1 -0
- package/dist/session/session.d.ts +133 -0
- package/dist/session/session.d.ts.map +1 -0
- package/dist/session/session.js +811 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/transaction.d.ts +119 -0
- package/dist/session/transaction.d.ts.map +1 -0
- package/dist/session/transaction.js +795 -0
- package/dist/session/transaction.js.map +1 -0
- package/dist/storage/jsonl/index.d.ts +2 -0
- package/dist/storage/jsonl/index.d.ts.map +1 -0
- package/dist/storage/jsonl/index.js +2 -0
- package/dist/storage/jsonl/index.js.map +1 -0
- package/dist/storage/jsonl/node.d.ts +6 -0
- package/dist/storage/jsonl/node.d.ts.map +1 -0
- package/dist/storage/jsonl/node.js +8 -0
- package/dist/storage/jsonl/node.js.map +1 -0
- package/dist/storage/jsonl/storage.d.ts +143 -0
- package/dist/storage/jsonl/storage.d.ts.map +1 -0
- package/dist/storage/jsonl/storage.js +682 -0
- package/dist/storage/jsonl/storage.js.map +1 -0
- package/dist/storage/memory.d.ts +62 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +733 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/scan.d.ts +18 -0
- package/dist/storage/scan.d.ts.map +1 -0
- package/dist/storage/scan.js +29 -0
- package/dist/storage/scan.js.map +1 -0
- package/dist/storage/sqlite/cloudflare.d.ts +46 -0
- package/dist/storage/sqlite/cloudflare.d.ts.map +1 -0
- package/dist/storage/sqlite/cloudflare.js +106 -0
- package/dist/storage/sqlite/cloudflare.js.map +1 -0
- package/dist/storage/sqlite/database.d.ts +37 -0
- package/dist/storage/sqlite/database.d.ts.map +1 -0
- package/dist/storage/sqlite/database.js +2 -0
- package/dist/storage/sqlite/database.js.map +1 -0
- package/dist/storage/sqlite/index.d.ts +4 -0
- package/dist/storage/sqlite/index.d.ts.map +1 -0
- package/dist/storage/sqlite/index.js +3 -0
- package/dist/storage/sqlite/index.js.map +1 -0
- package/dist/storage/sqlite/migrations.d.ts +11 -0
- package/dist/storage/sqlite/migrations.d.ts.map +1 -0
- package/dist/storage/sqlite/migrations.js +111 -0
- package/dist/storage/sqlite/migrations.js.map +1 -0
- package/dist/storage/sqlite/node.d.ts +41 -0
- package/dist/storage/sqlite/node.d.ts.map +1 -0
- package/dist/storage/sqlite/node.js +179 -0
- package/dist/storage/sqlite/node.js.map +1 -0
- package/dist/storage/sqlite/storage.d.ts +65 -0
- package/dist/storage/sqlite/storage.d.ts.map +1 -0
- package/dist/storage/sqlite/storage.js +670 -0
- package/dist/storage/sqlite/storage.js.map +1 -0
- package/dist/tasks.d.ts +6 -0
- package/dist/tasks.d.ts.map +1 -0
- package/dist/tasks.js +5 -0
- package/dist/tasks.js.map +1 -0
- package/dist/testing/assertions.d.ts +5 -0
- package/dist/testing/assertions.d.ts.map +1 -0
- package/dist/testing/assertions.js +25 -0
- package/dist/testing/assertions.js.map +1 -0
- package/dist/testing/env-conformance.d.ts +7 -0
- package/dist/testing/env-conformance.d.ts.map +1 -0
- package/dist/testing/env-conformance.js +431 -0
- package/dist/testing/env-conformance.js.map +1 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +6 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/runner.d.ts +12 -0
- package/dist/testing/runner.d.ts.map +1 -0
- package/dist/testing/runner.js +23 -0
- package/dist/testing/runner.js.map +1 -0
- package/dist/testing/storage-benchmark.d.ts +41 -0
- package/dist/testing/storage-benchmark.d.ts.map +1 -0
- package/dist/testing/storage-benchmark.js +350 -0
- package/dist/testing/storage-benchmark.js.map +1 -0
- package/dist/testing/storage-conformance.d.ts +4 -0
- package/dist/testing/storage-conformance.d.ts.map +1 -0
- package/dist/testing/storage-conformance.js +1213 -0
- package/dist/testing/storage-conformance.js.map +1 -0
- package/dist/testing/types.d.ts +37 -0
- package/dist/testing/types.d.ts.map +1 -0
- package/dist/testing/types.js +2 -0
- package/dist/testing/types.js.map +1 -0
- package/dist/tools/bash.d.ts +55 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +138 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit-diff.d.ts +89 -0
- package/dist/tools/edit-diff.d.ts.map +1 -0
- package/dist/tools/edit-diff.js +386 -0
- package/dist/tools/edit-diff.js.map +1 -0
- package/dist/tools/edit.d.ts +18 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +117 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/env.d.ts +5 -0
- package/dist/tools/env.d.ts.map +1 -0
- package/dist/tools/env.js +7 -0
- package/dist/tools/env.js.map +1 -0
- package/dist/tools/file-mutation-queue.d.ts +9 -0
- package/dist/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/tools/file-mutation-queue.js +52 -0
- package/dist/tools/file-mutation-queue.js.map +1 -0
- package/dist/tools/image-processor.d.ts +47 -0
- package/dist/tools/image-processor.d.ts.map +1 -0
- package/dist/tools/image-processor.js +30 -0
- package/dist/tools/image-processor.js.map +1 -0
- package/dist/tools/image.d.ts +20 -0
- package/dist/tools/image.d.ts.map +1 -0
- package/dist/tools/image.js +178 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/index.d.ts +46 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +23 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/path-utils.d.ts +5 -0
- package/dist/tools/path-utils.d.ts.map +1 -0
- package/dist/tools/path-utils.js +26 -0
- package/dist/tools/path-utils.js.map +1 -0
- package/dist/tools/read.d.ts +25 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +235 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/write.d.ts +10 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +31 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/truncate.d.ts +64 -0
- package/dist/truncate.d.ts.map +1 -0
- package/dist/truncate.js +154 -0
- package/dist/truncate.js.map +1 -0
- package/dist/types.d.ts +932 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +140 -5
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
import type { Message, ModelRuntime } from "@ny4n/ai/contracts";
|
|
2
|
+
import type { AttachedReplicatedState, Context, Draft, JsonValue } from "@ny4n/chord";
|
|
3
|
+
import type { Op } from "@ny4n/chord/delta";
|
|
4
|
+
import type { ExecutionEnv } from "./env/index.ts";
|
|
5
|
+
import type { Agent, ContextView, ConversationHandle, RegistrySnapshot, Settings, SettledTask } from "./harness/types.ts";
|
|
6
|
+
/** JSON object used as the root of every durable document. */
|
|
7
|
+
export type JsonObject = {
|
|
8
|
+
[key: string]: JsonValue;
|
|
9
|
+
};
|
|
10
|
+
declare const idBrand: unique symbol;
|
|
11
|
+
/** Erased nominal number identifying one durable record kind. */
|
|
12
|
+
export type Id<Kind extends string, Type = unknown> = number & {
|
|
13
|
+
readonly [idBrand]: {
|
|
14
|
+
readonly kind: Kind;
|
|
15
|
+
readonly type: Type;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export type ConversationId = Id<"conversation">;
|
|
19
|
+
export type EntryId = Id<"entry">;
|
|
20
|
+
export type TaskId<Result = unknown> = Id<"task", Result>;
|
|
21
|
+
export type SubmissionId = Id<"submission">;
|
|
22
|
+
export type DocumentId = Id<"document">;
|
|
23
|
+
declare const seqBrand: unique symbol;
|
|
24
|
+
/** Strictly increasing sequence assigned to one atomic storage commit; gaps are permitted. */
|
|
25
|
+
export type Seq = number & {
|
|
26
|
+
readonly [seqBrand]: "sequence";
|
|
27
|
+
};
|
|
28
|
+
/** The root conversation always uses this reserved ID. */
|
|
29
|
+
export declare const ROOT_CONVERSATION_ID: ConversationId;
|
|
30
|
+
/** Conversation document that retains only its current state. */
|
|
31
|
+
export type LatestConversationSemantics = {
|
|
32
|
+
readonly scope: "conversation";
|
|
33
|
+
readonly history: "latest";
|
|
34
|
+
readonly fork: "current" | "initial";
|
|
35
|
+
};
|
|
36
|
+
/** Conversation document whose history remains addressable for as-of reads. */
|
|
37
|
+
export type RewindableConversationSemantics = {
|
|
38
|
+
readonly scope: "conversation";
|
|
39
|
+
readonly history: "rewindable";
|
|
40
|
+
readonly fork: "asOf" | "current" | "initial";
|
|
41
|
+
};
|
|
42
|
+
/** Ownership and lifetime of a document; only conversation documents declare history and fork behavior. */
|
|
43
|
+
export type DocumentSemantics = {
|
|
44
|
+
readonly scope: "session";
|
|
45
|
+
readonly history?: never;
|
|
46
|
+
readonly fork?: never;
|
|
47
|
+
} | LatestConversationSemantics | RewindableConversationSemantics | {
|
|
48
|
+
readonly scope: "task";
|
|
49
|
+
readonly history?: never;
|
|
50
|
+
readonly fork?: never;
|
|
51
|
+
};
|
|
52
|
+
/** Stored replay state supplied to a document's checkpoint predicate. */
|
|
53
|
+
export type CheckpointInfo = {
|
|
54
|
+
/** Deltas already stored after the newest base, excluding the change being evaluated. */
|
|
55
|
+
readonly deltasSinceBase: number;
|
|
56
|
+
};
|
|
57
|
+
/** Definition fields shared by singleton documents and document families. */
|
|
58
|
+
export type CommonDocDefinition<T extends JsonObject> = {
|
|
59
|
+
/** Stable persisted kind; part of the public protocol. */
|
|
60
|
+
readonly kind: string;
|
|
61
|
+
/** Positive integer version of the stored value shape. */
|
|
62
|
+
readonly version: number;
|
|
63
|
+
initial(): T;
|
|
64
|
+
migrate?(value: JsonObject, fromVersion: number): T;
|
|
65
|
+
/** Return true to store this ordinary change as a complete base instead of a delta. */
|
|
66
|
+
checkpointWhen?(value: Readonly<T>, ops: readonly Op[], info: CheckpointInfo): boolean;
|
|
67
|
+
};
|
|
68
|
+
/** Singleton document definition. */
|
|
69
|
+
export type DocDefinition<T extends JsonObject> = CommonDocDefinition<T> & DocumentSemantics;
|
|
70
|
+
/** Keyed document family definition; `initial(seed)` runs only when a member is absent. */
|
|
71
|
+
export type DocFamilyDefinition<T extends JsonObject, I extends JsonValue> = Omit<CommonDocDefinition<T>, "initial"> & DocumentSemantics & {
|
|
72
|
+
readonly family: true;
|
|
73
|
+
initial(seed: I): T;
|
|
74
|
+
};
|
|
75
|
+
declare const docType: unique symbol;
|
|
76
|
+
/** Typed singleton document token passed explicitly to typed access. */
|
|
77
|
+
export interface DocToken<T extends JsonObject, D extends DocDefinition<T>> {
|
|
78
|
+
readonly definition: D;
|
|
79
|
+
readonly [docType]?: T;
|
|
80
|
+
}
|
|
81
|
+
/** Typed document family token passed explicitly to typed access. */
|
|
82
|
+
export interface DocFamilyToken<T extends JsonObject, I extends JsonValue, D extends DocFamilyDefinition<T, I>> {
|
|
83
|
+
readonly definition: D;
|
|
84
|
+
readonly [docType]?: T;
|
|
85
|
+
}
|
|
86
|
+
export type SessionDocToken<T extends JsonObject> = DocToken<T, CommonDocDefinition<T> & {
|
|
87
|
+
readonly scope: "session";
|
|
88
|
+
}>;
|
|
89
|
+
export type ConversationDocToken<T extends JsonObject> = DocToken<T, CommonDocDefinition<T> & (LatestConversationSemantics | RewindableConversationSemantics)>;
|
|
90
|
+
export type RewindableConversationDocToken<T extends JsonObject> = DocToken<T, CommonDocDefinition<T> & RewindableConversationSemantics>;
|
|
91
|
+
export type TaskDocToken<T extends JsonObject> = DocToken<T, CommonDocDefinition<T> & {
|
|
92
|
+
readonly scope: "task";
|
|
93
|
+
}>;
|
|
94
|
+
export type SessionDocFamilyToken<T extends JsonObject, I extends JsonValue> = DocFamilyToken<T, I, DocFamilyDefinition<T, I> & {
|
|
95
|
+
readonly scope: "session";
|
|
96
|
+
}>;
|
|
97
|
+
export type ConversationDocFamilyToken<T extends JsonObject, I extends JsonValue> = DocFamilyToken<T, I, DocFamilyDefinition<T, I> & (LatestConversationSemantics | RewindableConversationSemantics)>;
|
|
98
|
+
export type RewindableConversationDocFamilyToken<T extends JsonObject, I extends JsonValue> = DocFamilyToken<T, I, DocFamilyDefinition<T, I> & RewindableConversationSemantics>;
|
|
99
|
+
export type TaskDocFamilyToken<T extends JsonObject, I extends JsonValue> = DocFamilyToken<T, I, DocFamilyDefinition<T, I> & {
|
|
100
|
+
readonly scope: "task";
|
|
101
|
+
}>;
|
|
102
|
+
/** Live task record reserved by one invocation. */
|
|
103
|
+
export type RunningTask<I, S, R> = TaskRecord<I, S, R> & {
|
|
104
|
+
readonly state: Extract<TaskState<S, R>, {
|
|
105
|
+
readonly status: "running";
|
|
106
|
+
}>;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Next state a task commits for itself: a replacement checkpoint, a wait, or its outcome. A returned `terminal` state is
|
|
110
|
+
* stored as `completing` while ordinary owned work below the task is live (spec §5.5).
|
|
111
|
+
*/
|
|
112
|
+
export type NextTaskState<S, R> = Extract<TaskState<S, R>, {
|
|
113
|
+
readonly status: "running" | "waiting" | "terminal";
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Runs one checkpoint phase. It must commit a changed checkpoint or a terminal outcome through `runtime.commit()`;
|
|
117
|
+
* returning without durable progress faults the task.
|
|
118
|
+
*/
|
|
119
|
+
export type PhaseHandler<I, P, S, R, H extends object> = (task: RunningTask<I, P, R>, runtime: TaskRuntime<I, S, R, H>, context: Context) => Promise<void>;
|
|
120
|
+
/** Dispatches one hook of a task to every matching registered handler, in registry order of the phase snapshot. */
|
|
121
|
+
export interface HookRunner<H extends object> {
|
|
122
|
+
/**
|
|
123
|
+
* Call `invoke` with each matching handler named `name`. An ordinary throw from `invoke` is reported and the next
|
|
124
|
+
* handler runs; once the invocation is signalled, the error propagates. Composition happens inside `invoke`.
|
|
125
|
+
*/
|
|
126
|
+
each<K extends keyof H>(name: K, invoke: (handler: NonNullable<H[K]>) => void | Promise<void>): Promise<void>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Operations of one task invocation. Every operation rejects after the invocation ends; watches acquired through it
|
|
130
|
+
* stop at invocation end.
|
|
131
|
+
*/
|
|
132
|
+
export interface TaskRuntime<I, S, R, H extends object> extends DocumentObserver, DocumentReader {
|
|
133
|
+
readonly taskId: TaskId<R>;
|
|
134
|
+
readonly conversationId: ConversationId;
|
|
135
|
+
/**
|
|
136
|
+
* Aborted when the run is signalled by `abortTask()`, the Harness closes, or the invocation ends. Work still using it
|
|
137
|
+
* after the invocation ended, such as a detached wait, is cancelled; it could not write anything anyway.
|
|
138
|
+
*/
|
|
139
|
+
readonly signal: AbortSignal;
|
|
140
|
+
/** Registry snapshot of the current phase; refreshed at every phase boundary. */
|
|
141
|
+
readonly registry: RegistrySnapshot;
|
|
142
|
+
/** The task's conversation's agent, resolved at most once per phase, at first use, and fixed for the phase. */
|
|
143
|
+
agent(context: Context): Promise<Agent>;
|
|
144
|
+
/** `HarnessOptions.settings`, resolved at each access. */
|
|
145
|
+
readonly settings: Settings;
|
|
146
|
+
readonly models: ModelRuntime;
|
|
147
|
+
/** Calls `HarnessOptions.env` for the task's conversation; rejects with its error. */
|
|
148
|
+
env(context: Context): Promise<ExecutionEnv | undefined>;
|
|
149
|
+
/** Handlers of this task's name from the extensions its conversation selects, in extension order. */
|
|
150
|
+
readonly hooks: HookRunner<H>;
|
|
151
|
+
/**
|
|
152
|
+
* Commit on the Session line after rereading the task. Rejects when the task is terminal, the invocation ended, the
|
|
153
|
+
* Harness is closing, or, in a run invocation, the task carries an abort mark. A returned state replaces the task's
|
|
154
|
+
* state in the same commit; returning nothing leaves it unchanged. `tx.createTask()` defaults to the task's
|
|
155
|
+
* conversation. Inside the callback read only through `tx`: `snapshot()`, `documentState()`, `watchDoc()`, `getTask()`, and the other Session and runtime reads may queue on the line the callback holds, and then never resolve.
|
|
156
|
+
*/
|
|
157
|
+
commit(change: (tx: Tx, current: RunningTask<I, S, R>) => NextTaskState<S, R> | undefined | Promise<NextTaskState<S, R> | undefined>, context: Context): Promise<void>;
|
|
158
|
+
/** Read a durable memo of this task. */
|
|
159
|
+
memo<T extends JsonValue>(name: string, context: Context): Promise<T | undefined>;
|
|
160
|
+
/** Store `candidate` unless a memo already exists; return the durable winner. */
|
|
161
|
+
memo<T extends JsonValue>(name: string, candidate: T, context: Context): Promise<T>;
|
|
162
|
+
/** Committed task record. */
|
|
163
|
+
getTask<T>(id: TaskId<T>, context: Context): Promise<TaskRecord<JsonValue, JsonValue, T> | undefined>;
|
|
164
|
+
/** Resolve with the task's terminal receipt; rejects when the invocation ends. */
|
|
165
|
+
waitForTask<T>(id: TaskId<T>, context: Context): Promise<SettledTask<T>>;
|
|
166
|
+
/**
|
|
167
|
+
* Abort a task this task owns, as `Harness.abortTask()` does, and resolve once it is terminal. Rejects for a task
|
|
168
|
+
* another owns; resolves at once for a terminal one.
|
|
169
|
+
*/
|
|
170
|
+
abortOwned(id: TaskId, context: Context): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Live tasks this task owns directly, in ID order: also those an earlier invocation created, before a restart. Tasks
|
|
173
|
+
* in conversations it owns are not included. Copies of the committed records.
|
|
174
|
+
*/
|
|
175
|
+
ownedTasks(context: Context): Promise<TaskRecord<JsonValue, JsonValue, JsonValue>[]>;
|
|
176
|
+
/** Outcomes of terminal tasks, in order; rejects when one is missing or not terminal. Used after a wait. */
|
|
177
|
+
outcomes<T>(ids: readonly TaskId<T>[], context: Context): Promise<TaskOutcome<T>[]>;
|
|
178
|
+
/**
|
|
179
|
+
* Invocation-bound handle of an existing conversation, for example one this task owns; `undefined` when absent. Its
|
|
180
|
+
* operations and the submissions it returns reject after the invocation ends; admitted work stays durable.
|
|
181
|
+
*/
|
|
182
|
+
conversation(id: ConversationId, context: Context): Promise<ConversationHandle | undefined>;
|
|
183
|
+
/** Committed entry visible from the task's conversation. */
|
|
184
|
+
entry(id: EntryId, context: Context): Promise<EntryRecord | undefined>;
|
|
185
|
+
/** Undefined when the entry is absent, not visible, or has another kind. */
|
|
186
|
+
entry<D extends JsonValue>(token: Entry<D>, id: EntryId, context: Context): Promise<TypedEntry<D> | undefined>;
|
|
187
|
+
/** Committed raw active transcript and model context, optionally cut off at the visible entry `at`. */
|
|
188
|
+
context(conversationId: ConversationId, context: Context, options?: {
|
|
189
|
+
readonly at?: EntryId;
|
|
190
|
+
}): Promise<ContextView>;
|
|
191
|
+
/** The Harness clock. */
|
|
192
|
+
now(): number;
|
|
193
|
+
/** Forward a non-fatal failure to `HarnessOptions.onReport`. */
|
|
194
|
+
report(error: unknown): void;
|
|
195
|
+
/** Resolve once the Harness clock reaches `until`; rejects when the invocation or `context` is cancelled. */
|
|
196
|
+
sleep(until: number, context: Context): Promise<void>;
|
|
197
|
+
}
|
|
198
|
+
/** Executable durable state machine definition, registered in the registry by `name`. */
|
|
199
|
+
export type TaskDefinition<I, S extends {
|
|
200
|
+
phase: string;
|
|
201
|
+
}, R, H extends object> = {
|
|
202
|
+
/** Registered task kind persisted in `TaskRecord.kind`. */
|
|
203
|
+
readonly name: string;
|
|
204
|
+
/** Definition version persisted with live input and checkpoints. */
|
|
205
|
+
readonly version: number;
|
|
206
|
+
/** First durable checkpoint for a newly created task. */
|
|
207
|
+
initial(input: I): S;
|
|
208
|
+
/** Exhaustive phase map; each handler receives the task narrowed to its phase. */
|
|
209
|
+
readonly phases: {
|
|
210
|
+
readonly [P in S["phase"]]: PhaseHandler<I, Extract<S, {
|
|
211
|
+
phase: P;
|
|
212
|
+
}>, S, R, H>;
|
|
213
|
+
};
|
|
214
|
+
/** Runs in a fresh invocation after an abort mark and must commit a terminal outcome. */
|
|
215
|
+
abort(task: RunningTask<I, S, R>, runtime: TaskRuntime<I, S, R, H>, context: Context): Promise<void>;
|
|
216
|
+
/** Convert a record stored by any older supported version; runs at reservation. */
|
|
217
|
+
migrate?(input: JsonValue, checkpoint: JsonValue, fromVersion: number): {
|
|
218
|
+
input: I;
|
|
219
|
+
checkpoint: S;
|
|
220
|
+
};
|
|
221
|
+
readonly hooks?: H;
|
|
222
|
+
};
|
|
223
|
+
/** Typed executable task definition. */
|
|
224
|
+
export interface Task<I, S extends {
|
|
225
|
+
phase: string;
|
|
226
|
+
}, R, H extends object> {
|
|
227
|
+
readonly definition: TaskDefinition<I, S, R, H>;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* What creating a task needs: its identity and first checkpoint. The executable definition is found by `name` in the
|
|
231
|
+
* registry when the task runs, so a module that only starts a task need not import the module that implements it.
|
|
232
|
+
*/
|
|
233
|
+
export interface TaskReference<I, S extends {
|
|
234
|
+
phase: string;
|
|
235
|
+
}, R> {
|
|
236
|
+
readonly definition: {
|
|
237
|
+
readonly name: string;
|
|
238
|
+
readonly version: number;
|
|
239
|
+
initial(input: I): S;
|
|
240
|
+
};
|
|
241
|
+
/** Carries the result type of the referenced task; never present at runtime. */
|
|
242
|
+
readonly result?: R;
|
|
243
|
+
}
|
|
244
|
+
/** Who owns a task: its conversation (a top-level task) or another task of the same conversation (a child task). */
|
|
245
|
+
export type TaskOwnership = {
|
|
246
|
+
readonly kind: "conversation";
|
|
247
|
+
} | {
|
|
248
|
+
readonly kind: "task";
|
|
249
|
+
readonly taskId: TaskId;
|
|
250
|
+
};
|
|
251
|
+
/** How a waiting task treats the tasks it waits on (spec §5.5). */
|
|
252
|
+
export type JoinPolicy = "failFast" | "allSettled";
|
|
253
|
+
/** Creation options for a durable task. */
|
|
254
|
+
export type TaskOptions = {
|
|
255
|
+
/** Required: a task always names its owner (spec §5.5). */
|
|
256
|
+
readonly ownership: TaskOwnership;
|
|
257
|
+
/**
|
|
258
|
+
* Default: the owner task's conversation, or the transaction's bound conversation; required for conversation-owned
|
|
259
|
+
* tasks created by Session commits that are not bound to a conversation.
|
|
260
|
+
*/
|
|
261
|
+
readonly conversationId?: ConversationId;
|
|
262
|
+
/** Conversation-owned tasks only: excluded from ordinary idle waits, conversation aborts, and cascades. */
|
|
263
|
+
readonly background?: boolean;
|
|
264
|
+
/**
|
|
265
|
+
* Its creator awaits it only in memory and does not resume after a restart, so it is pointless once the Harness that
|
|
266
|
+
* created it is gone. When scheduling starts in a later Harness, the task, if still live, is abort-marked with reason
|
|
267
|
+
* `restart`, and the mark cascades to its ordinary owned work, before any of it runs again.
|
|
268
|
+
*/
|
|
269
|
+
readonly abandonOnRestart?: boolean;
|
|
270
|
+
};
|
|
271
|
+
/** Ownership selected explicitly whenever a conversation is created. */
|
|
272
|
+
export type ConversationOwnership = {
|
|
273
|
+
readonly kind: "ownerless";
|
|
274
|
+
} | {
|
|
275
|
+
readonly kind: "task";
|
|
276
|
+
readonly taskId: TaskId;
|
|
277
|
+
};
|
|
278
|
+
/** Immutable identity, history ancestry, and task ownership of a transcript scope. */
|
|
279
|
+
export type ConversationRecord = {
|
|
280
|
+
readonly id: ConversationId;
|
|
281
|
+
/** Fork source and inclusive parent entry through which history is inherited. */
|
|
282
|
+
readonly parent?: {
|
|
283
|
+
readonly conversationId: ConversationId;
|
|
284
|
+
readonly at: EntryId;
|
|
285
|
+
};
|
|
286
|
+
/** Creator edge used for attribution, subtree abort, and subtree idle waits. */
|
|
287
|
+
readonly owner?: {
|
|
288
|
+
readonly conversationId: ConversationId;
|
|
289
|
+
readonly taskId: TaskId;
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
/** An immutable override of one visible entry's contribution to model context. */
|
|
293
|
+
export type ContextEdit = {
|
|
294
|
+
/** Entry whose model messages are omitted or replaced. */
|
|
295
|
+
readonly target: EntryId;
|
|
296
|
+
} & ({
|
|
297
|
+
readonly action: "omit";
|
|
298
|
+
readonly messages?: never;
|
|
299
|
+
} | {
|
|
300
|
+
readonly action: "replace";
|
|
301
|
+
/** Messages contributed instead of the target entry's model messages. */
|
|
302
|
+
readonly messages: readonly Message[];
|
|
303
|
+
});
|
|
304
|
+
/** Immutable transcript event with separate model-facing and application-facing payloads. */
|
|
305
|
+
export type EntryRecord = {
|
|
306
|
+
readonly id: EntryId;
|
|
307
|
+
readonly conversationId: ConversationId;
|
|
308
|
+
/** Application-defined entry discriminator. */
|
|
309
|
+
readonly kind: string;
|
|
310
|
+
/** Messages contributed to model context; absent for display or bookkeeping entries. */
|
|
311
|
+
readonly model?: readonly Message[];
|
|
312
|
+
/** JSON payload consumed by views, extensions, or bookkeeping logic. */
|
|
313
|
+
readonly data?: JsonValue;
|
|
314
|
+
/** First entry in the active context selected by this entry. */
|
|
315
|
+
readonly head?: EntryId;
|
|
316
|
+
/** Context-only overrides of earlier visible entries. */
|
|
317
|
+
readonly edits?: readonly ContextEdit[];
|
|
318
|
+
/** Task that appended this entry, when it was produced by durable work. */
|
|
319
|
+
readonly byTaskId?: TaskId;
|
|
320
|
+
};
|
|
321
|
+
/** Entry content supplied before the Session assigns identity and task attribution. */
|
|
322
|
+
export type EntryDraft = Omit<EntryRecord, "id" | "conversationId" | "byTaskId" | "head"> & {
|
|
323
|
+
/** `"self"` starts active context at the newly assigned entry ID. */
|
|
324
|
+
readonly head?: EntryId | "self";
|
|
325
|
+
};
|
|
326
|
+
/** Entry whose `data` has type `D`; `never` means the kind carries no data. */
|
|
327
|
+
export type TypedEntry<D extends JsonValue> = Omit<EntryRecord, "data"> & ([D] extends [never] ? {
|
|
328
|
+
readonly data?: never;
|
|
329
|
+
} : {
|
|
330
|
+
readonly data: D;
|
|
331
|
+
});
|
|
332
|
+
/** Entry content of a typed kind; the token supplies `kind`. */
|
|
333
|
+
export type TypedEntryDraft<D extends JsonValue> = Omit<EntryDraft, "kind" | "data"> & ([D] extends [never] ? {
|
|
334
|
+
readonly data?: never;
|
|
335
|
+
} : {
|
|
336
|
+
readonly data: D;
|
|
337
|
+
});
|
|
338
|
+
/** Typed entry kind with a narrowing guard. */
|
|
339
|
+
export interface Entry<D extends JsonValue = never> {
|
|
340
|
+
readonly kind: string;
|
|
341
|
+
is(entry: EntryRecord | undefined): entry is TypedEntry<D>;
|
|
342
|
+
}
|
|
343
|
+
/** Identity fields shared by every durable submission state. */
|
|
344
|
+
type SubmissionRecordBase = {
|
|
345
|
+
readonly id: SubmissionId;
|
|
346
|
+
readonly conversationId: ConversationId;
|
|
347
|
+
/** Host-provided deduplication key, scoped to the conversation. */
|
|
348
|
+
readonly requestId?: string;
|
|
349
|
+
};
|
|
350
|
+
/** Durable lifecycle of one admitted user input or passive entry write. */
|
|
351
|
+
export type SubmissionRecord = (SubmissionRecordBase & {
|
|
352
|
+
readonly type: "input";
|
|
353
|
+
} & ({
|
|
354
|
+
/** Admitted but not yet represented in the transcript. */
|
|
355
|
+
readonly status: "queued";
|
|
356
|
+
readonly entry?: never;
|
|
357
|
+
readonly answer?: never;
|
|
358
|
+
readonly reason?: never;
|
|
359
|
+
readonly detail?: never;
|
|
360
|
+
} | {
|
|
361
|
+
/** Added to the transcript and owned by an active run. */
|
|
362
|
+
readonly status: "placed";
|
|
363
|
+
readonly entry: EntryId;
|
|
364
|
+
readonly answer?: never;
|
|
365
|
+
readonly reason?: never;
|
|
366
|
+
readonly detail?: never;
|
|
367
|
+
} | {
|
|
368
|
+
/** Successfully answered user input. */
|
|
369
|
+
readonly status: "done";
|
|
370
|
+
readonly entry: EntryId;
|
|
371
|
+
readonly answer: EntryId;
|
|
372
|
+
readonly reason?: never;
|
|
373
|
+
readonly detail?: never;
|
|
374
|
+
} | {
|
|
375
|
+
/** Terminal input that can no longer receive an answer. */
|
|
376
|
+
readonly status: "unanswered";
|
|
377
|
+
readonly entry?: EntryId;
|
|
378
|
+
readonly answer?: never;
|
|
379
|
+
readonly reason: string;
|
|
380
|
+
readonly detail?: JsonValue;
|
|
381
|
+
})) | (SubmissionRecordBase & {
|
|
382
|
+
readonly type: "write";
|
|
383
|
+
} & ({
|
|
384
|
+
/** Admitted but not yet appended to the transcript. */
|
|
385
|
+
readonly status: "queued";
|
|
386
|
+
readonly entry?: never;
|
|
387
|
+
readonly answer?: never;
|
|
388
|
+
readonly reason?: never;
|
|
389
|
+
readonly detail?: never;
|
|
390
|
+
} | {
|
|
391
|
+
/** Successfully appended passive entry. */
|
|
392
|
+
readonly status: "done";
|
|
393
|
+
readonly entry: EntryId;
|
|
394
|
+
readonly answer?: never;
|
|
395
|
+
readonly reason?: never;
|
|
396
|
+
readonly detail?: never;
|
|
397
|
+
} | {
|
|
398
|
+
/** Terminal passive write that could not be placed. */
|
|
399
|
+
readonly status: "unanswered";
|
|
400
|
+
readonly entry?: never;
|
|
401
|
+
readonly answer?: never;
|
|
402
|
+
readonly reason: string;
|
|
403
|
+
readonly detail?: JsonValue;
|
|
404
|
+
}));
|
|
405
|
+
/** Terminal status staged for a submission; identity, type, and entry come from its current record. */
|
|
406
|
+
export type SubmissionSettlement = {
|
|
407
|
+
readonly status: "done";
|
|
408
|
+
readonly answer: EntryId;
|
|
409
|
+
} | {
|
|
410
|
+
readonly status: "unanswered";
|
|
411
|
+
readonly reason: string;
|
|
412
|
+
readonly detail?: JsonValue;
|
|
413
|
+
};
|
|
414
|
+
/** Submission fields supplied before the Session assigns an ID. */
|
|
415
|
+
export type SubmissionCreate = SubmissionRecord extends infer Record ? Record extends SubmissionRecord ? Omit<Record, "id"> : never : never;
|
|
416
|
+
/** JSON-safe error snapshot persisted instead of a runtime `Error` object. */
|
|
417
|
+
export type TaskOutcomeError = {
|
|
418
|
+
readonly message: string;
|
|
419
|
+
/** Optional structured diagnostic data for inspection or recovery. */
|
|
420
|
+
readonly detail?: JsonValue;
|
|
421
|
+
};
|
|
422
|
+
/** Durable reason and optional result recorded when a task becomes terminal. */
|
|
423
|
+
export type TaskOutcome<R> = {
|
|
424
|
+
readonly status: "completed";
|
|
425
|
+
readonly result: R;
|
|
426
|
+
readonly error?: never;
|
|
427
|
+
readonly reason?: never;
|
|
428
|
+
}
|
|
429
|
+
/** Expected task or domain failure explicitly committed by its implementation. */
|
|
430
|
+
| {
|
|
431
|
+
readonly status: "failed";
|
|
432
|
+
readonly error: TaskOutcomeError;
|
|
433
|
+
readonly result?: R;
|
|
434
|
+
readonly reason?: never;
|
|
435
|
+
}
|
|
436
|
+
/** Explicit cancellation handled by the task's abort protocol. */
|
|
437
|
+
| {
|
|
438
|
+
readonly status: "aborted";
|
|
439
|
+
readonly reason?: string;
|
|
440
|
+
readonly result?: R;
|
|
441
|
+
readonly error?: never;
|
|
442
|
+
}
|
|
443
|
+
/** Task that cannot resume because its definition or migration is unavailable. */
|
|
444
|
+
| {
|
|
445
|
+
readonly status: "orphaned";
|
|
446
|
+
readonly reason: string;
|
|
447
|
+
readonly result?: never;
|
|
448
|
+
readonly error?: never;
|
|
449
|
+
}
|
|
450
|
+
/** Runtime-detected contract failure, such as an uncaught throw or no durable progress. */
|
|
451
|
+
| {
|
|
452
|
+
readonly status: "faulted";
|
|
453
|
+
readonly error: TaskOutcomeError;
|
|
454
|
+
readonly result?: never;
|
|
455
|
+
readonly reason?: never;
|
|
456
|
+
};
|
|
457
|
+
/** Complete durable execution state of a task. */
|
|
458
|
+
export type TaskState<S, R> = {
|
|
459
|
+
/** Eligible for scheduling. */
|
|
460
|
+
readonly status: "pending";
|
|
461
|
+
/** Complete durable state from which execution resumes. */
|
|
462
|
+
readonly checkpoint: S;
|
|
463
|
+
readonly outcome?: never;
|
|
464
|
+
} | {
|
|
465
|
+
/** Reserved by one in-memory task invocation. */
|
|
466
|
+
readonly status: "running";
|
|
467
|
+
/** Complete durable state from which execution resumes. */
|
|
468
|
+
readonly checkpoint: S;
|
|
469
|
+
readonly outcome?: never;
|
|
470
|
+
} | {
|
|
471
|
+
/** Parked without an invocation until every task in `on` is terminal; then resumes at `checkpoint`. */
|
|
472
|
+
readonly status: "waiting";
|
|
473
|
+
readonly checkpoint: S;
|
|
474
|
+
readonly on: readonly TaskId[];
|
|
475
|
+
readonly policy: JoinPolicy;
|
|
476
|
+
readonly outcome?: never;
|
|
477
|
+
} | {
|
|
478
|
+
/** Outcome decided; becomes terminal once no ordinary owned work below is live. Runs no more code. */
|
|
479
|
+
readonly status: "completing";
|
|
480
|
+
readonly checkpoint?: never;
|
|
481
|
+
readonly outcome: TaskOutcome<R>;
|
|
482
|
+
} | {
|
|
483
|
+
/** Permanently settled durable result receipt. */
|
|
484
|
+
readonly status: "terminal";
|
|
485
|
+
readonly checkpoint?: never;
|
|
486
|
+
readonly outcome: TaskOutcome<R>;
|
|
487
|
+
};
|
|
488
|
+
/** Identity, definition, and scheduling fields shared by every task state. */
|
|
489
|
+
type TaskRecordBase<I, R> = {
|
|
490
|
+
readonly id: TaskId<R>;
|
|
491
|
+
readonly conversationId: ConversationId;
|
|
492
|
+
/** Registered task definition name. */
|
|
493
|
+
readonly kind: string;
|
|
494
|
+
/** Definition version used to migrate live input and checkpoints. */
|
|
495
|
+
readonly version: number;
|
|
496
|
+
/** Original task input retained while the task is live or terminal. */
|
|
497
|
+
readonly input: I;
|
|
498
|
+
/** Owning task of a child task; absent for a task its conversation owns. Immutable. */
|
|
499
|
+
readonly owner?: TaskId;
|
|
500
|
+
/** Whether this conversation-owned task is excluded from ordinary idle waits, conversation aborts, and cascades. */
|
|
501
|
+
readonly background: boolean;
|
|
502
|
+
/** Durable abort mark checked before run-mode progress is committed. */
|
|
503
|
+
readonly abortRequested: boolean;
|
|
504
|
+
/**
|
|
505
|
+
* Why the mark was set when not by an abort request: `restart` for a task abandoned after a restart
|
|
506
|
+
* (`TaskOptions.abandonOnRestart`) or below one. Such a task waits for its definition instead of becoming `orphaned`.
|
|
507
|
+
* A later abort request clears it.
|
|
508
|
+
*/
|
|
509
|
+
readonly abortReason?: "restart";
|
|
510
|
+
/** Set from `TaskOptions.abandonOnRestart`. Immutable. */
|
|
511
|
+
readonly abandonOnRestart?: true;
|
|
512
|
+
/**
|
|
513
|
+
* Wall-clock milliseconds of the first change to `running`, stamped by the Session. Kept through waits and recovery,
|
|
514
|
+
* so the span to `endedAt` includes them. Absent before the task first runs, and on records written by earlier
|
|
515
|
+
* versions.
|
|
516
|
+
*/
|
|
517
|
+
readonly startedAt?: number;
|
|
518
|
+
/** Wall-clock milliseconds of the change to `terminal`, stamped by the Session; absent while live. */
|
|
519
|
+
readonly endedAt?: number;
|
|
520
|
+
};
|
|
521
|
+
/** Complete replacement record for one durable task state machine. */
|
|
522
|
+
export type TaskRecord<I, S, R> = TaskRecordBase<I, R> & ({
|
|
523
|
+
readonly state: Extract<TaskState<S, R>, {
|
|
524
|
+
readonly status: "pending" | "running" | "waiting";
|
|
525
|
+
}>;
|
|
526
|
+
/** Small first-writer-wins values retained while the task can run. */
|
|
527
|
+
readonly memos?: Readonly<Record<string, JsonValue>>;
|
|
528
|
+
} | {
|
|
529
|
+
readonly state: Extract<TaskState<S, R>, {
|
|
530
|
+
readonly status: "completing" | "terminal";
|
|
531
|
+
}>;
|
|
532
|
+
readonly memos?: never;
|
|
533
|
+
});
|
|
534
|
+
/** Persisted lifecycle record for one create-to-retire document incarnation. */
|
|
535
|
+
export type DocumentRecord = {
|
|
536
|
+
/** Unique incarnation ID; never reused when the same logical document is recreated. */
|
|
537
|
+
readonly id: DocumentId;
|
|
538
|
+
/** Stable document definition kind. */
|
|
539
|
+
readonly kind: string;
|
|
540
|
+
/** Family member key; absent for singleton documents. */
|
|
541
|
+
readonly key?: string;
|
|
542
|
+
/** Commit that created the incarnation, stamped by storage. */
|
|
543
|
+
readonly createdAt: Seq;
|
|
544
|
+
/** Commit that retired the incarnation; absent while it is current. */
|
|
545
|
+
readonly retiredAt?: Seq;
|
|
546
|
+
} & ({
|
|
547
|
+
readonly scope: {
|
|
548
|
+
readonly kind: "session";
|
|
549
|
+
};
|
|
550
|
+
readonly history?: never;
|
|
551
|
+
readonly fork?: never;
|
|
552
|
+
} | ({
|
|
553
|
+
readonly scope: {
|
|
554
|
+
readonly kind: "conversation";
|
|
555
|
+
readonly conversationId: ConversationId;
|
|
556
|
+
};
|
|
557
|
+
} & ({
|
|
558
|
+
/** Retain only current state. */
|
|
559
|
+
readonly history: "latest";
|
|
560
|
+
/** Initialize a fork from current source state or the definition's initial value. */
|
|
561
|
+
readonly fork: "current" | "initial";
|
|
562
|
+
} | {
|
|
563
|
+
/** Retain history needed for as-of reads. */
|
|
564
|
+
readonly history: "rewindable";
|
|
565
|
+
/** Initialize a fork at its cutoff, from current state, or from the initial value. */
|
|
566
|
+
readonly fork: "asOf" | "current" | "initial";
|
|
567
|
+
})) | {
|
|
568
|
+
readonly scope: {
|
|
569
|
+
readonly kind: "task";
|
|
570
|
+
readonly taskId: TaskId;
|
|
571
|
+
};
|
|
572
|
+
readonly history?: never;
|
|
573
|
+
readonly fork?: never;
|
|
574
|
+
});
|
|
575
|
+
/** Fields supplied when storage creates and stamps a new `DocumentRecord`. */
|
|
576
|
+
export type DocumentCreate = DocumentRecord extends infer Record ? Record extends DocumentRecord ? Omit<Record, "createdAt" | "retiredAt"> : never : never;
|
|
577
|
+
/** One ordered scan result and its optional continuation state. */
|
|
578
|
+
export type Page<T, C> = {
|
|
579
|
+
readonly items: readonly T[];
|
|
580
|
+
readonly next?: C;
|
|
581
|
+
};
|
|
582
|
+
/**
|
|
583
|
+
* Backend-owned JSON continuation state that callers only round-trip to the same scan. It carries the scan's order: a
|
|
584
|
+
* scan given a cursor continues in that order, and rejects a different `order` in its query.
|
|
585
|
+
*/
|
|
586
|
+
export type Cursor = Readonly<Record<string, JsonValue>>;
|
|
587
|
+
/** ID order of a scan: `ascending` is oldest first, `descending` newest first. */
|
|
588
|
+
export type ScanOrder = "ascending" | "descending";
|
|
589
|
+
/** Optional filters for an ordered conversation scan. */
|
|
590
|
+
export type ConversationQuery = {
|
|
591
|
+
readonly ownerConversationId?: ConversationId;
|
|
592
|
+
readonly ownerTaskId?: TaskId;
|
|
593
|
+
/** Default `ascending`; with a cursor, the cursor's order. */
|
|
594
|
+
readonly order?: ScanOrder;
|
|
595
|
+
};
|
|
596
|
+
/** Inclusive ID bounds for a scan of one conversation's fork-aware history. */
|
|
597
|
+
export type EntryQuery = {
|
|
598
|
+
readonly conversationId: ConversationId;
|
|
599
|
+
/** Oldest entry ID that may be returned. */
|
|
600
|
+
readonly minEntryId?: EntryId;
|
|
601
|
+
/** Newest entry ID that may be returned. */
|
|
602
|
+
readonly maxEntryId?: EntryId;
|
|
603
|
+
/** Default `descending`; with a cursor, the cursor's order. */
|
|
604
|
+
readonly order?: ScanOrder;
|
|
605
|
+
};
|
|
606
|
+
/** Optional filters for an ordered scan of durable task records. */
|
|
607
|
+
export type TaskQuery = {
|
|
608
|
+
readonly conversationId?: ConversationId;
|
|
609
|
+
readonly kind?: string;
|
|
610
|
+
readonly status?: TaskState<JsonValue, JsonValue>["status"];
|
|
611
|
+
readonly abortRequested?: boolean;
|
|
612
|
+
readonly background?: boolean;
|
|
613
|
+
/** Default `ascending`; with a cursor, the cursor's order. */
|
|
614
|
+
readonly order?: ScanOrder;
|
|
615
|
+
};
|
|
616
|
+
/** Optional filters for an ordered scan of submission records. */
|
|
617
|
+
export type SubmissionQuery = {
|
|
618
|
+
readonly conversationId?: ConversationId;
|
|
619
|
+
readonly status?: SubmissionRecord["status"];
|
|
620
|
+
/** Default `ascending`; with a cursor, the cursor's order. */
|
|
621
|
+
readonly order?: ScanOrder;
|
|
622
|
+
};
|
|
623
|
+
/** Current state or one historical commit sequence used for document membership and content reads. */
|
|
624
|
+
export type DocumentPoint = Seq | "current";
|
|
625
|
+
/** Exact logical identity of a singleton or one keyed family member. */
|
|
626
|
+
export type DocumentAddress = {
|
|
627
|
+
readonly kind: string;
|
|
628
|
+
readonly scope: DocumentRecord["scope"];
|
|
629
|
+
/** Absent selects the singleton; present selects one family member. */
|
|
630
|
+
readonly key?: string;
|
|
631
|
+
};
|
|
632
|
+
/** Ordered scan of document incarnations alive in one exact scope at one point. */
|
|
633
|
+
export type DocumentQuery = {
|
|
634
|
+
readonly scope: DocumentRecord["scope"];
|
|
635
|
+
readonly at: DocumentPoint;
|
|
636
|
+
readonly kind?: string;
|
|
637
|
+
};
|
|
638
|
+
/** Complete checkpoint or Chord operation batch selected by the owning Session. */
|
|
639
|
+
export type DocumentContent = {
|
|
640
|
+
readonly version: number;
|
|
641
|
+
readonly kind: "base";
|
|
642
|
+
readonly value: JsonObject;
|
|
643
|
+
} | {
|
|
644
|
+
readonly version: number;
|
|
645
|
+
readonly kind: "delta";
|
|
646
|
+
readonly ops: readonly Op[];
|
|
647
|
+
};
|
|
648
|
+
/** Exact persisted source selected for a definition-free document copy. */
|
|
649
|
+
export type DocumentCopySource = {
|
|
650
|
+
readonly id: DocumentId;
|
|
651
|
+
readonly at: DocumentPoint;
|
|
652
|
+
};
|
|
653
|
+
/** Detached materialized value and stored definition version at a selected point. */
|
|
654
|
+
export type StoredDocument = {
|
|
655
|
+
readonly record: DocumentRecord;
|
|
656
|
+
readonly version: number;
|
|
657
|
+
readonly value: JsonObject;
|
|
658
|
+
/** Deltas replayed after the selected base to materialize `value`. */
|
|
659
|
+
readonly deltasSinceBase: number;
|
|
660
|
+
};
|
|
661
|
+
/** One record or document mutation in an atomic storage commit. */
|
|
662
|
+
export type StorageWrite = {
|
|
663
|
+
readonly type: "conversation";
|
|
664
|
+
readonly value: ConversationRecord;
|
|
665
|
+
} | {
|
|
666
|
+
readonly type: "entry";
|
|
667
|
+
readonly value: EntryRecord;
|
|
668
|
+
} | {
|
|
669
|
+
readonly type: "task";
|
|
670
|
+
readonly value: TaskRecord<JsonValue, JsonValue, JsonValue>;
|
|
671
|
+
} | {
|
|
672
|
+
readonly type: "submission";
|
|
673
|
+
readonly value: SubmissionRecord;
|
|
674
|
+
} | {
|
|
675
|
+
readonly type: "document.create";
|
|
676
|
+
readonly record: DocumentCreate;
|
|
677
|
+
readonly content: Extract<DocumentContent, {
|
|
678
|
+
readonly kind: "base";
|
|
679
|
+
}>;
|
|
680
|
+
} | {
|
|
681
|
+
readonly type: "document.copy";
|
|
682
|
+
readonly record: DocumentCreate;
|
|
683
|
+
readonly source: DocumentCopySource;
|
|
684
|
+
} | {
|
|
685
|
+
readonly type: "document.change";
|
|
686
|
+
readonly id: DocumentId;
|
|
687
|
+
readonly content: DocumentContent;
|
|
688
|
+
} | {
|
|
689
|
+
readonly type: "document.retire";
|
|
690
|
+
readonly id: DocumentId;
|
|
691
|
+
};
|
|
692
|
+
/** Committed change of one document incarnation. */
|
|
693
|
+
export type DocumentCommitChange = {
|
|
694
|
+
readonly type: "document";
|
|
695
|
+
readonly record: DocumentRecord;
|
|
696
|
+
/** Conversation owning the document; task documents derive it from their task record. Undefined only for Session documents. */
|
|
697
|
+
readonly conversationId: ConversationId | undefined;
|
|
698
|
+
/** Definition version of `value`; absent when this commit retired the incarnation. */
|
|
699
|
+
readonly version: number | undefined;
|
|
700
|
+
/** Exact adopted immutable revision, or `null` when this commit retired the incarnation. */
|
|
701
|
+
readonly value: JsonObject | null;
|
|
702
|
+
/** Exact adopted operations for an ordinary update; empty for creation and retirement. */
|
|
703
|
+
readonly ops: readonly Op[];
|
|
704
|
+
} | {
|
|
705
|
+
/** Definition-free child initialization; consumers hydrate through state or watch acquisition. */
|
|
706
|
+
readonly type: "document.copy";
|
|
707
|
+
readonly record: DocumentRecord;
|
|
708
|
+
readonly conversationId: ConversationId;
|
|
709
|
+
readonly source: DocumentCopySource;
|
|
710
|
+
};
|
|
711
|
+
/** Complete table record committed without another publication copy. */
|
|
712
|
+
export type TableCommitChange = Extract<StorageWrite, {
|
|
713
|
+
readonly type: "conversation" | "entry" | "task" | "submission";
|
|
714
|
+
}>;
|
|
715
|
+
export type CommitChange = TableCommitChange | DocumentCommitChange;
|
|
716
|
+
/** Every immutable change from one successful Session commit. Change order is unspecified. */
|
|
717
|
+
export type CommitPublication = {
|
|
718
|
+
readonly seq: Seq;
|
|
719
|
+
readonly changes: readonly CommitChange[];
|
|
720
|
+
};
|
|
721
|
+
/**
|
|
722
|
+
* Transaction surface of one Session commit callback.
|
|
723
|
+
* Table reads and creation results are trusted immutable values and may be shared with internal commit state.
|
|
724
|
+
*/
|
|
725
|
+
export interface Tx {
|
|
726
|
+
conversation(id: ConversationId): Promise<ConversationRecord | undefined>;
|
|
727
|
+
entry(id: EntryId): Promise<EntryRecord | undefined>;
|
|
728
|
+
/** Undefined when the entry is absent or has another kind. */
|
|
729
|
+
entry<D extends JsonValue>(token: Entry<D>, id: EntryId): Promise<TypedEntry<D> | undefined>;
|
|
730
|
+
task(id: TaskId): Promise<TaskRecord<JsonValue, JsonValue, JsonValue> | undefined>;
|
|
731
|
+
scanConversations(query: ConversationQuery, limit: number, cursor?: Cursor): Promise<Page<ConversationRecord, Cursor>>;
|
|
732
|
+
scanEntries(query: EntryQuery, limit: number, cursor?: Cursor): Promise<Page<EntryRecord, Cursor>>;
|
|
733
|
+
/** Newest visible entry of the conversation that carries a `head`. */
|
|
734
|
+
latestHeadMarker(conversationId: ConversationId): Promise<(EntryRecord & {
|
|
735
|
+
readonly head: EntryId;
|
|
736
|
+
}) | undefined>;
|
|
737
|
+
scanTasks(query: TaskQuery, limit: number, cursor?: Cursor): Promise<Page<TaskRecord<JsonValue, JsonValue, JsonValue>, Cursor>>;
|
|
738
|
+
/** Committed submission with a conversation-scoped request ID. */
|
|
739
|
+
submissionByRequest(conversationId: ConversationId, requestId: string): Promise<SubmissionRecord | undefined>;
|
|
740
|
+
/** Create a conversation with explicitly selected ownership. */
|
|
741
|
+
createConversation(options: {
|
|
742
|
+
readonly ownership: ConversationOwnership;
|
|
743
|
+
}): Promise<ConversationRecord>;
|
|
744
|
+
/** Create a history fork at one concrete visible entry with explicitly selected ownership. */
|
|
745
|
+
forkConversation(parentConversationId: ConversationId, at: EntryId, options: {
|
|
746
|
+
readonly ownership: ConversationOwnership;
|
|
747
|
+
}): Promise<ConversationRecord>;
|
|
748
|
+
/** Returned records are Session-owned immutable values and may be shared with commit listeners. */
|
|
749
|
+
appendEntry(conversationId: ConversationId, value: EntryDraft): Promise<EntryRecord>;
|
|
750
|
+
/** The token supplies `kind` and types `data`. */
|
|
751
|
+
appendEntry<D extends JsonValue>(token: Entry<D>, conversationId: ConversationId, value: TypedEntryDraft<NoInfer<D>>): Promise<TypedEntry<D>>;
|
|
752
|
+
createTask<I, S extends {
|
|
753
|
+
phase: string;
|
|
754
|
+
}, R, H extends object>(task: Task<I, S, R, H>, input: I, options: TaskOptions): Promise<TaskId<R>>;
|
|
755
|
+
createTask<I, S extends {
|
|
756
|
+
phase: string;
|
|
757
|
+
}, R>(task: TaskReference<I, S, R>, input: I, options: TaskOptions): Promise<TaskId<R>>;
|
|
758
|
+
/**
|
|
759
|
+
* Create a raw submission record with a fresh ID. No admission rules apply: no busy check, no inbox queueing, no
|
|
760
|
+
* placement. Use `Conversation.submit()` or a conversation handle unless the caller implements admission itself.
|
|
761
|
+
*/
|
|
762
|
+
createSubmission(create: SubmissionCreate): Promise<SubmissionRecord>;
|
|
763
|
+
/**
|
|
764
|
+
* Settle a queued or placed submission; only a placed input can be answered, and a settled submission stays
|
|
765
|
+
* unchanged. Resolved against this transaction's latest record of the submission, so it works after table writes.
|
|
766
|
+
* Run tasks settle the inputs they answer.
|
|
767
|
+
*/
|
|
768
|
+
settleSubmission(id: SubmissionId, settlement: SubmissionSettlement): void;
|
|
769
|
+
/**
|
|
770
|
+
* Place a queued submission at `entry`: an input becomes `placed`, a write `done`. Resolved like
|
|
771
|
+
* `settleSubmission()`. Inbox boundaries place the submissions they select.
|
|
772
|
+
*/
|
|
773
|
+
placeSubmission(id: SubmissionId, entry: EntryId): void;
|
|
774
|
+
doc<T extends JsonObject>(token: SessionDocToken<T>): Promise<Draft<T>>;
|
|
775
|
+
doc<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId): Promise<Draft<T>>;
|
|
776
|
+
doc<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId): Promise<Draft<T>>;
|
|
777
|
+
doc<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, seed: I): Promise<Draft<T>>;
|
|
778
|
+
doc<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, seed: I): Promise<Draft<T>>;
|
|
779
|
+
doc<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, seed: I): Promise<Draft<T>>;
|
|
780
|
+
retireDoc<T extends JsonObject>(token: SessionDocToken<T>): Promise<void>;
|
|
781
|
+
retireDoc<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId): Promise<void>;
|
|
782
|
+
retireDoc<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId): Promise<void>;
|
|
783
|
+
retireDoc<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string): Promise<void>;
|
|
784
|
+
retireDoc<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string): Promise<void>;
|
|
785
|
+
retireDoc<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string): Promise<void>;
|
|
786
|
+
}
|
|
787
|
+
/** Disposable, read-only Chord state bound to one committed document incarnation. */
|
|
788
|
+
export type DocumentState<T extends JsonObject> = AttachedReplicatedState<Readonly<T> | null>;
|
|
789
|
+
/** Terminal result of one document watch. */
|
|
790
|
+
export type WatchEnd = {
|
|
791
|
+
readonly reason: "stopped" | "cancelled" | "session_closed" | "retired";
|
|
792
|
+
} | {
|
|
793
|
+
readonly reason: "listener_error";
|
|
794
|
+
readonly error: Error;
|
|
795
|
+
}
|
|
796
|
+
/** The Session failed; `error` is what failed it, usually a storage error (see `SessionFailed`). */
|
|
797
|
+
| {
|
|
798
|
+
readonly reason: "session_failed";
|
|
799
|
+
readonly error: unknown;
|
|
800
|
+
};
|
|
801
|
+
/** Serialized exact-frame observation of an immutable value with bounded pending delivery. */
|
|
802
|
+
export interface WatchHandle<T> {
|
|
803
|
+
/** Acquisition revision before start; latest delivered immutable revision afterward. */
|
|
804
|
+
readonly value: T;
|
|
805
|
+
/** Install the sole asynchronous listener. Never invokes it inline. */
|
|
806
|
+
start(listener: (value: T, ops: readonly Op[], context: Context) => Promise<void>): void;
|
|
807
|
+
/** Idempotently stop future callbacks and return this watch's terminal result. */
|
|
808
|
+
stop(): Promise<WatchEnd>;
|
|
809
|
+
/** Settle when the watch terminates; an already-running callback remains caller-owned. */
|
|
810
|
+
readonly closed: Promise<WatchEnd>;
|
|
811
|
+
}
|
|
812
|
+
export type DocumentWatch<T extends JsonObject> = WatchHandle<Readonly<T> | null>;
|
|
813
|
+
/** Committed document reads. */
|
|
814
|
+
export type DocumentReader = Pick<Session, "snapshot" | "snapshotAsOf">;
|
|
815
|
+
/** Non-creating document watch acquisition shared by Session and later invocation APIs. */
|
|
816
|
+
export interface DocumentObserver {
|
|
817
|
+
watchDoc<T extends JsonObject>(token: SessionDocToken<T>, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
818
|
+
watchDoc<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
819
|
+
watchDoc<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
820
|
+
watchDoc<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
821
|
+
watchDoc<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
822
|
+
watchDoc<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, context: Context): Promise<DocumentWatch<T> | undefined>;
|
|
823
|
+
}
|
|
824
|
+
/** Why a Session ended: `close()`, or a failed Storage call, whose error it carries. */
|
|
825
|
+
export type SessionEnd = {
|
|
826
|
+
readonly reason: "closed";
|
|
827
|
+
} | {
|
|
828
|
+
readonly reason: "failed";
|
|
829
|
+
readonly error: unknown;
|
|
830
|
+
};
|
|
831
|
+
/** Owner of one mutation line, its records, and its tracked documents. */
|
|
832
|
+
export interface Session extends DocumentObserver {
|
|
833
|
+
/**
|
|
834
|
+
* Run one atomic transaction on the Session mutation line. Inside the callback read only through `tx`: `snapshot()`, `documentState()`, `watchDoc()`, `getTask()`, and the other Session and runtime reads may queue on the line the callback holds, and then never resolve.
|
|
835
|
+
*/
|
|
836
|
+
commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context): Promise<T>;
|
|
837
|
+
/** Seal admission, settle admitted commits, then close storage. */
|
|
838
|
+
close(context: Context): Promise<void>;
|
|
839
|
+
/**
|
|
840
|
+
* Settles once the Session has closed, Storage included: after `close()`, or after the first failed Storage call,
|
|
841
|
+
* which closes the Session itself. A failed Session is reopened from Storage; nothing else is left to clean up.
|
|
842
|
+
*/
|
|
843
|
+
readonly closed: Promise<SessionEnd>;
|
|
844
|
+
/** Observe complete commits synchronously after adoption. The listener must not block or call Session APIs. */
|
|
845
|
+
subscribeCommits(listener: (publication: CommitPublication, context: Context) => void): () => void;
|
|
846
|
+
/**
|
|
847
|
+
* Observe close synchronously when it begins, also when a failed Storage call closes the Session. The listener must
|
|
848
|
+
* not block or call Session APIs.
|
|
849
|
+
*/
|
|
850
|
+
subscribeClose(listener: () => void): () => void;
|
|
851
|
+
snapshot<T extends JsonObject>(token: SessionDocToken<T>, context: Context): Promise<Readonly<T> | undefined>;
|
|
852
|
+
snapshot<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId, context: Context): Promise<Readonly<T> | undefined>;
|
|
853
|
+
snapshot<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId, context: Context): Promise<Readonly<T> | undefined>;
|
|
854
|
+
snapshot<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, context: Context): Promise<Readonly<T> | undefined>;
|
|
855
|
+
snapshot<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, context: Context): Promise<Readonly<T> | undefined>;
|
|
856
|
+
snapshot<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, context: Context): Promise<Readonly<T> | undefined>;
|
|
857
|
+
documentState<T extends JsonObject>(token: SessionDocToken<T>, context: Context): Promise<DocumentState<T> | undefined>;
|
|
858
|
+
documentState<T extends JsonObject>(token: ConversationDocToken<T>, conversationId: ConversationId, context: Context): Promise<DocumentState<T> | undefined>;
|
|
859
|
+
documentState<T extends JsonObject>(token: TaskDocToken<T>, taskId: TaskId, context: Context): Promise<DocumentState<T> | undefined>;
|
|
860
|
+
documentState<T extends JsonObject, I extends JsonValue>(token: SessionDocFamilyToken<T, I>, key: string, context: Context): Promise<DocumentState<T> | undefined>;
|
|
861
|
+
documentState<T extends JsonObject, I extends JsonValue>(token: ConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, context: Context): Promise<DocumentState<T> | undefined>;
|
|
862
|
+
documentState<T extends JsonObject, I extends JsonValue>(token: TaskDocFamilyToken<T, I>, taskId: TaskId, key: string, context: Context): Promise<DocumentState<T> | undefined>;
|
|
863
|
+
snapshotAsOf<T extends JsonObject>(token: RewindableConversationDocToken<T>, conversationId: ConversationId, at: EntryId, context: Context): Promise<Readonly<T> | undefined>;
|
|
864
|
+
snapshotAsOf<T extends JsonObject, I extends JsonValue>(token: RewindableConversationDocFamilyToken<T, I>, conversationId: ConversationId, key: string, at: EntryId, context: Context): Promise<Readonly<T> | undefined>;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Atomic persistence boundary for Session records.
|
|
868
|
+
*
|
|
869
|
+
* Storage trusts the owning Session to supply semantically valid records, references,
|
|
870
|
+
* ancestry, and transitions. Implementations enforce atomicity, global ID ownership,
|
|
871
|
+
* immutable conversation/entry creation, document record consistency, and detached values;
|
|
872
|
+
* Session serializes commits.
|
|
873
|
+
*
|
|
874
|
+
* An error a method throws is final: it fails the Session, which nothing retries, so retry transient failures inside
|
|
875
|
+
* the method. Two errors of a read fail only that read: a `StorageRequestError` for an invalid request (an unknown
|
|
876
|
+
* conversation, a foreign or malformed cursor, history a document does not keep), which must have no durable effect, and a
|
|
877
|
+
* rejection because its caller's context was aborted. Any error from `commit()` or `mintId()` is fatal.
|
|
878
|
+
*/
|
|
879
|
+
export interface Storage {
|
|
880
|
+
/**
|
|
881
|
+
* Atomically persist one batch and return its sequence. Once resolved, later reads through this storage observe it.
|
|
882
|
+
*/
|
|
883
|
+
commit(writes: readonly StorageWrite[], context: Context): Promise<Seq>;
|
|
884
|
+
/**
|
|
885
|
+
* Return a fresh branded candidate from the Session-global numeric ID namespace, greater than every ID minted or stored
|
|
886
|
+
* before, also across reopen: scans order by ID as creation order, and the Harness relies on it.
|
|
887
|
+
*/
|
|
888
|
+
mintId<I extends Id<string>>(): Promise<I>;
|
|
889
|
+
/** Look up one conversation by exact ID. */
|
|
890
|
+
conversation(id: ConversationId, context: Context): Promise<ConversationRecord | undefined>;
|
|
891
|
+
/** Scan conversations in `query.order` (default ascending) by ID. */
|
|
892
|
+
scanConversations(query: ConversationQuery, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<ConversationRecord, Cursor>>;
|
|
893
|
+
/** Look up one global entry and the sequence of the commit that persisted it. */
|
|
894
|
+
entry(id: EntryId, context: Context): Promise<{
|
|
895
|
+
readonly entry: EntryRecord;
|
|
896
|
+
readonly commitSeq: Seq;
|
|
897
|
+
} | undefined>;
|
|
898
|
+
/** Look up one entry only when it is visible through the requested conversation's ancestry. */
|
|
899
|
+
entry(conversationId: ConversationId, id: EntryId, context: Context): Promise<{
|
|
900
|
+
readonly entry: EntryRecord;
|
|
901
|
+
readonly commitSeq: Seq;
|
|
902
|
+
} | undefined>;
|
|
903
|
+
/**
|
|
904
|
+
* Return the newest visible entry with a `head` at or below the optional inclusive cutoff.
|
|
905
|
+
* The returned entry is the marker; its `head` value is the range's actual lower bound.
|
|
906
|
+
*/
|
|
907
|
+
findLatestHeadMarker(conversationId: ConversationId, atOrBeforeEntryId: EntryId | undefined, context: Context): Promise<(EntryRecord & {
|
|
908
|
+
readonly head: EntryId;
|
|
909
|
+
}) | undefined>;
|
|
910
|
+
/** Scan the inclusive visible range in `query.order` (default descending), returning at most `limit` entries. */
|
|
911
|
+
scanEntries(query: EntryQuery, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<EntryRecord, Cursor>>;
|
|
912
|
+
/** Look up the latest complete record for one task. */
|
|
913
|
+
task(id: TaskId, context: Context): Promise<TaskRecord<JsonValue, JsonValue, JsonValue> | undefined>;
|
|
914
|
+
/** Scan task records matching every supplied filter in `query.order` (default ascending) by ID. */
|
|
915
|
+
scanTasks(query: TaskQuery, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<TaskRecord<JsonValue, JsonValue, JsonValue>, Cursor>>;
|
|
916
|
+
/** Look up the latest complete record for one admitted submission. */
|
|
917
|
+
submission(id: SubmissionId, context: Context): Promise<SubmissionRecord | undefined>;
|
|
918
|
+
/** Scan submissions matching every supplied filter in `query.order` (default ascending) by ID. */
|
|
919
|
+
scanSubmissions(query: SubmissionQuery, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<SubmissionRecord, Cursor>>;
|
|
920
|
+
/** Find a submission by its conversation-scoped host deduplication key. */
|
|
921
|
+
submissionByRequest(conversationId: ConversationId, requestId: string, context: Context): Promise<SubmissionRecord | undefined>;
|
|
922
|
+
/** Resolve the incarnation occupying one exact logical address at the selected point. */
|
|
923
|
+
findDocument(address: DocumentAddress, at: DocumentPoint, context: Context): Promise<DocumentRecord | undefined>;
|
|
924
|
+
/** Materialize one specific incarnation by ID at the selected point without following a replacement at its address. */
|
|
925
|
+
document(id: DocumentId, at: DocumentPoint, context: Context): Promise<StoredDocument | undefined>;
|
|
926
|
+
/** Scan incarnations alive in one exact scope at the selected point. */
|
|
927
|
+
scanDocuments(query: DocumentQuery, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<DocumentRecord, Cursor>>;
|
|
928
|
+
/** Release backend resources; all later operations must reject. */
|
|
929
|
+
close(context: Context): Promise<void>;
|
|
930
|
+
}
|
|
931
|
+
export {};
|
|
932
|
+
//# sourceMappingURL=types.d.ts.map
|