@mcp-b/do-runtime 0.1.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +110 -0
  3. package/LICENSE.workerd +176 -0
  4. package/NOTICE +7 -0
  5. package/README.md +282 -0
  6. package/dist/backends/node-sqlite.d.ts +38 -0
  7. package/dist/backends/node-sqlite.js +335 -0
  8. package/dist/backends/node-sqlite.js.map +1 -0
  9. package/dist/backends/sqlite-wasm.d.ts +130 -0
  10. package/dist/backends/sqlite-wasm.js +259 -0
  11. package/dist/backends/sqlite-wasm.js.map +1 -0
  12. package/dist/chunks/sqlite-DFg92Tgt.js +498 -0
  13. package/dist/chunks/sqlite-DFg92Tgt.js.map +1 -0
  14. package/dist/cloudflare-workers.js +351 -0
  15. package/dist/cloudflare-workers.js.map +1 -0
  16. package/dist/conformance/host.d.ts +58 -0
  17. package/dist/conformance.js +18 -0
  18. package/dist/conformance.js.map +1 -0
  19. package/dist/index.js +7184 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/server/alarm-scheduler.js +513 -0
  22. package/dist/server/alarm-scheduler.js.map +1 -0
  23. package/dist/src/api/actor-state.d.ts +396 -0
  24. package/dist/src/api/actor.d.ts +306 -0
  25. package/dist/src/api/cloudflare-workers.d.ts +259 -0
  26. package/dist/src/api/export-loopback.d.ts +264 -0
  27. package/dist/src/api/global-scope.d.ts +262 -0
  28. package/dist/src/api/http.d.ts +52 -0
  29. package/dist/src/api/sql.d.ts +188 -0
  30. package/dist/src/api/sync-kv.d.ts +51 -0
  31. package/dist/src/api/web-socket.d.ts +93 -0
  32. package/dist/src/api/worker-loader.d.ts +354 -0
  33. package/dist/src/index.d.ts +130 -0
  34. package/dist/src/io/actor-cache.d.ts +203 -0
  35. package/dist/src/io/actor-id.d.ts +74 -0
  36. package/dist/src/io/actor-sqlite.d.ts +298 -0
  37. package/dist/src/io/io-channels.d.ts +191 -0
  38. package/dist/src/io/io-context.d.ts +451 -0
  39. package/dist/src/io/io-gate.d.ts +298 -0
  40. package/dist/src/io/worker-source.d.ts +108 -0
  41. package/dist/src/io/worker.d.ts +88 -0
  42. package/dist/src/server/actor-container.d.ts +525 -0
  43. package/dist/src/server/actor-id-impl.d.ts +118 -0
  44. package/dist/src/server/alarm-scheduler.d.ts +201 -0
  45. package/dist/src/server/facet-deletion.d.ts +156 -0
  46. package/dist/src/server/facet-tree-index.d.ts +94 -0
  47. package/dist/src/server/sha256.d.ts +39 -0
  48. package/dist/src/transport/rpc-session.d.ts +34 -0
  49. package/dist/src/util/sqlite-kv.d.ts +98 -0
  50. package/dist/src/util/sqlite-metadata.d.ts +46 -0
  51. package/dist/src/util/sqlite.d.ts +291 -0
  52. package/package.json +111 -0
@@ -0,0 +1,203 @@
1
+ /**
2
+ * ← workerd `src/workerd/io/actor-cache.h` — INTERFACE ONLY.
3
+ *
4
+ * The `actor-cache.c++` LRU implementation is ABSENT rather than skipped: it
5
+ * caches a remote storage service that none of our substrates have. Upstream
6
+ * does not use it in SQLite mode either — `ActorSqlite` is the sole
7
+ * `ActorCacheInterface` implementation there, and the same is true here.
8
+ *
9
+ * The two behaviours decision 5 names live in `io/actor-sqlite.ts`, which is
10
+ * where workerd's SQLite path exhibits them: `allowUnconfirmed` skips the
11
+ * output-gate lock but STILL breaks the gate on error, and a batch started as
12
+ * unconfirmed is retroactively upgraded when a must-confirm write joins it.
13
+ *
14
+ * Ordering guarantee, upstream's words (`actor-cache.h:334-340`): writes are
15
+ * never committed out-of-order, by brute force — one transaction commits all
16
+ * dirty keys at once.
17
+ *
18
+ * This file carries only what `ActorSqlite` genuinely implements. Everything in
19
+ * `ActorCacheInterface` that exists solely for the LRU — `evictStale`'s
20
+ * backpressure, the RPC storage client, the shared LRU and its hooks — is
21
+ * absent with it.
22
+ *
23
+ * The one shape that is ours rather than upstream's: **every read and write is
24
+ * synchronous.** Upstream returns `kj::OneOf<T, kj::Promise<T>>` so a cache miss
25
+ * can go to the network; §1.4 measures that a SQLite-backed actor never does,
26
+ * and the SQLite arm of every one of those `OneOf`s is the immediate value. A
27
+ * `OneOf` with one reachable arm is a promise nobody can observe, and keeping it
28
+ * would make `api/actor-state.ts` unwrap something that is never a promise.
29
+ * `onNoPendingFlush` and `abandonAlarm` stay asynchronous because upstream's
30
+ * SQLite arm is genuinely asynchronous there.
31
+ *
32
+ * Spec: §1.7, decisions 2 and 5.
33
+ */
34
+ /** ← `ActorCacheOps::Key`. "Keys are text for now." */
35
+ export type Key = string;
36
+ /** ← `ActorCacheOps::Value`. Values are raw bytes; the value encoding is `api/`'s. */
37
+ export type Value = Uint8Array;
38
+ /** ← `ActorCacheOps::KeyValuePair`. */
39
+ export type KeyValuePair = {
40
+ readonly key: Key;
41
+ readonly value: Value;
42
+ };
43
+ /**
44
+ * ← `ActorCacheOps::GetResultList`, which upstream makes a class so it can
45
+ * iterate pointers into the cache's own storage. Ours has already copied.
46
+ */
47
+ export type GetResultList = readonly KeyValuePair[];
48
+ /**
49
+ * The option bags. Per §1.2 `allowConcurrency` is precisely the input-gate
50
+ * opt-out: it selects `awaitIo` over `awaitIoWithInputLock`, which per §1.7.1
51
+ * also ends the implicit transaction.
52
+ *
53
+ * Nothing passes any of these today — not upstream, not this repo, not the
54
+ * vendored tests. They are built anyway; building half of the
55
+ * `awaitIoWithInputLock` branch is the feature-subset failure the porting
56
+ * philosophy rejects. The conformance suite exercises them deliberately.
57
+ *
58
+ * Placement note: upstream's `ActorCacheReadOptions` holds only `noCache`, and
59
+ * `allowConcurrency` is read one layer up, in `DurableObjectStorageOperations`
60
+ * (`actor-state.c++:68-79`) — `ActorCacheOps` never sees it. Part 4's table puts
61
+ * decision 2 in this file, so it is declared here and consumed by `api/`;
62
+ * `ActorSqlite` itself reads neither `allowConcurrency` nor `noCache`, exactly
63
+ * as upstream's does not.
64
+ */
65
+ export type ReadOptions = {
66
+ /** Release the input gate across the await. Ends the implicit transaction. */
67
+ allowConcurrency?: boolean;
68
+ /** Do not retain the value in cache. */
69
+ noCache?: boolean;
70
+ };
71
+ export type WriteOptions = ReadOptions & {
72
+ /** Skip the output-gate lock. Never skips break-on-error. */
73
+ allowUnconfirmed?: boolean;
74
+ };
75
+ /** ← `DeleteAllOptions`. */
76
+ export type DeleteAllOptions = {
77
+ /**
78
+ * When true, deleteAll() will also delete any scheduled alarm. The alarm
79
+ * deletion is guaranteed to take effect only after the deleteAll() itself
80
+ * succeeds, so that we never end up in a state where the alarm is deleted but
81
+ * KV data remains.
82
+ */
83
+ deleteAlarm?: boolean;
84
+ };
85
+ /**
86
+ * ← `ActorCacheInterface::DeleteAllResults`.
87
+ *
88
+ * Upstream splits these "so client code that doesn't need the count doesn't have
89
+ * to wait for it just to account for backpressure". Both arms are immediate for
90
+ * SQLite: `backpressure` is always `kj::none` and `count` is a ready promise.
91
+ */
92
+ export type DeleteAllResults = {
93
+ readonly backpressure: Promise<void> | undefined;
94
+ readonly count: number;
95
+ };
96
+ /**
97
+ * ← `ActorCacheInterface::CancelAlarmHandler`. Alarm should be canceled without
98
+ * retry, because alarm state has changed such that the requested alarm time is
99
+ * no longer valid.
100
+ */
101
+ export type CancelAlarmHandler = {
102
+ /** Caller should wait for this promise to complete before canceling. */
103
+ readonly waitBeforeCancel: Promise<void>;
104
+ };
105
+ /**
106
+ * ← the `kj::Own<void>` that `RunAlarmHandler` carries, whose disposer runs
107
+ * `maybeDeleteDeferredAlarm()`. Section 1's rule applies: a kj destructor
108
+ * becomes an explicit call, so the caller attaches `drop()` to the promise
109
+ * representing the handler's execution rather than a scope exit.
110
+ */
111
+ export interface DeferredAlarmDeleter {
112
+ drop(): void;
113
+ }
114
+ /** ← `ActorCacheInterface::RunAlarmHandler`. Alarm should be run. */
115
+ export type RunAlarmHandler = {
116
+ readonly deferredDelete: DeferredAlarmDeleter;
117
+ };
118
+ /** ← `kj::OneOf<CancelAlarmHandler, RunAlarmHandler>`. */
119
+ export type ArmAlarmResult = {
120
+ readonly kind: "cancel";
121
+ readonly cancel: CancelAlarmHandler;
122
+ } | {
123
+ readonly kind: "run";
124
+ readonly run: RunAlarmHandler;
125
+ };
126
+ /** ← `ActorCache::SHUTDOWN_ERROR_MESSAGE`, which `ActorSqlite::shutdown` reuses. */
127
+ export declare const SHUTDOWN_ERROR_MESSAGE = "broken.ignored; jsg.Error: Durable Object storage is no longer accessible.";
128
+ /**
129
+ * ← the message every unimplemented `ActorCacheInterface` PITR method throws.
130
+ * `ActorSqlite` overrides two of the four; the other two keep this.
131
+ */
132
+ export declare const PITR_UNIMPLEMENTED_MESSAGE = "This Durable Object's storage back-end does not implement point-in-time recovery.";
133
+ /** ← the message the three replication methods throw. */
134
+ export declare const REPLICATION_UNIMPLEMENTED_MESSAGE = "This Durable Object's storage back-end does not support replication.";
135
+ /**
136
+ * Common interface between the storage engine and a transaction on it.
137
+ *
138
+ * ← `ActorCacheOps`. Upstream's `list`/`listReverse` split exists because the
139
+ * two directions "require a subtly different implementation of pretty much the
140
+ * entire algorithm" in the cache; both are kept, because both are separate
141
+ * entry points a caller reaches.
142
+ */
143
+ export interface ActorCacheOps {
144
+ get(key: Key, options: ReadOptions): Value | undefined;
145
+ getMultiple(keys: readonly Key[], options: ReadOptions): GetResultList;
146
+ getAlarm(options: ReadOptions): number | null;
147
+ list(begin: Key, end: Key | undefined, limit: number | undefined, options: ReadOptions): GetResultList;
148
+ listReverse(begin: Key, end: Key | undefined, limit: number | undefined, options: ReadOptions): GetResultList;
149
+ put(key: Key, value: Value, options: WriteOptions): void;
150
+ putMultiple(pairs: readonly KeyValuePair[], options: WriteOptions): void;
151
+ /** Returns whether the key was present. */
152
+ delete(key: Key, options: WriteOptions): boolean;
153
+ /** Returns how many of the keys were present. */
154
+ deleteMultiple(keys: readonly Key[], options: WriteOptions): number;
155
+ setAlarm(newAlarmTime: number | null, options: WriteOptions): void;
156
+ }
157
+ /**
158
+ * ← `ActorCacheInterface::Transaction`.
159
+ *
160
+ * "If commit() is not called before the Transaction is destroyed, nothing is
161
+ * written." JS has no destruction, so `drop()` is that moment and exactly one of
162
+ * `commit()`/`rollback()`+`drop()` has to run — the same contract Section 1
163
+ * established for `Lock` and `CriticalSection`.
164
+ */
165
+ export interface ActorCacheTransaction extends ActorCacheOps {
166
+ /**
167
+ * Write all changes to the underlying storage.
168
+ *
169
+ * "This will NOT detect conflicts, it will always just write blindly, because
170
+ * conflicts inherently cannot happen."
171
+ */
172
+ commit(): void;
173
+ rollback(): void;
174
+ /** ← `~ExplicitTxn`: roll back if not committed, then leave the txn stack. */
175
+ drop(): void;
176
+ }
177
+ /**
178
+ * Abstract interface that upstream implements twice, and that this package
179
+ * implements once — `ActorSqlite` is the sole implementation, exactly as on
180
+ * workerd-with-SQLite.
181
+ */
182
+ export interface ActorCacheInterface extends ActorCacheOps {
183
+ startTransaction(): ActorCacheTransaction;
184
+ deleteAll(options: WriteOptions, deleteAllOptions?: DeleteAllOptions): DeleteAllResults;
185
+ /**
186
+ * "Call each time the isolate lock is taken to evict stale entries." There is
187
+ * no cache to evict from and never any backpressure to apply.
188
+ */
189
+ evictStale(now: number): undefined;
190
+ shutdown(exception?: unknown): void;
191
+ armAlarmHandler(scheduledTime: number, currentTime: number): ArmAlarmResult;
192
+ cancelDeferredAlarmDeletion(): void;
193
+ abandonAlarm(scheduledTime: number): Promise<number | null>;
194
+ /** Implements `sync()`. */
195
+ onNoPendingFlush(): Promise<void>;
196
+ getCurrentBookmark(): Promise<string>;
197
+ getBookmarkForTime(timestamp: number): Promise<string>;
198
+ onNextSessionRestoreBookmark(bookmark: string): Promise<string>;
199
+ waitForBookmark(bookmark: string): Promise<void>;
200
+ ensureReplicas(): void;
201
+ disableReplicas(): void;
202
+ configureReadReplication(enabled: boolean): Promise<void>;
203
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * ← workerd `src/workerd/io/actor-id.h` (74 lines, header-only — there is no
3
+ * `actor-id.c++`).
4
+ *
5
+ * `api/actor.h` includes this file directly, and every type in it is named by
6
+ * `api/actor.{h,c++}`: `ActorIdFactory` is `DurableObjectNamespace`'s member,
7
+ * `ActorIdFactory::ActorId` is what a `DurableObjectId` wraps, and
8
+ * `ActorGetMode` / `ActorRoutingMode` / `ActorVersion` are the three parameters
9
+ * `getImpl` computes before handing them to an outgoing factory. Per the
10
+ * package README's rule for a legitimate upstream include crossing a wall, the
11
+ * reference widens to match upstream rather than the declarations being
12
+ * relocated into `api/`.
13
+ *
14
+ * The whole file is ported. What is NOT here is the **implementation** —
15
+ * upstream's is `server/actor-id-impl.{h,c++}`, a keyed SHA-256 construction —
16
+ * because it is `server/`'s and because a faithful port of it needs a
17
+ * synchronous digest, which the browser does not expose (`crypto.subtle` is
18
+ * asynchronous and every method below is synchronous). That is Section 6's
19
+ * problem to solve, and this interface is the seam it fills.
20
+ *
21
+ * Spec: §1.10 in docs/decisions.md.
22
+ */
23
+ /**
24
+ * ← `ActorGetMode`. "Behavior mode for getting an actor."
25
+ *
26
+ * A union of the upstream enumerator names rather than a TypeScript `enum`,
27
+ * which is the shape every other discriminant in this package already takes.
28
+ */
29
+ export type ActorGetMode = "GET_OR_CREATE" | "GET_EXISTING";
30
+ /** ← `ActorRoutingMode`. "Routing mode for actor requests when replicas are available." */
31
+ export type ActorRoutingMode = "DEFAULT" | "PRIMARY_ONLY";
32
+ /** ← `ActorVersion`. "Version information for an actor. Used to specify cohort." */
33
+ export type ActorVersion = {
34
+ readonly cohort?: string;
35
+ };
36
+ /**
37
+ * ← `ActorIdFactory::ActorId`. "Abstract actor ID."
38
+ *
39
+ * Upstream's comment, kept because it is the reason this is an interface rather
40
+ * than a class: "This is NOT an I/O type. An ActorId created in one IoContext
41
+ * can be used in other IoContexts."
42
+ *
43
+ * `clone()` is dropped: it exists so a `kj::Own<ActorId>` can be copied out of a
44
+ * borrowed reference, and a JS value needs no such thing. Every upstream call
45
+ * site (`DurableObjectId`'s constructor, `cloneId()`, the facet start info) is
46
+ * satisfied by passing the same object.
47
+ */
48
+ export interface ActorId {
49
+ /** "Get the string that could be passed to `idFromString()` to recreate this ID." */
50
+ toString(): string;
51
+ /**
52
+ * "If the ActorId was created using `idFromName()`, return a copy of the name
53
+ * that was passed to it. Otherwise, returns null."
54
+ */
55
+ getName(): string | undefined;
56
+ /** "Get the jurisdiction that was used when creating this ID." */
57
+ getJurisdiction(): string | undefined;
58
+ /**
59
+ * "Compare with another ID. This is allowed to assume the other ID was created
60
+ * by some other ActorIdFactory passed to one of the worker's other bindings."
61
+ */
62
+ equals(other: ActorId): boolean;
63
+ }
64
+ /**
65
+ * ← `ActorIdFactory`. "An abstract class that implements generation of global
66
+ * actor IDs in a particular namespace."
67
+ */
68
+ export interface ActorIdFactory {
69
+ newUniqueId(jurisdiction: string | undefined): ActorId;
70
+ idFromName(name: string): ActorId;
71
+ idFromString(str: string): ActorId;
72
+ matchesJurisdiction(id: ActorId): boolean;
73
+ cloneWithJurisdiction(maybeJurisdiction: string | undefined): ActorIdFactory;
74
+ }
@@ -0,0 +1,298 @@
1
+ /**
2
+ * ← workerd `src/workerd/io/actor-sqlite.{h,c++}`
3
+ *
4
+ * The storage engine. Owns:
5
+ * - implicit transactions, bounded by GATE RELEASE rather than by an
6
+ * event-loop turn (§1.7.1 — measured; a storage await does not end the
7
+ * transaction, a timer or outbound await does);
8
+ * - `onWrite` taking the output-gate lock at the first must-confirm write,
9
+ * one lock per flush batch;
10
+ * - `transactionSync` as SAVEPOINT/RELEASE/ROLLBACK TO with a depth counter,
11
+ * plus the async-callback guard today's version lacks;
12
+ * - alarm arm/consume/deferred-deletion, and `deleteAll`.
13
+ *
14
+ * Sole `ActorCacheInterface` implementation, exactly as on workerd-with-SQLite.
15
+ *
16
+ * The single most important constraint in the whole port lives here: the
17
+ * transaction boundary and the gate boundary are the same line. Implement them
18
+ * as one mechanism. Release at every await — the naive reading of §1.2 — and
19
+ * every multi-statement write silently loses atomicity, with nothing failing
20
+ * until a crash lands between two statements that were meant to be one.
21
+ *
22
+ * **How that one line is drawn here, since it is the question the design record
23
+ * left open.** Upstream needs no gate hook: `startImplicitTxn` wraps the commit
24
+ * in `kj::evalLater`, which runs it on the next turn of the KJ event loop, and
25
+ * the next KJ turn is by construction after the isolate run — which is after
26
+ * `js.runMicrotasks()`, which is after `KJ_DEFER` clears `currentInputLock`.
27
+ * "Next turn" and "gate release" are one boundary upstream, so `ActorSqlite`
28
+ * hangs the commit on the cheaper of the two. They are one boundary here for the
29
+ * same reason, provided the commit rides `atCheckpointEnd` — the primitive
30
+ * `io-context.ts` releases on. Its comment carries the proof; the short form is
31
+ * that holding the lock across an await is a pure microtask chain and releasing
32
+ * it always costs a hand-off, so no write can cross a hand-off inside one
33
+ * transaction and no two events can share one. `IoContext` therefore grows no
34
+ * per-invocation exit notification, and the root gate's `inputGateReleased` hook
35
+ * is *not* the right edge: it fires when `lockCount` hits zero, which never
36
+ * happens inside a critical section, so decision 4's fifteen boot phases would
37
+ * become a single transaction nobody chose.
38
+ *
39
+ * `onWrite` and `onCriticalError` are `SqliteDatabase`'s, in `util/sqlite.ts`,
40
+ * exactly as upstream has them, and the constructor binds itself to both the way
41
+ * `ActorSqlite`'s does. What is ours is only the substitute for the question
42
+ * upstream answers with `sqlite3_stmt_readonly()` — see `isWrite` there.
43
+ *
44
+ * Not ported, because the substrate has no equivalent to port onto: `SpanParent`
45
+ * tracing, already a Section 1 divergence, so every `traceSpan` parameter and
46
+ * `currentCommitSpan` with it; `debugAlarmSync` and every `LOG_*`, which are a
47
+ * logger this package does not have; and `TxnCommitRegulator::onError`, which
48
+ * re-reports `SQLITE_CONSTRAINT` during commit as a user-visible error — error
49
+ * codes do not cross the backend seam, the same reason Section 3 dropped
50
+ * `SqliteKvRegulator::onError`.
51
+ *
52
+ * Spec: §1.4, §1.7, §1.7.1, §1.8, §2.4, §2.6, decisions 2, 5, 6 and 7 in
53
+ * docs/decisions.md.
54
+ */
55
+ import type { ActorCacheInterface, ActorCacheTransaction, ArmAlarmResult, DeleteAllOptions, DeleteAllResults, GetResultList, Key, KeyValuePair, ReadOptions, Value, WriteOptions } from "./actor-cache.js";
56
+ import type { OutputGate } from "./io-gate.js";
57
+ import { SqliteKv } from "../util/sqlite-kv.js";
58
+ import { SqliteDatabase } from "../util/sqlite.js";
59
+ /**
60
+ * The alarm port — one outbound method, matching upstream's seam exactly.
61
+ *
62
+ * Everything else about alarms is runtime-internal: arm/consume semantics here,
63
+ * retry ladder and serialised delivery in `server/alarm-scheduler.ts`. Delivery
64
+ * comes back IN through `ActorContainer.deliverAlarm`, not through this port.
65
+ */
66
+ export interface AlarmOutlet {
67
+ /**
68
+ * Must be durable before the returned promise resolves.
69
+ *
70
+ * `priorTask` is upstream's second parameter and is load bearing rather than
71
+ * decorative: "any work we must wait on prior to scheduling the new request,
72
+ * as of this writing, this would be the alarmLaterInFlight promise, which
73
+ * tracks any in-flight request to move the alarm 'later' than is currently
74
+ * set." An implementation that ignores it can send a move-earlier request
75
+ * concurrently with a move-later one and lose the ordering invariant that the
76
+ * scheduled alarm is always at or before the persisted one.
77
+ *
78
+ * May throw synchronously; `ActorSqlite` relies on it, because a scheduling
79
+ * failure has to reach the caller before the local database commits.
80
+ */
81
+ scheduleRun(newAlarmTime: number | null, priorTask: Promise<void>): Promise<void>;
82
+ }
83
+ /** ← `ActorSqlite::Hooks::DEFAULT`, whose `scheduleRun` refuses. */
84
+ export declare const DEFAULT_ALARM_OUTLET: AlarmOutlet;
85
+ /**
86
+ * ← `kj::TaskSet` plus its `ErrorHandler`. `ActorSqlite` owns one of its own,
87
+ * separate from `IoContext`'s, exactly as upstream does.
88
+ */
89
+ declare class TaskSet {
90
+ #private;
91
+ constructor(taskFailed: (exception: unknown) => void);
92
+ add(promise: Promise<void>): void;
93
+ }
94
+ /** ← `kj::OneOf<NoTxn, ImplicitTxn*, ExplicitTxn*>`. */
95
+ type CurrentTxn = {
96
+ readonly kind: "none";
97
+ } | {
98
+ readonly kind: "implicit";
99
+ readonly txn: ImplicitTxn;
100
+ } | {
101
+ readonly kind: "explicit";
102
+ readonly txn: ExplicitTxn;
103
+ };
104
+ /** ← `ActorSqlite::PrecommitAlarmState`. */
105
+ type PrecommitAlarmState = {
106
+ /** Promise for the completion of precommit alarm scheduling */
107
+ schedulingPromise?: Promise<void>;
108
+ };
109
+ /**
110
+ * An implementation of ActorCacheOps that is backed by SqliteKv.
111
+ *
112
+ * Constructing one arranges to honor the output gate, that is, any writes to the
113
+ * database which occur without any `await`s in between will automatically be
114
+ * combined into a single atomic write. This is accomplished using transactions.
115
+ * In addition to ensuring atomicity, this tends to improve performance, as
116
+ * SQLite is able to coalesce writes across statements that modify the same page.
117
+ *
118
+ * `commitCallback` will be invoked after committing a transaction. The output
119
+ * gate will block on the returned promise. This can be used e.g. when the
120
+ * database needs to be replicated to other machines before being considered
121
+ * durable.
122
+ *
123
+ * Members upstream marks `private` and reaches through `ImplicitTxn` and
124
+ * `ExplicitTxn`, which are nested classes with implicit friendship, are ordinary
125
+ * members here for the reason `io-gate.ts` gives: TypeScript has no friendship,
126
+ * and the boundary that actually holds is the package facade in `src/index.ts`.
127
+ */
128
+ export declare class ActorSqlite implements ActorCacheInterface {
129
+ #private;
130
+ /** Upstream-private; reached by the two transaction classes. */
131
+ readonly db: SqliteDatabase;
132
+ /** Upstream-private; reached by the two transaction classes. */
133
+ readonly outputGate: OutputGate;
134
+ /** Upstream-private; reached by the two transaction classes. */
135
+ readonly commitTasks: TaskSet;
136
+ /** Upstream-private; the transaction classes read it to skip their rollback. */
137
+ broken: unknown | undefined;
138
+ /**
139
+ * When set to `none`, there is no transaction outstanding.
140
+ *
141
+ * When set to an `ImplicitTxn`, an implicit transaction is currently open,
142
+ * owned by `commitTasks`. If there is a need to commit this early, e.g. to
143
+ * start an explicit transaction, that can be done through this reference.
144
+ *
145
+ * When set to an `ExplicitTxn`, an explicit transaction is currently open, so
146
+ * no implicit transactions should be used in the meantime.
147
+ */
148
+ currentTxn: CurrentTxn;
149
+ /**
150
+ * State for tracking completion of all commits (both confirmed and
151
+ * unconfirmed) for implementing sync() in onNoPendingFlush.
152
+ *
153
+ * Upstream-private; `ExplicitTxn::commit` replaces it.
154
+ */
155
+ lastCommit: Promise<void>;
156
+ /**
157
+ * We need to track some additional alarm state to guarantee at-least-once
158
+ * alarm delivery: within an alarm handler, we want the observable alarm state
159
+ * to look like the running alarm was deleted at the start of the handler (when
160
+ * armAlarmHandler() is called), but we don't actually want to persist that
161
+ * deletion until after the handler has successfully completed.
162
+ *
163
+ * Upstream-private; `ExplicitTxn::commit` clears it when the txn was alarm-dirty.
164
+ */
165
+ haveDeferredDelete: boolean;
166
+ constructor(db: SqliteDatabase, outputGate: OutputGate, commitCallback: () => Promise<void>, hooks?: AlarmOutlet);
167
+ isCommitScheduled(): boolean;
168
+ getSqliteDatabase(): SqliteDatabase;
169
+ getSqliteKv(): SqliteKv;
170
+ /**
171
+ * To be called just before committing the local sqlite db, to synchronously
172
+ * start any necessary alarm scheduling.
173
+ *
174
+ * Upstream-private; `ExplicitTxn::commit` calls it for the root transaction.
175
+ */
176
+ startPrecommitAlarmScheduling(): PrecommitAlarmState;
177
+ /**
178
+ * Performs the rest of the asynchronous commit, to be waited on after
179
+ * committing the local sqlite db. Should be called in the same turn of the
180
+ * event loop as startPrecommitAlarmScheduling() and passed the state that it
181
+ * returned.
182
+ *
183
+ * Upstream-private; `ExplicitTxn::commit` calls it for the root transaction.
184
+ */
185
+ commitImpl(precommitAlarmState: PrecommitAlarmState): Promise<void>;
186
+ /** Upstream-private; the transaction classes call it before touching the db. */
187
+ requireNotBroken(): void;
188
+ get(key: Key, _options?: ReadOptions): Value | undefined;
189
+ getMultiple(keys: readonly Key[], _options?: ReadOptions): GetResultList;
190
+ getAlarm(_options?: ReadOptions): number | null;
191
+ list(begin: Key, end: Key | undefined, limit: number | undefined, _options?: ReadOptions): GetResultList;
192
+ listReverse(begin: Key, end: Key | undefined, limit: number | undefined, _options?: ReadOptions): GetResultList;
193
+ put(key: Key, value: Value, options?: WriteOptions): void;
194
+ putMultiple(pairs: readonly KeyValuePair[], options?: WriteOptions): void;
195
+ delete(key: Key, options?: WriteOptions): boolean;
196
+ deleteMultiple(keys: readonly Key[], options?: WriteOptions): number;
197
+ setAlarm(newAlarmTime: number | null, options?: WriteOptions): void;
198
+ startTransaction(): ActorCacheTransaction;
199
+ deleteAll(options?: WriteOptions, deleteAllOptions?: DeleteAllOptions): DeleteAllResults;
200
+ evictStale(_now: number): undefined;
201
+ shutdown(exception?: unknown): void;
202
+ armAlarmHandler(scheduledTime: number, currentTime: number): ArmAlarmResult;
203
+ cancelDeferredAlarmDeletion(): void;
204
+ abandonAlarm(scheduledTime: number): Promise<number | null>;
205
+ /**
206
+ * This implements sync().
207
+ *
208
+ * sync() should wait for ALL writes (both confirmed and unconfirmed) that are
209
+ * outstanding at the time sync() is called. We use lastCommit which keeps track
210
+ * of the most recent commit to be formed. We join with the outputGate because
211
+ * there are a lot of edge cases where we break the output gate and it's easiest
212
+ * to catch all of those instances here rather than updating everything to also
213
+ * break lastCommit.
214
+ */
215
+ onNoPendingFlush(): Promise<void>;
216
+ /**
217
+ * This is an ersatz implementation that's good enough for local dev with D1's
218
+ * Session API.
219
+ *
220
+ * The returned bookmark satisfies the properties that D1 cares about:
221
+ *
222
+ * * Later bookmarks sort after earlier bookmarks. We implement this by
223
+ * incrementing the bookmark whenever getCurrentBookmark() is called.
224
+ *
225
+ * * Bookmarks from the current session sort after bookmarks from previous
226
+ * sessions. We implement this by saving an ersatz bookmark in the metadata
227
+ * table.
228
+ *
229
+ * This is NOT the point-in-time-recovery bookmark API, which is a substrate
230
+ * boundary: it needs nothing the substrate lacks, which is exactly why Section
231
+ * 3 ported `getLocalDevelopmentBookmark`/`setLocalDevelopmentBookmark`.
232
+ */
233
+ getCurrentBookmark(): Promise<string>;
234
+ waitForBookmark(_bookmark: string): Promise<void>;
235
+ getBookmarkForTime(_timestamp: number): Promise<string>;
236
+ onNextSessionRestoreBookmark(_bookmark: string): Promise<string>;
237
+ ensureReplicas(): void;
238
+ disableReplicas(): void;
239
+ configureReadReplication(_enabled: boolean): Promise<void>;
240
+ /**
241
+ * ← `DurableObjectStorage::transactionSync` (`actor-state.c++:713-753`).
242
+ *
243
+ * One layer lower than upstream, which is where `util/sqlite.ts` already
244
+ * records it belongs: the savepoint depth counter and `notifyWrite` both live
245
+ * here, and `api/actor-state.ts`'s `transactionSync` becomes a one-line forward
246
+ * the way `blockConcurrencyWhile` already is.
247
+ *
248
+ * The nesting guard §2.4 asks for is upstream's own and is the depth-named
249
+ * savepoint: a second `BEGIN IMMEDIATE` is a SQLite error, a nested SAVEPOINT
250
+ * is not, which is why this issues savepoints and lets the implicit transaction
251
+ * underneath be the only `BEGIN`.
252
+ *
253
+ * The async-callback guard is ours and has no upstream twin, because upstream's
254
+ * `jsg::Function<jsg::JsRef<jsg::JsValue>()>` callback cannot be awaited at
255
+ * all: it returns a value, and a JS function that returns a promise simply has
256
+ * its promise ignored. Here the same mistake is silent and corrupting — the
257
+ * RELEASE fires at the first await and everything after it lands outside the
258
+ * transaction — so a thenable result is refused and the savepoint rolled back.
259
+ * Work the callback already started is not cancellable and keeps running; the
260
+ * throw is what stops it being mistaken for transactional.
261
+ */
262
+ transactionSync<T>(callback: () => T): T;
263
+ }
264
+ /** ← `ActorSqlite::ImplicitTxn`. */
265
+ declare class ImplicitTxn {
266
+ #private;
267
+ constructor(parent: ActorSqlite);
268
+ commit(): void;
269
+ rollback(): void;
270
+ setSomeWriteConfirmed(someWriteConfirmed: boolean): void;
271
+ isSomeWriteConfirmed(): boolean;
272
+ /** ← `~ImplicitTxn`. Idempotent, because the commit path drops before and after the callback. */
273
+ drop(): void;
274
+ }
275
+ /** ← `ActorSqlite::ExplicitTxn`. */
276
+ declare class ExplicitTxn implements ActorCacheTransaction {
277
+ #private;
278
+ constructor(actorSqlite: ActorSqlite);
279
+ getAlarmDirty(): boolean;
280
+ setAlarmDirty(): void;
281
+ setSomeWriteConfirmed(someWriteConfirmed: boolean): void;
282
+ isSomeWriteConfirmed(): boolean;
283
+ commit(): void;
284
+ rollback(): void;
285
+ /** ← `~ExplicitTxn`. */
286
+ drop(): void;
287
+ get(key: Key, options?: ReadOptions): Value | undefined;
288
+ getMultiple(keys: readonly Key[], options?: ReadOptions): GetResultList;
289
+ getAlarm(options?: ReadOptions): number | null;
290
+ list(begin: Key, end: Key | undefined, limit: number | undefined, options?: ReadOptions): GetResultList;
291
+ listReverse(begin: Key, end: Key | undefined, limit: number | undefined, options?: ReadOptions): GetResultList;
292
+ put(key: Key, value: Value, options?: WriteOptions): void;
293
+ putMultiple(pairs: readonly KeyValuePair[], options?: WriteOptions): void;
294
+ delete(key: Key, options?: WriteOptions): boolean;
295
+ deleteMultiple(keys: readonly Key[], options?: WriteOptions): number;
296
+ setAlarm(newAlarmTime: number | null, options?: WriteOptions): void;
297
+ }
298
+ export {};