@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.
- package/CHANGELOG.md +14 -0
- package/LICENSE +110 -0
- package/LICENSE.workerd +176 -0
- package/NOTICE +7 -0
- package/README.md +282 -0
- package/dist/backends/node-sqlite.d.ts +38 -0
- package/dist/backends/node-sqlite.js +335 -0
- package/dist/backends/node-sqlite.js.map +1 -0
- package/dist/backends/sqlite-wasm.d.ts +130 -0
- package/dist/backends/sqlite-wasm.js +259 -0
- package/dist/backends/sqlite-wasm.js.map +1 -0
- package/dist/chunks/sqlite-DFg92Tgt.js +498 -0
- package/dist/chunks/sqlite-DFg92Tgt.js.map +1 -0
- package/dist/cloudflare-workers.js +351 -0
- package/dist/cloudflare-workers.js.map +1 -0
- package/dist/conformance/host.d.ts +58 -0
- package/dist/conformance.js +18 -0
- package/dist/conformance.js.map +1 -0
- package/dist/index.js +7184 -0
- package/dist/index.js.map +1 -0
- package/dist/server/alarm-scheduler.js +513 -0
- package/dist/server/alarm-scheduler.js.map +1 -0
- package/dist/src/api/actor-state.d.ts +396 -0
- package/dist/src/api/actor.d.ts +306 -0
- package/dist/src/api/cloudflare-workers.d.ts +259 -0
- package/dist/src/api/export-loopback.d.ts +264 -0
- package/dist/src/api/global-scope.d.ts +262 -0
- package/dist/src/api/http.d.ts +52 -0
- package/dist/src/api/sql.d.ts +188 -0
- package/dist/src/api/sync-kv.d.ts +51 -0
- package/dist/src/api/web-socket.d.ts +93 -0
- package/dist/src/api/worker-loader.d.ts +354 -0
- package/dist/src/index.d.ts +130 -0
- package/dist/src/io/actor-cache.d.ts +203 -0
- package/dist/src/io/actor-id.d.ts +74 -0
- package/dist/src/io/actor-sqlite.d.ts +298 -0
- package/dist/src/io/io-channels.d.ts +191 -0
- package/dist/src/io/io-context.d.ts +451 -0
- package/dist/src/io/io-gate.d.ts +298 -0
- package/dist/src/io/worker-source.d.ts +108 -0
- package/dist/src/io/worker.d.ts +88 -0
- package/dist/src/server/actor-container.d.ts +525 -0
- package/dist/src/server/actor-id-impl.d.ts +118 -0
- package/dist/src/server/alarm-scheduler.d.ts +201 -0
- package/dist/src/server/facet-deletion.d.ts +156 -0
- package/dist/src/server/facet-tree-index.d.ts +94 -0
- package/dist/src/server/sha256.d.ts +39 -0
- package/dist/src/transport/rpc-session.d.ts +34 -0
- package/dist/src/util/sqlite-kv.d.ts +98 -0
- package/dist/src/util/sqlite-metadata.d.ts +46 -0
- package/dist/src/util/sqlite.d.ts +291 -0
- package/package.json +111 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ← workerd `src/workerd/server/server.c++` — `ActorNamespace::ActorContainer`
|
|
3
|
+
* (`:2383-2968`), which is at once the supervisor's per-actor record, its
|
|
4
|
+
* `Worker::Actor::FacetManager`, and the code that builds the storage engine.
|
|
5
|
+
*
|
|
6
|
+
* Composes the gates, the context, the storage engine and the facet tree into
|
|
7
|
+
* one actor. Constructs the Durable Object class under workerd's boot
|
|
8
|
+
* semantics, and on break aborts facets, abandons scheduled writes, refuses
|
|
9
|
+
* re-entry, and surfaces `onBroken`.
|
|
10
|
+
*
|
|
11
|
+
* **The three line ranges this file was handed are all in the wrong class, and
|
|
12
|
+
* the right ones are above.** `server.c++:1199-1214`, `:1225-1237` and
|
|
13
|
+
* `:1293-1297` are all inside `Server::DiskDirectoryService` (`:1058`) — the
|
|
14
|
+
* directory-listing branch of a static-file handler, its entry-type switch, and
|
|
15
|
+
* a `sendError(501, "Not Implemented")`. None of them has anything to do with
|
|
16
|
+
* actors. The three things they were offered for are real, and are at
|
|
17
|
+
* `:2864-2877` (alarm hooks installed only `if (parent == kj::none)`, with
|
|
18
|
+
* `// TODO(someday): Support alarms in facets, somehow.`), `:2885-2897`
|
|
19
|
+
* (`afterReset`, where `deleteAll()`'s cascade to descendant facet storage
|
|
20
|
+
* lives) and `:2603-2620` / `:2953-2956` (`getFacetContainer` and
|
|
21
|
+
* `actorClass->newActor`, the two halves of facet actor construction). Every
|
|
22
|
+
* citation in this file was checked line by line against
|
|
23
|
+
* `e8f1e125bd48f048a3e82c48d37e5e3902fffbd6`, which is the tree Section 6a's
|
|
24
|
+
* citations were taken from and agree with.
|
|
25
|
+
*
|
|
26
|
+
* **Ordering, because it is the part that cannot be read off upstream.**
|
|
27
|
+
* Upstream builds the actor lazily inside `getActor()`, so `ctx.storage` does
|
|
28
|
+
* not exist until the first request arrives and nothing can observe the gap.
|
|
29
|
+
* Here `ActorContainer.state` is a plain property that promises a
|
|
30
|
+
* `DurableObjectState` answering `.storage`, and the database behind it opens
|
|
31
|
+
* asynchronously (`SqlDatabaseProvider.open`, Section 3's seam). Something has to
|
|
32
|
+
* give, and the honest one is the factory: `createActorContainer` returns a
|
|
33
|
+
* promise, and everything it returns is fully built. The alternative — a `state`
|
|
34
|
+
* property that throws until `start()` — is a worse lie, because it makes the
|
|
35
|
+
* one declared field of the public interface conditional on a call the type
|
|
36
|
+
* system cannot see.
|
|
37
|
+
*
|
|
38
|
+
* Spec: §1.6, §1.10, decisions 6 and 14 in
|
|
39
|
+
* docs/decisions.md.
|
|
40
|
+
*/
|
|
41
|
+
import { DurableObjectState } from "../api/actor-state.js";
|
|
42
|
+
import type { FetchPort } from "../api/global-scope.js";
|
|
43
|
+
import { ActorGlobalScope } from "../api/global-scope.js";
|
|
44
|
+
import type { AcceptedWebSocket, RawWebSocket } from "../api/web-socket.js";
|
|
45
|
+
import type { IsolateChannelFactory, WorkerLoaderOptions } from "../api/worker-loader.js";
|
|
46
|
+
import { WorkerLoader } from "../api/worker-loader.js";
|
|
47
|
+
import type { AlarmOutlet } from "../io/actor-sqlite.js";
|
|
48
|
+
import type { AlarmResult } from "./alarm-scheduler.js";
|
|
49
|
+
import type { Timer } from "../io/io-context.js";
|
|
50
|
+
import type { SqlDatabase, SqlDatabaseProvider } from "../util/sqlite.js";
|
|
51
|
+
import type { IndexFile } from "./facet-tree-index.js";
|
|
52
|
+
import { FacetReferenceEpochs } from "./facet-deletion.js";
|
|
53
|
+
export type FacetId = number;
|
|
54
|
+
export type FacetStartRequest = {
|
|
55
|
+
id: FacetId;
|
|
56
|
+
/** The `facets.get` name, `class\0name` form preserved. */
|
|
57
|
+
name: string;
|
|
58
|
+
/** Resolved against `ctx.exports` by `api/actor-state.ts`. */
|
|
59
|
+
className: string;
|
|
60
|
+
/** This facet's depth. The container enforces <= 4 including the root. */
|
|
61
|
+
depth: number;
|
|
62
|
+
/**
|
|
63
|
+
* The `ctx.id` the child was told to take, present only when the startup
|
|
64
|
+
* options supplied one. Absent means the child inherits the parent's, which
|
|
65
|
+
* is upstream's `ioCtx.getActorOrThrow().cloneId()` (`actor-state.c++:1026`).
|
|
66
|
+
*
|
|
67
|
+
* The scaffolding called this "the DurableObjectId name". It is not
|
|
68
|
+
* necessarily a name: `FacetStartupOptions.id` is `DurableObjectId | string`
|
|
69
|
+
* (`actor-state.h:453`), so this carries a 64-hex id string whenever the app
|
|
70
|
+
* passed a `DurableObjectId`, and whatever the app chose whenever it passed a
|
|
71
|
+
* string. The host decides what to do with it, exactly as upstream's
|
|
72
|
+
* `Worker::Actor::Id` leaves that to the supervisor.
|
|
73
|
+
*/
|
|
74
|
+
routedId?: string;
|
|
75
|
+
};
|
|
76
|
+
export interface FacetHandle {
|
|
77
|
+
/**
|
|
78
|
+
* The placement's outcome, resolving to what `facets.get` will call —
|
|
79
|
+
* Fetcher-shaped per §1.10: no id, no name.
|
|
80
|
+
*
|
|
81
|
+
* `start` is synchronous because `facets.get` is, but placing an actor is not: a database
|
|
82
|
+
* has to open and a constructor has to run. Upstream has exactly this shape and
|
|
83
|
+
* does not have to say so — `getFacetContainer` hands `ActorChannelImpl` a
|
|
84
|
+
* `kj::Promise<ClassAndId>` (`server.c++:2603-2620`) and the channel is
|
|
85
|
+
* returned before it resolves, so a failure to construct reaches the caller at
|
|
86
|
+
* the first call on the stub. Measured on workerd 1.20260722.1: a facet whose
|
|
87
|
+
* constructor throws returns a stub from `facets.get()`, rejects the first call
|
|
88
|
+
* with the constructor's own message, and leaves the parent untouched.
|
|
89
|
+
*
|
|
90
|
+
* Keeping the placement promise here makes construction failures observable at
|
|
91
|
+
* the first call and leaves `asFacetTransport` as the sole deferral layer.
|
|
92
|
+
*/
|
|
93
|
+
stub: Promise<object>;
|
|
94
|
+
/**
|
|
95
|
+
* Rejects when a RUNNING facet breaks — the signal upstream gets from
|
|
96
|
+
* `actor.onBroken()` and monitors in `monitorOnBroken`
|
|
97
|
+
* (`server.c++:2767-2800`).
|
|
98
|
+
*
|
|
99
|
+
* **A break travels DOWN and never up, so nothing here reaches the parent.**
|
|
100
|
+
* `ActorContainer::abort` (`:2565-2589`) and `monitorOnBroken` each loop
|
|
101
|
+
* `for (auto& facet: facets)` and abort the container's OWN children; a broken
|
|
102
|
+
* child takes itself and its subtree, and nothing above it notices.
|
|
103
|
+
* `conformance/suite/facets.spec.ts` guards this against workerd: the parent and
|
|
104
|
+
* its other facets remain live.
|
|
105
|
+
*
|
|
106
|
+
* `FacetManagerImpl` consumes this signal for `monitorOnBroken`'s two local
|
|
107
|
+
* effects: tell the host to tear down the broken placement (which aborts its
|
|
108
|
+
* descendants), and erase it from the PARENT's facet map (`:2777-2780`,
|
|
109
|
+
* `:2794-2798`). That frees the name for a fresh placement without changing
|
|
110
|
+
* the parent or its siblings.
|
|
111
|
+
*
|
|
112
|
+
* **A placement that never completed does not belong here** — it is a start
|
|
113
|
+
* that failed, not a break, and it travels through `stub`. Measured on
|
|
114
|
+
* workerd: a facet whose construction fails does not break its parent, and the
|
|
115
|
+
* next `facets.get` runs the startup callback again.
|
|
116
|
+
*/
|
|
117
|
+
broken: Promise<never>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The facet port. Substrate is only placement, the callable stub across that
|
|
121
|
+
* placement, and physical storage deletion for children a parent cannot open.
|
|
122
|
+
*
|
|
123
|
+
* NOT substrate, and therefore not in this interface: naming, ids, the
|
|
124
|
+
* depth/name/count limits, deletion receipts and epochs, and `clone()`
|
|
125
|
+
* orchestration. Those are package-owned. In particular there is no
|
|
126
|
+
* addressing-strategy port: once
|
|
127
|
+
* the package speaks facet ids, the app-address mapping is the browser
|
|
128
|
+
* adapter's private business and needs no interface at all.
|
|
129
|
+
*
|
|
130
|
+
* This is NOT the interface `api/actor-state.ts` consumes. That one is
|
|
131
|
+
* `io/worker.ts`'s `FacetManager`, upstream's own `Worker::Actor::FacetManager`,
|
|
132
|
+
* which this file implements on top of this port — see that file's header for
|
|
133
|
+
* why the two were conflated and why the fix was to widen rather than reshuffle.
|
|
134
|
+
* The `clone()` orchestration named above is `cloneFacet`'s body, and the
|
|
135
|
+
* limits named above are enforced by `DurableObjectFacets` where upstream
|
|
136
|
+
* enforces them.
|
|
137
|
+
*
|
|
138
|
+
* One host serves a whole actor tree, as upstream's `ActorNamespace` does: every
|
|
139
|
+
* `FacetId` it is handed is an id in the root's index, so a facet's own host
|
|
140
|
+
* must be able to place and remove any of its descendants.
|
|
141
|
+
*/
|
|
142
|
+
export interface FacetHost {
|
|
143
|
+
/**
|
|
144
|
+
* Synchronous, like `facets.get` itself — but the placement it begins is not,
|
|
145
|
+
* and `FacetHandle.stub` is where that is declared. A host reports a placement
|
|
146
|
+
* it could not finish by rejecting that promise, and reports nothing about it
|
|
147
|
+
* on `broken`: see `FacetHandle`.
|
|
148
|
+
*
|
|
149
|
+
* A synchronous throw is still legal and still means the same thing — the
|
|
150
|
+
* facet cannot be started — and `getFacet` turns it into the same rejected
|
|
151
|
+
* stub. What is no longer possible is a host that fails asynchronously and has
|
|
152
|
+
* nowhere to say so.
|
|
153
|
+
*/
|
|
154
|
+
start(request: FacetStartRequest): FacetHandle;
|
|
155
|
+
/**
|
|
156
|
+
* Kills the instance; storage survives (measured on workerd).
|
|
157
|
+
*
|
|
158
|
+
* **Never called while a placement for `id` is in flight**, and never before
|
|
159
|
+
* that placement's `stub` has settled. The container orders the two against
|
|
160
|
+
* each other, so a host needs no queue of its own and is never handed an abort
|
|
161
|
+
* for a facet it is still placing — which it could only no-op, its placement
|
|
162
|
+
* map having no entry for the id yet.
|
|
163
|
+
*
|
|
164
|
+
* It may still be called for an id that never ran: a placement that failed, or
|
|
165
|
+
* one refused before `start` was reached. Upstream's is too — `abortFacet`
|
|
166
|
+
* finds the container whether or not its `kj::Promise<ClassAndId>` ever
|
|
167
|
+
* resolved (`server.c++:2635-2640`) — so a host that has nothing to kill
|
|
168
|
+
* should return, not throw.
|
|
169
|
+
*/
|
|
170
|
+
abort(id: FacetId, reason?: string): void;
|
|
171
|
+
/**
|
|
172
|
+
* Physical removal, descendants included. `subtree` is the descendants alone,
|
|
173
|
+
* deepest first — upstream removes children before the parent
|
|
174
|
+
* (`server.c++:2754-2759`) — and `id` is the facet itself.
|
|
175
|
+
*/
|
|
176
|
+
deleteStorage(id: FacetId, subtree: readonly FacetId[]): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Physical copy of one facet's storage onto another, for `cloneFacet`. The
|
|
179
|
+
* recursive walk of the source subtree is this file's; copying one database
|
|
180
|
+
* is the substrate's, the same split `deleteStorage` already makes.
|
|
181
|
+
*/
|
|
182
|
+
copyStorage(src: FacetId, dst: FacetId): Promise<void>;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The `FacetHost` for a host that places no facets — the shape of every first
|
|
186
|
+
* integration, provided so hosts stop re-typing it. `start` refuses by name.
|
|
187
|
+
* `abort` returns, per its contract above: a host with nothing to kill returns.
|
|
188
|
+
* The storage operations refuse, because a call to either proves a facet once
|
|
189
|
+
* existed — which this host could not have placed.
|
|
190
|
+
*/
|
|
191
|
+
export declare const noFacets: FacetHost;
|
|
192
|
+
/**
|
|
193
|
+
* The four ports. Each one is a seam workerd itself takes as a constructor
|
|
194
|
+
* input; a port that would exist only because our code is currently shaped
|
|
195
|
+
* badly is an invented seam and was rejected. Rejected, for the record:
|
|
196
|
+
* a transport port (one implementation per substrate, forever), a logger port
|
|
197
|
+
* (fail closed — errors throw, breakage surfaces on `onBroken`), a value-codec
|
|
198
|
+
* port (giving lanes different codecs would make the Node lane lie about the
|
|
199
|
+
* browser), and an addressing-strategy port (unnecessary once the package
|
|
200
|
+
* speaks facet ids).
|
|
201
|
+
*
|
|
202
|
+
* A fifth, `isolates?: IsolateHost`, was here from the scaffolding and Section 7b
|
|
203
|
+
* removed it. A Worker Loader is a **binding**, not a port: upstream builds it
|
|
204
|
+
* from `Global::WorkerLoader{channel}` alongside every other binding
|
|
205
|
+
* (`server/workerd-api.c++:748`) and it reaches an application through `env`,
|
|
206
|
+
* exactly as `DurableObjectNamespace` and `ctx.exports` already do here. A host
|
|
207
|
+
* constructs `WorkerLoader` over its own `IsolateChannelFactory` and puts it in
|
|
208
|
+
* `env`; the container never sees one. See `api/worker-loader.ts`'s header.
|
|
209
|
+
*/
|
|
210
|
+
export type ActorPorts = {
|
|
211
|
+
sql: SqlDatabaseProvider;
|
|
212
|
+
/**
|
|
213
|
+
* Root containers only — facets have no alarm slot (§1.10).
|
|
214
|
+
*
|
|
215
|
+
* `AlarmScheduler.hooks(actorId)` is the implementation to put here: upstream
|
|
216
|
+
* builds one `AlarmScheduler` per namespace and gives each actor a
|
|
217
|
+
* three-line `ActorSqliteHooks` adapter over it (`server.c++:2325-2350`,
|
|
218
|
+
* `:3199-3219`), which is the same composition.
|
|
219
|
+
*/
|
|
220
|
+
alarms: AlarmOutlet;
|
|
221
|
+
facets: FacetHost;
|
|
222
|
+
timer: Timer;
|
|
223
|
+
/**
|
|
224
|
+
* ← the global outbound `Fetcher` a Worker's `fetch` resolves
|
|
225
|
+
* (`api/global-scope.c++:1160`), which `container.globals.fetch` gates.
|
|
226
|
+
*
|
|
227
|
+
* Optional, and absence is upstream's `globalOutbound: null` posture rather
|
|
228
|
+
* than a missing port: a Worker configured that way has no ambient `fetch` at
|
|
229
|
+
* all, which is how Code Mode forces every I/O through connectors (§1.11).
|
|
230
|
+
* `fetch` then refuses by name instead of reaching a `fetch` this package does
|
|
231
|
+
* not own — an ungated one that works is the failure this layer exists to
|
|
232
|
+
* prevent.
|
|
233
|
+
*/
|
|
234
|
+
fetch?: FetchPort;
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* The whole-tree facet state, which belongs to the root container and is shared
|
|
238
|
+
* by every container in one actor tree.
|
|
239
|
+
*
|
|
240
|
+
* Upstream keeps the same thing in the same place — "FacetTreeIndex for this
|
|
241
|
+
* actor. Only initialized on the root" (`server.c++:2680-2681`), reached from a
|
|
242
|
+
* facet by `root.ensureFacetTreeIndex()` (`:2697`) — and can do so with a plain
|
|
243
|
+
* reference because every facet of an actor is an object in one process. None of
|
|
244
|
+
* these methods can cross a worker boundary: `facets.get()` is synchronous all
|
|
245
|
+
* the way down, so `getId` has to answer without yielding. A facet in another
|
|
246
|
+
* worker cannot be handed this object and therefore cannot have facets of its
|
|
247
|
+
* own. Every host here
|
|
248
|
+
* now places in the parent's realm and passes the root's object straight through.
|
|
249
|
+
*
|
|
250
|
+
* It is an interface rather than a plain reference anyway, because a facet
|
|
251
|
+
* container is constructed on its own and the root's index is the one piece of
|
|
252
|
+
* state it cannot build for itself: ids are sequential across the whole tree. A
|
|
253
|
+
* host that does not supply one gets a facet that cannot have facets of its own
|
|
254
|
+
* and says so, rather than a per-parent counter that would collide the storage.
|
|
255
|
+
*/
|
|
256
|
+
export interface FacetTree {
|
|
257
|
+
/** ← `FacetTreeIndex::getId`. Assigns on first sight, stable thereafter. */
|
|
258
|
+
getId(parent: FacetId, name: string): FacetId;
|
|
259
|
+
/** ← `FacetTreeIndex::forEachChild`, collected. Ordered by the child's UTF-8 name. */
|
|
260
|
+
children(parent: FacetId): readonly {
|
|
261
|
+
readonly id: FacetId;
|
|
262
|
+
readonly name: string;
|
|
263
|
+
}[];
|
|
264
|
+
/** ← `deleteDescendantStorage`'s recursion, as a list: descendants only, deepest first. */
|
|
265
|
+
descendants(id: FacetId): FacetId[];
|
|
266
|
+
/**
|
|
267
|
+
* Records the intent durably now, then removes `id` and its descendants after
|
|
268
|
+
* the current parent and descendant operations represented by `waitBeforeDelete`.
|
|
269
|
+
*/
|
|
270
|
+
deleteSubtree(id: FacetId, waitBeforeDelete: Promise<unknown>): Promise<void>;
|
|
271
|
+
/** Copies the whole `src` subtree onto `dst`, minting `dst`'s children as it goes. */
|
|
272
|
+
copySubtree(src: FacetId, dst: FacetId): Promise<void>;
|
|
273
|
+
/** Runs one placement or abort after every earlier operation on the same stable facet id. */
|
|
274
|
+
runOperation(id: FacetId, operation: () => Promise<void>): void;
|
|
275
|
+
/** Snapshots the current operation tail for `id` and every indexed descendant. */
|
|
276
|
+
subtreeOperationBarrier(id: FacetId): Promise<void>;
|
|
277
|
+
/**
|
|
278
|
+
* Resolves once no queued deletion still covers `id`, which is what makes a
|
|
279
|
+
* facet re-created under a name that is still being deleted safe to start.
|
|
280
|
+
*/
|
|
281
|
+
settled(id: FacetId): Promise<void>;
|
|
282
|
+
/** Every capability captured before an ancestor abort or delete goes stale here. */
|
|
283
|
+
readonly epochs: FacetReferenceEpochs;
|
|
284
|
+
/** ← boot. Carries out every deletion a previous session recorded and did not finish. */
|
|
285
|
+
recoverDeletions(): Promise<void>;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* ← `IoContext::awaitIo`, as the one primitive a host needs in order to build a
|
|
289
|
+
* platform async primitive of its own.
|
|
290
|
+
*/
|
|
291
|
+
export type ActorContainerOptions = {
|
|
292
|
+
/** The DurableObjectId name. */
|
|
293
|
+
id: string;
|
|
294
|
+
/**
|
|
295
|
+
* The namespace's unique key, upstream's `uniqueKey` configuration field
|
|
296
|
+
* (`server.c++:2919`, read from `config::Worker::DurableObjectNamespace::Durable`).
|
|
297
|
+
* `ActorIdFactoryImpl` derives its factory key as `SHA256(uniqueKey)` and an
|
|
298
|
+
* id as 16 bytes of base plus 16 bytes of `HMAC-SHA256(key, base)`.
|
|
299
|
+
*
|
|
300
|
+
* **The host must keep this stable forever.** `ctx.id` is
|
|
301
|
+
* `idFromName(options.id)` under this key, and the id names the actor's
|
|
302
|
+
* storage, so a key that changes across a restart changes every id and every
|
|
303
|
+
* actor loses its data. There is no default and it is not optional, because a
|
|
304
|
+
* default is exactly the shape that would let a host acquire this obligation
|
|
305
|
+
* without noticing it. This package cannot check the property for itself —
|
|
306
|
+
* nothing it can observe distinguishes "a new key" from "a new actor" — so
|
|
307
|
+
* this comment is the whole of the enforcement.
|
|
308
|
+
*/
|
|
309
|
+
uniqueKey: string;
|
|
310
|
+
/** The `ctx.exports` class registry. Keys are the consumer's concern. */
|
|
311
|
+
exports: Record<string, unknown>;
|
|
312
|
+
env: unknown;
|
|
313
|
+
ports: ActorPorts;
|
|
314
|
+
/** Present when this container hosts a facet rather than a root. */
|
|
315
|
+
facet?: {
|
|
316
|
+
/** Root is 0, a direct child of the root is 1. `getDepth()` answers with it. */
|
|
317
|
+
depth: number;
|
|
318
|
+
/** This facet's own id, the one its parent allocated from the tree index. */
|
|
319
|
+
id: FacetId;
|
|
320
|
+
/** The root-owned tree this facet and every descendant share. */
|
|
321
|
+
tree: FacetTree;
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
/** The local entry proxy: data properties stay local; every method becomes one async event. */
|
|
325
|
+
export type ActorEntry<T extends object> = {
|
|
326
|
+
[K in keyof T]: T[K] extends (...args: infer Args) => infer Result ? (...args: Args) => Promise<Awaited<Result>> : T[K];
|
|
327
|
+
};
|
|
328
|
+
export interface ActorContainer {
|
|
329
|
+
/** Implements the workers-types interface. No `as unknown as` cast (§2.4). */
|
|
330
|
+
readonly state: DurableObjectState;
|
|
331
|
+
/**
|
|
332
|
+
* The actor tree this container belongs to, which a root builds for itself and
|
|
333
|
+
* a facet is handed.
|
|
334
|
+
*
|
|
335
|
+
* It is on the interface because the host is the only thing that can carry it
|
|
336
|
+
* from a parent to a child: `FacetHost.start` builds the nested container, and
|
|
337
|
+
* a facet that may have facets of its own needs the root's index rather than
|
|
338
|
+
* one of its own (see `FacetTree`). Upstream needs no equivalent because a
|
|
339
|
+
* facet reaches `root.ensureFacetTreeIndex()` through a plain reference
|
|
340
|
+
* (`server.c++:2697`), and every facet of an actor is an object in one process.
|
|
341
|
+
*
|
|
342
|
+
*/
|
|
343
|
+
readonly facetTree: FacetTree;
|
|
344
|
+
/**
|
|
345
|
+
* Whether this container owns the synchronous actor slice on the JS stack.
|
|
346
|
+
* This is the narrow identity check a host loopback needs to call the raw
|
|
347
|
+
* instance instead of queueing behind the lock it already holds. It resolves
|
|
348
|
+
* no container and carries no state into continuations.
|
|
349
|
+
*/
|
|
350
|
+
isCurrentSlice(): boolean;
|
|
351
|
+
/**
|
|
352
|
+
* Construct the instance under workerd's boot semantics: the input gate is
|
|
353
|
+
* held for the constructor's synchronous slice, and boot-time
|
|
354
|
+
* deletion-receipt replay precedes it.
|
|
355
|
+
*/
|
|
356
|
+
start<T extends object>(construct: (ctx: DurableObjectState, env: unknown) => T): Promise<T>;
|
|
357
|
+
/**
|
|
358
|
+
* THE door for RPC targets. A proxy whose every method invocation is one
|
|
359
|
+
* gated event. This single wrapper is what replaces the serialised tail,
|
|
360
|
+
* all three dispatch tables, and the 33 hand-written exemptions.
|
|
361
|
+
*
|
|
362
|
+
* EVERY call queues, including one made while this actor is holding its own
|
|
363
|
+
* lock across an await. That is §1.2's whole content and the suite pins it: a
|
|
364
|
+
* second event posted while a storage await holds the gate must not interleave,
|
|
365
|
+
* and a door that reused the held lock could not tell that event apart from a
|
|
366
|
+
* call the actor made to itself. Telling them apart needs to know WHO is
|
|
367
|
+
* calling, which is a host's question rather than a container's — see the
|
|
368
|
+
* extension host's `loopbackStub`, where an actor reaching its own
|
|
369
|
+
* `DurableObjectNamespace` binding skips this door entirely because the lock it
|
|
370
|
+
* would take is the one it is already holding.
|
|
371
|
+
*/
|
|
372
|
+
entry<T extends object>(target: T): ActorEntry<T>;
|
|
373
|
+
/**
|
|
374
|
+
* The door for events that are not method calls — one WebSocket frame, one
|
|
375
|
+
* host-originated callback. Upstream: `IoContext::run`.
|
|
376
|
+
*/
|
|
377
|
+
run<T>(event: () => T | PromiseLike<T>): Promise<T>;
|
|
378
|
+
/**
|
|
379
|
+
* ← `IoContext::awaitIo`. The form a HOST-PROVIDED async primitive must take,
|
|
380
|
+
* and the only gate primitive this package makes public.
|
|
381
|
+
*
|
|
382
|
+
* Every platform async thing an application can await — `scheduler.wait`, a
|
|
383
|
+
* `fetch`, a WebSocket round trip — is an io-context primitive upstream, which
|
|
384
|
+
* is why "resuming from an await re-enters the isolate with a fresh input
|
|
385
|
+
* lock" needs saying nowhere in workerd: there is no other kind of await.
|
|
386
|
+
* There is here. A raw `setTimeout` resolves a promise the runtime does not
|
|
387
|
+
* own, the application's continuation resumes with an empty invocation stack,
|
|
388
|
+
* and its next `ctx.storage` call throws `no input lock available in this
|
|
389
|
+
* context` — the README's divergence 147. Wrapping the promise in this makes
|
|
390
|
+
* the continuation resume inside a gated slice, which is what upstream's does.
|
|
391
|
+
*
|
|
392
|
+
* It releases the input gate for the duration, per §1.3, so the actor stays
|
|
393
|
+
* re-entrant while it waits. The holding form,
|
|
394
|
+
* `IoContext::awaitIoWithInputLock`, is deliberately NOT public: that one is
|
|
395
|
+
* the transaction boundary of §1.7.1, it belongs to the four async storage
|
|
396
|
+
* calls, and a host holding it by hand is the serialised tail growing back.
|
|
397
|
+
*/
|
|
398
|
+
awaitIo<T>(promise: Promise<T>): Promise<T>;
|
|
399
|
+
/**
|
|
400
|
+
* ← `ServiceWorkerGlobalScope`, the async-primitive half: this actor's
|
|
401
|
+
* `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval`, `fetch` and
|
|
402
|
+
* `scheduler` (`api/global-scope.ts`).
|
|
403
|
+
*
|
|
404
|
+
* **This is what "own the primitives in the worker global" means, and the
|
|
405
|
+
* ownership is the point.** `awaitIo` above is the primitive a host needs to
|
|
406
|
+
* build one of these; this is the set already built, so a host installs rather
|
|
407
|
+
* than reimplements the surface.
|
|
408
|
+
*
|
|
409
|
+
* **One scope per actor, installed lexically, and never resolved from an
|
|
410
|
+
* ambient.** Upstream's globals read `IoContext::current()` because acquisition
|
|
411
|
+
* is structural there; this one holds its context. A host puts it where its
|
|
412
|
+
* actor's code reads it — `globalThis` for a class in the worker's own module
|
|
413
|
+
* graph, a module-scoped binding for a class that arrived as a
|
|
414
|
+
* dynamically-loaded Worker source, which is upstream's own arrangement (§1.11:
|
|
415
|
+
* a dynamic Worker has its own global scope bound to its own context). What
|
|
416
|
+
* happens when a facet reaches past its binding to a parent's scope is
|
|
417
|
+
* `ActorGlobalScope`'s `requireOwnSlice`.
|
|
418
|
+
*/
|
|
419
|
+
readonly globals: ActorGlobalScope;
|
|
420
|
+
/**
|
|
421
|
+
* ← `WebSocket::accept()` / `state.acceptWebSocket()`
|
|
422
|
+
* (`api/web-socket.c++:133`, `:426`), whose gating is `api/web-socket.ts`.
|
|
423
|
+
*
|
|
424
|
+
* Separate from `globals` because accepting is an act rather than a binding:
|
|
425
|
+
* the critical section is captured at THIS call, so a socket accepted inside
|
|
426
|
+
* `blockConcurrencyWhile` delivers its frames inside that section (§1.8).
|
|
427
|
+
*/
|
|
428
|
+
acceptWebSocket(socket: RawWebSocket): AcceptedWebSocket;
|
|
429
|
+
/**
|
|
430
|
+
* ← `WorkerInterface::runAlarm(scheduledTime, retryCount)`
|
|
431
|
+
* (`io/worker-interface.h:107`), which is what `AlarmScheduler` calls and what
|
|
432
|
+
* `ServiceWorkerGlobalScope::runAlarm` answers. Strictly serialised (§1.8).
|
|
433
|
+
*
|
|
434
|
+
* It reports rather than throws, because the two bits the scheduler's ladder
|
|
435
|
+
* turns on — retry, and whether the retry counts against the limit — are not
|
|
436
|
+
* derivable from "the promise rejected".
|
|
437
|
+
*
|
|
438
|
+
* `retryCount` reaches the handler as `AlarmInvocationInfo`. It is the
|
|
439
|
+
* scheduler's `countedRetry` for this alarm, so the container takes it as an
|
|
440
|
+
* argument exactly as upstream's `runAlarm` does.
|
|
441
|
+
*/
|
|
442
|
+
deliverAlarm(scheduledTime: number, retryCount: number): Promise<AlarmResult>;
|
|
443
|
+
/**
|
|
444
|
+
* ← `WorkerInterface::abandonAlarm` (`io/worker-interface.h:114`), forwarded to
|
|
445
|
+
* `ActorSqlite::abandonAlarm` (`io/actor-sqlite.c++:1039-1060`).
|
|
446
|
+
*
|
|
447
|
+
* Called when the scheduler has given up retrying, so the actor clears its own
|
|
448
|
+
* alarm state and `getAlarm()` stops reporting a time that will never fire.
|
|
449
|
+
* Answers the actor's stored alarm time when it differs from `scheduledTime` —
|
|
450
|
+
* meaning the application set a different one — and null when the alarm was
|
|
451
|
+
* cleared or there was none.
|
|
452
|
+
*/
|
|
453
|
+
abandonAlarm(scheduledTime: number): Promise<number | null>;
|
|
454
|
+
/**
|
|
455
|
+
* Output-gate wait for outbound sends that do not ride an `entry()` reply.
|
|
456
|
+
* A broadcast path calls this before each frame (decision 5).
|
|
457
|
+
*/
|
|
458
|
+
waitOutputLocks(): Promise<void>;
|
|
459
|
+
/** For the host's idle check — today's `drainWaitUntil`. */
|
|
460
|
+
drainWaitUntil(): Promise<void>;
|
|
461
|
+
/**
|
|
462
|
+
* ← `WorkerdApi::compileGlobals`'s `Global::WorkerLoader` arm
|
|
463
|
+
* (`server/workerd-api.c++:748-752`), which is the step that turns a configured
|
|
464
|
+
* loader channel into the JS binding an application finds in `env`.
|
|
465
|
+
*
|
|
466
|
+
* **The one binding the runtime has to construct, and the reason is the
|
|
467
|
+
* context.** Upstream's `WorkerLoader` holds a channel number and a
|
|
468
|
+
* validation mode and nothing else, because `get()` and `load()` read
|
|
469
|
+
* `IoContext::current()` when they are called. This package deliberately has no
|
|
470
|
+
* ambient of any kind, so the context is a constructor input — and it must be
|
|
471
|
+
* *this* container's, since `makeReentryCallback` inherits the critical section
|
|
472
|
+
* a `blockConcurrencyWhile` is holding (decision 13). `IoContext` is not
|
|
473
|
+
* exported, on purpose (see `src/index.ts`'s header), so this method is how a
|
|
474
|
+
* host gets a loader bound to the right one.
|
|
475
|
+
*
|
|
476
|
+
* The host still owns the name: assign the result onto the `env` object it
|
|
477
|
+
* passed in, which is what upstream's binding compilation does one layer down.
|
|
478
|
+
* A container whose host never calls this simply has no loader binding, exactly
|
|
479
|
+
* as a Worker with no `workerLoader` in its config does.
|
|
480
|
+
*/
|
|
481
|
+
workerLoader(channel: IsolateChannelFactory, options: WorkerLoaderOptions): WorkerLoader;
|
|
482
|
+
/**
|
|
483
|
+
* Rejects when either gate breaks, or when a facet the parent did not abort
|
|
484
|
+
* breaks (decisions 6 and 14). The host consumes this: terminate the worker,
|
|
485
|
+
* respawn on the next event.
|
|
486
|
+
*/
|
|
487
|
+
readonly onBroken: Promise<never>;
|
|
488
|
+
/** The programmatic `ctx.abort()` path. */
|
|
489
|
+
abort(reason?: unknown): void;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* A facet has no alarm slot, and this is where that becomes visible.
|
|
493
|
+
*
|
|
494
|
+
* `server.c++:2864-2877` installs alarm hooks only `if (parent == kj::none)` and
|
|
495
|
+
* gives a facet `ActorSqlite::Hooks::getDefaultHooks()`, whose `scheduleRun`
|
|
496
|
+
* throws — so on workerd a `setAlarm()` inside a facet appears to succeed and
|
|
497
|
+
* then breaks the whole actor asynchronously, which is open bug
|
|
498
|
+
* https://github.com/cloudflare/workerd/issues/6810. This runtime refuses at the
|
|
499
|
+
* call instead, as recorded in §2.7. A deliberate semantic
|
|
500
|
+
* divergence: the observable behaviour is a synchronous throw naming the facet
|
|
501
|
+
* where workerd's is a destroyed actor three turns later.
|
|
502
|
+
*/
|
|
503
|
+
export declare const FACET_ALARM_UNIMPLEMENTED_MESSAGE: string;
|
|
504
|
+
/**
|
|
505
|
+
* ← the `kj::File` `FacetTreeIndex` is constructed over, backed by one BLOB.
|
|
506
|
+
*
|
|
507
|
+
* `datasync()` is a no-op and that is a property of the substrate rather than a
|
|
508
|
+
* shortcut: nothing else ever opens a transaction on this connection, so every
|
|
509
|
+
* statement below is its own implicit SQLite transaction and is durable by the
|
|
510
|
+
* time `exec` returns. The read-modify-write is O(file) per append, which is
|
|
511
|
+
* what upstream's own bound makes affordable — the format is four bytes plus a
|
|
512
|
+
* name per facet and there can be at most 65,535 facets over an actor's whole
|
|
513
|
+
* lifetime (`facet-tree-index.h:19-22`).
|
|
514
|
+
*/
|
|
515
|
+
export declare function newDatabaseIndexFile(db: SqlDatabase): IndexFile;
|
|
516
|
+
/**
|
|
517
|
+
* Builds one actor: the two gates, the `IoContext` over them, the storage engine
|
|
518
|
+
* over the actor's database, the facet tree, the id factory, and the `api/`
|
|
519
|
+
* classes on top.
|
|
520
|
+
*
|
|
521
|
+
* Asynchronous because `SqlDatabaseProvider.open` is — see this file's header for
|
|
522
|
+
* why that surfaces here rather than being hidden behind a lazily-opening
|
|
523
|
+
* `state`.
|
|
524
|
+
*/
|
|
525
|
+
export declare function createActorContainer(options: ActorContainerOptions): Promise<ActorContainer>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ← workerd `src/workerd/server/actor-id-impl.{h,c++}`
|
|
3
|
+
*
|
|
4
|
+
* The implementation behind `io/actor-id.ts`'s two interfaces, which that file's
|
|
5
|
+
* header names as Section 6's problem: "upstream's is a keyed SHA-256
|
|
6
|
+
* construction … a faithful port of it needs a synchronous digest, which the
|
|
7
|
+
* browser does not expose."
|
|
8
|
+
*
|
|
9
|
+
* **What upstream computes.** The factory's key is `SHA256(uniqueKey)`, where
|
|
10
|
+
* `uniqueKey` is the namespace's configured string (`workerd-api.c++:675`).
|
|
11
|
+
* An id is 32 bytes in two halves: a 16-byte base and the first 16 bytes of
|
|
12
|
+
* `HMAC-SHA256(key, base)` — `computeMac` (`actor-id-impl.c++:115-125`), which
|
|
13
|
+
* writes a full 32-byte HMAC into a 48-byte working buffer of which only the
|
|
14
|
+
* first 32 bytes ever become the id. `idFromName` derives the base from
|
|
15
|
+
* `HMAC-SHA256(key, name)` (`:71-83`); `newUniqueId` draws it from the entropy
|
|
16
|
+
* source (`:48-69`); `idFromString` takes it from the supplied hex and refuses
|
|
17
|
+
* the string unless the MAC it recomputes matches the half that came with it
|
|
18
|
+
* (`:85-100`). `toString` is `kj::encodeHex` of the 32 bytes.
|
|
19
|
+
*
|
|
20
|
+
* **The digest is written out; the bytes are unchanged.** Every method on
|
|
21
|
+
* `ActorIdFactory` is synchronous (`io/actor-id.h:66-71`) and no browser API
|
|
22
|
+
* offers a synchronous digest, so `server/sha256.ts` supplies SHA-256 and
|
|
23
|
+
* HMAC-SHA-256 in place of BoringSSL. It computes what FIPS 180-4 and RFC 2104
|
|
24
|
+
* specify, so this is decision 16's **substrate** divergence and not a semantic
|
|
25
|
+
* one: `idFromName` here produces the identical 64 hex digits workerd produces
|
|
26
|
+
* from the same unique key, which keeps workerd usable as an oracle for ids.
|
|
27
|
+
*
|
|
28
|
+
* That equality is why the construction is ported whole rather than narrowed.
|
|
29
|
+
* The reduced threat model would have tolerated much less — ids never cross the
|
|
30
|
+
* host boundary, there is no colo, no jurisdiction routing and no second worker
|
|
31
|
+
* re-deriving an id from the same key, so nothing here forges an id — but only
|
|
32
|
+
* two of the contract's properties are cheap to satisfy any other way. The other
|
|
33
|
+
* two are not: `idFromName` must be **stable forever**, because the id names the
|
|
34
|
+
* actor's storage and a name that hashed differently after a restart loses its
|
|
35
|
+
* data; and `idFromString` must **refuse a string this namespace did not mint**,
|
|
36
|
+
* which is a decision only the keyed MAC half can make. A narrower construction
|
|
37
|
+
* would have satisfied both and cost the oracle, turning every future question
|
|
38
|
+
* about an id into original research on a bespoke artifact — the failure the
|
|
39
|
+
* "Porting philosophy" section describes.
|
|
40
|
+
*
|
|
41
|
+
* **`isPredictableModeForTest()` is absent** (`actor-id-impl.c++:59-62`). It is a
|
|
42
|
+
* `util/thread-scopes.h` process-global test hack with no port here, it makes
|
|
43
|
+
* `newUniqueId` return a counter, and `actor-id-impl-test.c++` does not use it.
|
|
44
|
+
* Its body is also wrong upstream: `kj::arrayPtr(id).slice(counter)` slices by
|
|
45
|
+
* the counter's *value*, which is a no-op for every counter it can legitimately
|
|
46
|
+
* reach and out of bounds once the counter passes the buffer's 48 bytes.
|
|
47
|
+
*
|
|
48
|
+
* Spec: §1.10 in docs/decisions.md.
|
|
49
|
+
*/
|
|
50
|
+
import type { ActorId, ActorIdFactory } from "../io/actor-id.js";
|
|
51
|
+
/**
|
|
52
|
+
* ← `JSG_REQUIRE(jurisdiction == kj::none, Error, …)` (`actor-id-impl.c++:50-51`,
|
|
53
|
+
* `:108`).
|
|
54
|
+
*
|
|
55
|
+
* Verbatim, "in workerd" and all: the conformance suite runs one assertion
|
|
56
|
+
* against both runtimes, so a reworded message would be a difference where there
|
|
57
|
+
* is none.
|
|
58
|
+
*/
|
|
59
|
+
export declare const JURISDICTION_UNIMPLEMENTED_MESSAGE = "Jurisdiction restrictions are not implemented in workerd.";
|
|
60
|
+
/** ← the first `JSG_REQUIRE` in `idFromString` (`actor-id-impl.c++:87-89`). */
|
|
61
|
+
export declare const INVALID_ACTOR_ID_MESSAGE = "Invalid Durable Object ID: must be 64 hex digits";
|
|
62
|
+
/** ← the second `JSG_REQUIRE` in `idFromString` (`actor-id-impl.c++:96-97`). */
|
|
63
|
+
export declare const WRONG_NAMESPACE_ACTOR_ID_MESSAGE = "Durable Object ID is not valid for this namespace.";
|
|
64
|
+
/**
|
|
65
|
+
* Upstream `kj::downcast`s the argument of `equals` (`actor-id-impl.c++:33`),
|
|
66
|
+
* which asserts in a debug build and is undefined in a release one. There is one
|
|
67
|
+
* `ActorId` implementation here, so a correct caller cannot reach this; it fails
|
|
68
|
+
* closed rather than comparing something meaningless.
|
|
69
|
+
*/
|
|
70
|
+
export declare const FOREIGN_ACTOR_ID_MESSAGE = "This actor id was not created by this runtime, so it cannot be compared with one that was.";
|
|
71
|
+
/** ← `ActorIdFactoryImpl::ActorIdImpl` (`actor-id-impl.h:13-30`). */
|
|
72
|
+
export declare class ActorIdImpl implements ActorId {
|
|
73
|
+
#private;
|
|
74
|
+
/**
|
|
75
|
+
* ← the constructor (`actor-id-impl.c++:14-18`). Its parameter is declared
|
|
76
|
+
* `const kj::byte idParam[SHA256_DIGEST_LENGTH]` and its body `memcpy`s
|
|
77
|
+
* exactly `sizeof(id)` bytes, so a caller may hand over the longer working
|
|
78
|
+
* buffer and only its first 32 bytes become the id. The copy is upstream's
|
|
79
|
+
* too — a later write to the caller's buffer is not seen here.
|
|
80
|
+
*/
|
|
81
|
+
constructor(id: Uint8Array, name: string | undefined);
|
|
82
|
+
/** ← `toString()` — `kj::encodeHex`, which is lowercase (`actor-id-impl.c++:20-22`). */
|
|
83
|
+
toString(): string;
|
|
84
|
+
/** ← `getName()` (`actor-id-impl.c++:24-26`). */
|
|
85
|
+
getName(): string | undefined;
|
|
86
|
+
/** ← `getJurisdiction()`, which is unconditionally none (`actor-id-impl.c++:28-30`). */
|
|
87
|
+
getJurisdiction(): string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* ← `equals()` (`actor-id-impl.c++:32-34`). The id bytes only — the name is
|
|
90
|
+
* deliberately not part of identity, which is what upstream's own table
|
|
91
|
+
* asserts by giving two equal ids different names.
|
|
92
|
+
*/
|
|
93
|
+
equals(other: ActorId): boolean;
|
|
94
|
+
/** ← `clearName()` (`actor-id-impl.h:23-25`). Not JS-visible; `server/` calls it. */
|
|
95
|
+
clearName(): void;
|
|
96
|
+
}
|
|
97
|
+
/** ← `ActorIdFactoryImpl` (`actor-id-impl.h:8-46`). */
|
|
98
|
+
export declare class ActorIdFactoryImpl implements ActorIdFactory {
|
|
99
|
+
#private;
|
|
100
|
+
/**
|
|
101
|
+
* ← both constructors (`actor-id-impl.c++:40-46`). C++ overloads on the
|
|
102
|
+
* parameter type; one constructor branching on it is the same two behaviours.
|
|
103
|
+
* The string form is the namespace's configured `uniqueKey`
|
|
104
|
+
* (`workerd-api.c++:675`, `:680`); the byte form exists for
|
|
105
|
+
* `cloneWithJurisdiction`, which passes the already-derived key.
|
|
106
|
+
*/
|
|
107
|
+
constructor(uniqueKey: string | Uint8Array);
|
|
108
|
+
/** ← `newUniqueId()` (`actor-id-impl.c++:48-69`). */
|
|
109
|
+
newUniqueId(jurisdiction: string | undefined): ActorId;
|
|
110
|
+
/** ← `idFromName()` (`actor-id-impl.c++:71-83`). */
|
|
111
|
+
idFromName(name: string): ActorId;
|
|
112
|
+
/** ← `idFromString()` (`actor-id-impl.c++:85-100`). */
|
|
113
|
+
idFromString(str: string): ActorId;
|
|
114
|
+
/** ← `cloneWithJurisdiction()` (`actor-id-impl.c++:102-109`). */
|
|
115
|
+
cloneWithJurisdiction(maybeJurisdiction: string | undefined): ActorIdFactory;
|
|
116
|
+
/** ← `matchesJurisdiction()`, which is unconditionally true (`actor-id-impl.c++:111-113`). */
|
|
117
|
+
matchesJurisdiction(_id: ActorId): boolean;
|
|
118
|
+
}
|