@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,188 @@
1
+ /**
2
+ * ← workerd `src/workerd/api/sql.{h,c++}`
3
+ *
4
+ * `SqlStorage` and its two nested types. ~330 call sites depend on this — it is
5
+ * the real storage layer, not KV.
6
+ *
7
+ * Four things about the translation, in descending order of how much they cost:
8
+ *
9
+ * 1. **The cursor is materialised, not live.** Upstream's `Cursor` owns a
10
+ * running `SqliteDatabase::Query` and pulls one row at a time; the backend
11
+ * seam this package chose (`SqlDatabase.exec` → `SqlResult`) has already
12
+ * collected every row before a cursor exists. Everything downstream of that
13
+ * follows: there is no statement cache, so `CachedStatement`, the 1 MiB LRU
14
+ * and `reusedCachedQueryForTest` are absent with it; there is no live
15
+ * statement to cancel, so `Cursor::canceled` and `selfRef` — both already
16
+ * dead upstream, written but never assigned — have nothing to guard; and
17
+ * `endQuery`'s job of returning a statement to the cache is nothing here, so
18
+ * the counters it saves off are simply the counters. What is kept is every
19
+ * observable: the position is shared across `next`/`toArray`/`one`/`raw`,
20
+ * and a drained cursor keeps yielding done.
21
+ * 2. **`Cursor` and `Statement` must be constructible with no arguments**, or
22
+ * `SqlStorage` cannot satisfy workers-types without a cast: the interface
23
+ * types them `typeof SqlStorageCursor` / `typeof SqlStorageStatement`, and
24
+ * both are `abstract` there, so their construct signatures take none.
25
+ * Upstream's are unconstructible from JS for the same reason they are
26
+ * `abstract` in the types — JSG nested types have no JS constructor — so the
27
+ * faithful shape is a constructor that refuses. `sql.Cursor` exists for
28
+ * `instanceof`, which is all upstream exposes it for.
29
+ * 3. **The regulator is ported whole; what is missing is the authorizer that
30
+ * calls it.** All three callbacks are here and none of them needed the
31
+ * authorizer to compute anything — `isAllowedName` is a prefix test,
32
+ * `isAllowedTrigger` is `return true`, `allowTransactions` throws. What the
33
+ * authorizer supplied was the *identifiers*, not the decisions. With no
34
+ * authorizer the statement text is the only source, so `exec` tokenizes it
35
+ * and runs `isAllowedName` over every identifier-shaped token. That is
36
+ * deliberately STRICTER than upstream — see `SQL_RESERVED_PREFIX_MESSAGE`.
37
+ * 4. **`ingest` stays at upstream's SQLite seam.** `SqliteDatabase.ingest()`
38
+ * executes every complete statement and returns the partial tail, using the
39
+ * same compiled boundaries and regulator as `exec`.
40
+ *
41
+ * Spec: §1.4, §2.4 in docs/decisions.md.
42
+ */
43
+ import type { IoContext } from "../io/io-context.js";
44
+ import type { SqlIngestResult, SqliteDatabase } from "../util/sqlite.js";
45
+ /**
46
+ * ← `SqlStorage::BindingValue`. JSG converts these public JavaScript values
47
+ * to workerd's `Maybe<OneOf<Array<byte>, String, double>>` before C++ sees them;
48
+ * `toSqlBindingValue()` is that conversion for this no-isolate runtime.
49
+ */
50
+ export type BindingValue = ArrayBuffer | ArrayBufferView | string | number | boolean | null | undefined;
51
+ /** ← the `SqlStorageValue` `JSG_TS_DEFINE` on `Cursor`. */
52
+ export type SqlRow = Record<string, SqlStorageValue>;
53
+ /** ← `SqlStorage::IngestResult`. */
54
+ export type SqlStorageIngestResult = SqlIngestResult;
55
+ /**
56
+ * ← `SqlStorageRegulator::allowTransactions()`, copied verbatim. Users match on
57
+ * it and it is the one regulator callback our substrate can still answer.
58
+ */
59
+ export declare const SQL_TRANSACTION_REFUSED_MESSAGE: string;
60
+ /** See translation 2 in the header: the class is exposed for `instanceof` only. */
61
+ export declare const CURSOR_NOT_CONSTRUCTIBLE_MESSAGE = "Illegal invocation: SqlStorage.Cursor cannot be constructed directly. Use sql.exec().";
62
+ /** Same, for the prepared-statement compatibility shim. */
63
+ export declare const STATEMENT_NOT_CONSTRUCTIBLE_MESSAGE = "Illegal invocation: SqlStorage.Statement cannot be constructed directly. Use sql.prepare().";
64
+ /**
65
+ * ← SQLite's own denial text, with the reason appended.
66
+ *
67
+ * There is no upstream string to copy here: `SqlStorageRegulator::onError` just
68
+ * rethrows whatever SQLite produced, and SQLite produces `not authorized` for an
69
+ * authorizer denial (`access to X.Y is prohibited` for the column-read case,
70
+ * which needs a resolved identifier we do not have). The prefix is kept so that
71
+ * anything matching upstream still matches; the rest is here because a bare
72
+ * `not authorized` is not debuggable.
73
+ */
74
+ export declare const SQL_RESERVED_PREFIX_MESSAGE: string;
75
+ /**
76
+ * ← `SqlStorageRegulator` (`sql.h:15-22`, `sql.c++:143-173`), whole.
77
+ *
78
+ * Upstream reaches these through the SQLite authorizer while a statement is
79
+ * being compiled. `exec` calls them from the statement text instead, which is
80
+ * the same translation Section 3 made for the write classifier and for
81
+ * transaction state.
82
+ */
83
+ export declare const SqlStorageRegulator: {
84
+ /**
85
+ * Upstream's body is `return !name.startsWith("_cf_")`, with an autogate that
86
+ * makes the comparison case-insensitive and logs a warning until it lands. The
87
+ * case-insensitive form is taken here: it is the direction upstream is moving,
88
+ * and there is no logger for the warning half.
89
+ */
90
+ isAllowedName(name: string): boolean;
91
+ /** Upstream's body is `return true`. */
92
+ isAllowedTrigger(_name: string): boolean;
93
+ /** Upstream's body is a `JSG_FAIL_REQUIRE` with this message. */
94
+ allowTransactions(): never;
95
+ /** "Bill for queries executed from JavaScript." Nothing reads it — `SqliteObserver` has no port. */
96
+ shouldAddQueryStats(): boolean;
97
+ };
98
+ /**
99
+ * ← the `jsg::Ref<DurableObjectStorage>` `SqlStorage` holds, narrowed to the one
100
+ * member it reaches through (`SqlStorage::getDb`). `DurableObjectStorage`
101
+ * satisfies it; narrowing is what keeps this file free of a value-level import
102
+ * cycle, which upstream tolerates because C++ headers do not have one.
103
+ */
104
+ export interface SqlStorageOwner {
105
+ /** ← `DurableObjectStorage::getSqliteDb`. Throws if not SQLite-backed. */
106
+ getSqliteDb(): SqliteDatabase;
107
+ }
108
+ /** The rows a cursor walks, plus the counters that outlive them. */
109
+ type CursorState = {
110
+ readonly columnNames: string[];
111
+ readonly rawRows: readonly (readonly SqlStorageValue[])[];
112
+ readonly rowsWritten: number;
113
+ };
114
+ /**
115
+ * ← `SqlStorage::Cursor`.
116
+ *
117
+ * `rowsRead` is the one counter that is not upstream's. Upstream reads
118
+ * `Query::getRowsRead()`, a billing counter sourced from libsql's
119
+ * `STMTSTATUS_ROWS_READ` that counts index rows and that neither backend
120
+ * exposes — the same absence the README already records for `SqlResult`. The
121
+ * interface requires a number, so this returns the rows the cursor has yielded,
122
+ * which is what today's browser host returns and what its tests assert. It
123
+ * undercounts any query that scans more rows than it returns.
124
+ */
125
+ export declare class Cursor<T extends SqlRow = SqlRow> implements SqlStorageCursor<T> {
126
+ #private;
127
+ readonly columnNames: string[];
128
+ constructor(state?: CursorState);
129
+ /** ← `Cursor::next`, whose `RowIterator::Next` is this exact shape. */
130
+ next(): {
131
+ done?: false;
132
+ value: T;
133
+ } | {
134
+ done: true;
135
+ value?: never;
136
+ };
137
+ /** ← `Cursor::toArray`, which drains from the current position. */
138
+ toArray(): T[];
139
+ /** ← `Cursor::one`. Both messages are upstream's, verbatim. */
140
+ one(): T;
141
+ /** ← `Cursor::raw`, which shares this cursor's position rather than restarting. */
142
+ raw<U extends SqlStorageValue[]>(): IterableIterator<U>;
143
+ /** ← `JSG_ITERABLE(rows)`. */
144
+ [Symbol.iterator](): IterableIterator<T>;
145
+ get rowsRead(): number;
146
+ /** ← `Cursor::getRowsWritten`, which is `SqlResult.rowsWritten` here. */
147
+ get rowsWritten(): number;
148
+ }
149
+ /**
150
+ * ← `SqlStorage::Statement`, which upstream describes as "supported only for
151
+ * backwards compatibility ... it is actually just a wrapper around `exec()`".
152
+ * `JSG_CALLABLE(run)` makes the object itself callable, so `prepare()` returns a
153
+ * function wearing this prototype rather than an object with a `run` method.
154
+ */
155
+ export declare class Statement {
156
+ constructor();
157
+ }
158
+ /** What `prepare()` hands back: `Statement::run`, reachable by calling it. */
159
+ export interface PreparedStatement {
160
+ <T extends SqlRow = SqlRow>(...bindings: BindingValue[]): Cursor<T>;
161
+ }
162
+ export declare class SqlStorage implements globalThis.SqlStorage {
163
+ #private;
164
+ constructor(ctx: IoContext, owner: SqlStorageOwner);
165
+ /** ← `JSG_NESTED_TYPE(Cursor)`. Exposed so `instanceof` works, as upstream's is. */
166
+ readonly Cursor: typeof Cursor;
167
+ /** ← `JSG_NESTED_TYPE(Statement)`. */
168
+ readonly Statement: typeof Statement;
169
+ exec<T extends SqlRow = SqlRow>(query: string, ...bindings: BindingValue[]): Cursor<T>;
170
+ /**
171
+ * ← `SqlStorage::getDatabaseSize`.
172
+ *
173
+ * Upstream's second query is `PRAGMA page_size;`, which `sqlite3_stmt_readonly()`
174
+ * reports read-only. With no such call the text is the only source and §1.7.1's
175
+ * rule is write-unless-provably-a-read, so a bare `PRAGMA` would open a
176
+ * transaction and take an output-gate lock to answer a size question. The
177
+ * `pragma_page_size` table-valued function is the same value read through the
178
+ * `SELECT` upstream already uses for the page count.
179
+ */
180
+ get databaseSize(): number;
181
+ /** ← `SqlStorage::prepare`. Experimental and deprecated upstream; `exec` caches for you. */
182
+ prepare(query: string): PreparedStatement;
183
+ /** ← `SqlStorage::ingest`. */
184
+ ingest(query: string): SqlStorageIngestResult;
185
+ /** ← `SqlStorage::setMaxPageCountForTest`, which is what its name says. */
186
+ setMaxPageCountForTest(count: number): void;
187
+ }
188
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * ← workerd `src/workerd/api/sync-kv.{h,c++}`
3
+ *
4
+ * "Synchronous KV storage. Available as ctx.storage.kv on SQLite-backed DOs."
5
+ *
6
+ * This module is not in Section 5's brief and exists because
7
+ * `DurableObjectStorage` cannot satisfy workers-types without it: the interface
8
+ * declares `kv: SyncKvStorage` unconditionally, and §2.4's rule is that the
9
+ * surface is verified by the type system rather than by a cast. It is also a
10
+ * genuine part of the contract — a whole KV surface that skips the promise
11
+ * wrapper, over the same `SqliteKv` `DurableObjectStorage` writes through, with
12
+ * the same codec.
13
+ *
14
+ * Two things upstream has that are absent, both already absent below this file:
15
+ * the trace spans every method opens, and the billing counters. What is kept is
16
+ * the whole of the behaviour, including the one error that is neither of those:
17
+ * a `list()` iterator invalidated by a second `list()` says so rather than
18
+ * silently ending, which is `SqliteKv::ListCursor::wasCanceled()`.
19
+ *
20
+ * Spec: §2.4 in docs/decisions.md.
21
+ */
22
+ import type { IoContext } from "../io/io-context.js";
23
+ import type { SqliteKv } from "../util/sqlite-kv.js";
24
+ /**
25
+ * ← the `jsg::Ref<DurableObjectStorage>` `SyncKvStorage` holds, narrowed to the
26
+ * one member it reaches through (`SyncKvStorage::getSqliteKv`).
27
+ */
28
+ export interface SyncKvStorageOwner {
29
+ getSqliteKv(): SqliteKv;
30
+ }
31
+ /** ← `SyncKvStorage::ListOptions`, which is `ListOptions` minus the two gate flags. */
32
+ export type SyncKvListOptions = {
33
+ start?: string;
34
+ startAfter?: string;
35
+ end?: string;
36
+ prefix?: string;
37
+ reverse?: boolean;
38
+ limit?: number;
39
+ };
40
+ export declare class SyncKvStorage implements globalThis.SyncKvStorage {
41
+ #private;
42
+ constructor(ctx: IoContext, owner: SyncKvStorageOwner);
43
+ get<T = unknown>(key: string): T | undefined;
44
+ /**
45
+ * ← `SyncKvStorage::list`, which reuses `compileListOptions` — "This is public
46
+ * so that SyncKvStorage can reuse it."
47
+ */
48
+ list<T = unknown>(options?: SyncKvListOptions): Iterable<[string, T]>;
49
+ put<T>(key: string, value: T): void;
50
+ delete(key: string): boolean;
51
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * ← workerd `src/workerd/api/web-socket.{h,c++}` — the gating, and nothing else.
3
+ *
4
+ * A socket is the one primitive that is neither of the other two, and §1.8 says
5
+ * why in three lines: incoming frames "each take a fresh input lock via
6
+ * `context.run(...)`", the read loop "captures the critical section at
7
+ * `accept()` time", and outbound messages "each carry their own output-gate
8
+ * promise captured at `send()` time". Upstream states the first outright, on the
9
+ * line that does it (`web-socket.c++:1056-1059`):
10
+ *
11
+ * > "Re-enter the context with context.run(). This is arguably a bit unusual
12
+ * > compared to other I/O which is delivered by return from context.awaitIo(),
13
+ * > but the difference here is that we have a long stream of events over time.
14
+ * > It makes sense to use context.run() each time a new event arrives."
15
+ *
16
+ * So a socket cannot be `awaitIo`: there is no single result to resume from.
17
+ * `accept()` starts a loop, and the loop is the gate's caller.
18
+ *
19
+ * **What is ported and what is not.** The frame protocol, the hibernation
20
+ * states, auto-response, `WebSocketPair` and the byte accounting are all
21
+ * absent — the substrate ships a `WebSocket`, and hibernation is a recorded
22
+ * substrate boundary with no Chrome lifecycle to be faithful to. What is here is
23
+ * `WebSocket::Accepted`: the three gate properties above, over whatever socket
24
+ * the host hands in. That is the same division `api/http.ts` makes and for the
25
+ * same reason.
26
+ *
27
+ * **The accept contract, and the hole it leaves.** After `acceptWebSocket`, the
28
+ * gated view owns the raw socket's events. A consumer that keeps a reference to
29
+ * the raw socket and registers a listener on it directly gets that listener
30
+ * called ungated, and nothing here can prevent it — upstream cannot be reached
31
+ * that way because `accept()` moves the `kj::WebSocket` into `Accepted` and the
32
+ * JS object never had it. The refusal below covers the case that is detectable
33
+ * (accepting the same socket twice); the rest is the accept contract, stated.
34
+ *
35
+ * Spec: §1.1, §1.8 and decision 5 in
36
+ * docs/decisions.md.
37
+ */
38
+ import type { IoContext } from "../io/io-context.js";
39
+ /**
40
+ * The socket beneath. Deliberately structural and minimal: a real `WebSocket`,
41
+ * the extension's `WebSocketFacade` over capnweb, and a test double all satisfy
42
+ * it, and none of them is a type this package should name.
43
+ */
44
+ export interface RawWebSocket {
45
+ addEventListener(type: string, listener: (event: Event) => void): void;
46
+ send(data: string | ArrayBufferLike | ArrayBufferView | Blob): void;
47
+ close(code?: number, reason?: string): void;
48
+ }
49
+ /** ← the `JSG_REQUIRE(!native.state.is<Accepted>(), ...)` at the head of `accept()`. */
50
+ export declare const ALREADY_ACCEPTED_MESSAGE: string;
51
+ /**
52
+ * ← `WebSocket::Accepted` (`web-socket.h:~300-360`), reached through
53
+ * `accept()` → `internalAccept(js, IoContext::current().getCriticalSection())`
54
+ * → `startReadLoop` (`web-socket.c++:133`, `:426`, `:429-433`, `:507`).
55
+ *
56
+ * An `EventTarget`, so a consumer registers listeners the way it would on a real
57
+ * socket — but on THIS object rather than on the raw one, because this is what
58
+ * runs them inside a gated slice.
59
+ */
60
+ export declare class AcceptedWebSocket extends EventTarget {
61
+ #private;
62
+ onopen: ((event: Event) => void) | null;
63
+ onmessage: ((event: MessageEvent) => void) | null;
64
+ onclose: ((event: CloseEvent) => void) | null;
65
+ onerror: ((event: Event) => void) | null;
66
+ constructor(ctx: IoContext, socket: RawWebSocket);
67
+ /**
68
+ * ← `WebSocket::send` (`web-socket.c++:~640`), which inserts a
69
+ * `GatedMessage{IoContext::current().waitForOutputLocksIfNecessary(), …}`.
70
+ *
71
+ * Synchronous, as upstream's is: the wait is the pump's, not the caller's. The
72
+ * output gate is what "blocks all outgoing messages from an actor that would
73
+ * allow the rest of the world to observe the actor's state" (§1.1), and a
74
+ * socket frame is exactly such a message.
75
+ *
76
+ * `waitForOutputLocksIfNecessary()` collapses to `waitForOutputLocks()` here
77
+ * for the reason the whole file collapses `kj::Maybe<Worker::Actor&>`: its
78
+ * body is `actor.map(…)` (`io-context.c++:383-386`) and every context in this
79
+ * runtime is an actor context.
80
+ */
81
+ send(data: string | ArrayBufferLike | ArrayBufferView | Blob): void;
82
+ /** ← `WebSocket::close`, which enqueues a `Close` through the same gate. */
83
+ close(code?: number, reason?: string): void;
84
+ }
85
+ /**
86
+ * ← `accept()` / `state.acceptWebSocket()`, as the one verb.
87
+ *
88
+ * Named for what upstream names it, because the critical-section capture is a
89
+ * property of accepting rather than of constructing: "a socket accepted inside a
90
+ * `blockConcurrencyWhile` delivers its messages inside that critical section"
91
+ * (§1.8).
92
+ */
93
+ export declare function acceptWebSocket(ctx: IoContext, socket: RawWebSocket): AcceptedWebSocket;