@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,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ← workerd `src/workerd/api/export-loopback.{h,c++}`
|
|
3
|
+
*
|
|
4
|
+
* The four types `ctx.exports` is made of. Upstream's own comment on the first
|
|
5
|
+
* says what they all are: "the type of a property of `ctx.exports` which points
|
|
6
|
+
* back at a … entrypoint of this Worker", specialized by *invoking* it.
|
|
7
|
+
*
|
|
8
|
+
* - `LoopbackServiceStub` (`export-loopback.h:18`) — a stateless entrypoint. A
|
|
9
|
+
* `Fetcher` with empty props, callable to get one with props.
|
|
10
|
+
* - `LoopbackDurableObjectClass` (`:116`) — an actor class with **no storage
|
|
11
|
+
* configured**. A `DurableObjectClass`, callable to get a specialized one.
|
|
12
|
+
* - `LoopbackDurableObjectNamespace` (`:155`) — an actor class **with** storage:
|
|
13
|
+
* "we want a binding that behaves *both* like a LoopbackDurableObjectClass
|
|
14
|
+
* *and* like a DurableObjectNamespace binding."
|
|
15
|
+
* - `LoopbackColoLocalActorNamespace` (`:192`) — the same, for a colo-local
|
|
16
|
+
* (ephemeral) namespace binding.
|
|
17
|
+
*
|
|
18
|
+
* The third is why this file blocks `server/`. The vendored consumer reads
|
|
19
|
+
* `ctx.exports[className]` and needs one value to answer both `idFromName`
|
|
20
|
+
* (`vendor/agents/packages/agents/src/index.ts:10829`, `:10855`) and
|
|
21
|
+
* `ctx.facets.get`'s class check (`:10857`) — namespace-shaped and class-shaped
|
|
22
|
+
* at once, which is exactly what `LoopbackDurableObjectNamespace` is for.
|
|
23
|
+
* Upstream's own `api/tests/worker-loader-test.js:449-450` pins the same pair.
|
|
24
|
+
*
|
|
25
|
+
* **`JSG_CALLABLE` becomes a `Proxy` with an `apply` trap.** A JS value can only
|
|
26
|
+
* be invoked if it is a function, and a class instance is not one; the private
|
|
27
|
+
* fields these classes inherit mean the callable cannot simply be a function
|
|
28
|
+
* whose prototype is the instance, because an inherited method would then run
|
|
29
|
+
* with `this` set to the function. So each class keeps its behaviour and an
|
|
30
|
+
* `asLoopback…` function produces the JS-visible value — the same split, for the
|
|
31
|
+
* same reason, that `asDurableObjectStub` already makes for `JSG_INHERIT`.
|
|
32
|
+
* `getPrototypeOf` is what keeps `instanceof` answering, which is how
|
|
33
|
+
* `DurableObjectFacets.get` discriminates the three arms of its class switch.
|
|
34
|
+
*
|
|
35
|
+
* **Two `IoChannelFactory` methods are declared here rather than in
|
|
36
|
+
* `io/io-channels.ts`.** `getSubrequestChannel` and `getActorClass` are what
|
|
37
|
+
* `export-loopback.c++` reaches for, and both take a channel *number* upstream —
|
|
38
|
+
* which this package does not have (`io/io-channels.ts`'s header: there is no
|
|
39
|
+
* numbered channel table). So each collapses into a factory taking an object
|
|
40
|
+
* request, exactly as `api/actor.ts` already does for `IoChannelFactory`'s
|
|
41
|
+
* `getGlobalActor` and `getColoLocalActor`, and each is declared beside its one
|
|
42
|
+
* consumer for the same reason `ActorChannelFactory` is. Section 7 fills them.
|
|
43
|
+
*
|
|
44
|
+
* **Non-serializability survives, and Section 7b is where it is enforced.**
|
|
45
|
+
* Upstream is explicit that `LoopbackServiceStub` is "intentionally NOT
|
|
46
|
+
* serializable, unlike its parent class Fetcher", and
|
|
47
|
+
* `api/tests/worker-loader-test.js:104` asserts the message;
|
|
48
|
+
* `LoopbackDurableObjectClass` likewise declares no `JSG_SERIALIZABLE` where
|
|
49
|
+
* `DurableObjectClass` (`actor.h:389`) does, and neither namespace type declares
|
|
50
|
+
* one either — `JSG_INHERIT` does not carry serializability, which is what the
|
|
51
|
+
* test's own comment says it is checking.
|
|
52
|
+
*
|
|
53
|
+
* An earlier revision of this paragraph said the refusal did not survive, and
|
|
54
|
+
* named `src/transport/` as the layer that would have to make it. Both halves
|
|
55
|
+
* were wrong about *where*: the test reaches the refusal through
|
|
56
|
+
* `worker.getEntrypoint(name, {props})`, and `WorkerStub::getEntrypoint`'s first
|
|
57
|
+
* act is `Frankenvalue::fromJs`, which runs `jsg::Serializer` inside
|
|
58
|
+
* `api/worker-loader.c++`. So `api/worker-loader.ts`'s `requireSerializableProps`
|
|
59
|
+
* refuses all four of these in `props` and in `env`, with upstream's message and
|
|
60
|
+
* a `DataCloneError`. `DurableObjectClass.serialize` remains a separate named
|
|
61
|
+
* substrate boundary that throws for every class, loopback or not.
|
|
62
|
+
*
|
|
63
|
+
* The version half of `LoopbackServiceStub` is present and `Options`, the
|
|
64
|
+
* flag-off form, is not: `FeatureFlags::getEnableVersionApi()` is read as on
|
|
65
|
+
* here, the same current-behaviour reading `api/actor.ts` gives the four
|
|
66
|
+
* compatibility flags it meets. That makes this a superset of
|
|
67
|
+
* `@cloudflare/workers-types` 4.20260702.1, which generated the flag-off
|
|
68
|
+
* signature — the same relationship `DurableObjectNamespace.getExisting` has.
|
|
69
|
+
*
|
|
70
|
+
* Spec: §1.10, §1.11, decisions 14 and 16 in
|
|
71
|
+
* docs/decisions.md.
|
|
72
|
+
*/
|
|
73
|
+
import type { ActorIdFactory } from "../io/actor-id.js";
|
|
74
|
+
import type { ActorClassChannel } from "../io/io-channels.js";
|
|
75
|
+
import { ColoLocalActorNamespace, DurableObjectClass, DurableObjectNamespace, type ActorChannelFactory, type ColoLocalActorChannelFactory } from "./actor.js";
|
|
76
|
+
/**
|
|
77
|
+
* ← what JSG's struct unwrapper does with a value that is not an object
|
|
78
|
+
* (`jsg/struct.h:246`). Undefined and null are **not** in that set: a struct
|
|
79
|
+
* whose every field is optional — which both option structs here are — unwraps
|
|
80
|
+
* from either as an empty struct (`jsg/struct.h:236-243`), so `ctx.exports.Foo()`
|
|
81
|
+
* is upstream's own empty-options call and not an error.
|
|
82
|
+
*/
|
|
83
|
+
export declare const LOOPBACK_OPTIONS_NOT_AN_OBJECT_MESSAGE = "A ctx.exports binding is invoked with an options object: pass { props }, or nothing at all.";
|
|
84
|
+
/** ← what JSG does unwrapping a `jsg::JsRef<jsg::JsObject>` from a non-object. */
|
|
85
|
+
export declare const LOOPBACK_PROPS_NOT_AN_OBJECT_MESSAGE = "`props` must be an object. Upstream unwraps it as a jsg::JsObject, which refuses anything else.";
|
|
86
|
+
/** ← `IoChannelFactory::VersionRequest` (`io/io-channels.h:123-131`). */
|
|
87
|
+
export type VersionRequest = {
|
|
88
|
+
/** "Request a version within the given cohort." */
|
|
89
|
+
readonly cohort: string | undefined;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* ← the two arguments `IoChannelFactory::getSubrequestChannel` takes besides the
|
|
93
|
+
* channel number (`io/io-channels.h:243-245`). Upstream: "`props` and
|
|
94
|
+
* `versionRequest` can only be specified if this is a loopback channel (i.e.
|
|
95
|
+
* from ctx.exports)."
|
|
96
|
+
*/
|
|
97
|
+
export type SubrequestChannelRequest = {
|
|
98
|
+
/** ← `kj::Maybe<Frankenvalue> props`. */
|
|
99
|
+
readonly props: unknown;
|
|
100
|
+
readonly version: VersionRequest | undefined;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* ← `IoChannelFactory::getSubrequestChannel` composed with the `Fetcher` upstream
|
|
104
|
+
* builds over the `SubrequestChannel` it returns.
|
|
105
|
+
*
|
|
106
|
+
* The composition is `api/actor.ts`'s: a `SubrequestChannel` is only ever driven
|
|
107
|
+
* through `startRequest()` → `WorkerInterface`, which has no port, while the
|
|
108
|
+
* JS-visible product is a `Fetcher` — so the channel and the stub it produces are
|
|
109
|
+
* one object here.
|
|
110
|
+
*/
|
|
111
|
+
export interface SubrequestChannelFactory {
|
|
112
|
+
getSubrequestChannel(request: SubrequestChannelRequest): Fetcher;
|
|
113
|
+
}
|
|
114
|
+
/** ← the `props` argument of `IoChannelFactory::getActorClass` (`io/io-channels.h:315`). */
|
|
115
|
+
export type ActorClassRequest = {
|
|
116
|
+
readonly props: unknown;
|
|
117
|
+
};
|
|
118
|
+
/** ← `IoChannelFactory::getActorClass`, which returns the token `io/io-channels.ts` ports. */
|
|
119
|
+
export interface ActorClassChannelFactory {
|
|
120
|
+
getActorClass(request: ActorClassRequest): ActorClassChannel;
|
|
121
|
+
}
|
|
122
|
+
/** ← `LoopbackServiceStub::OptionsWithVersion::Version` (`export-loopback.h:32-36`). */
|
|
123
|
+
export type LoopbackServiceStubVersion = {
|
|
124
|
+
/** `jsg::Optional<kj::Maybe<kj::String>>`: omitted and null are the same request. */
|
|
125
|
+
readonly cohort?: string | null;
|
|
126
|
+
};
|
|
127
|
+
/** ← `LoopbackServiceStub::OptionsWithVersion` (`export-loopback.h:31-42`). */
|
|
128
|
+
export type LoopbackServiceStubOptions = {
|
|
129
|
+
readonly props?: unknown;
|
|
130
|
+
readonly version?: LoopbackServiceStubVersion;
|
|
131
|
+
};
|
|
132
|
+
/** ← `LoopbackDurableObjectClass::Options` (`export-loopback.h:120-124`). */
|
|
133
|
+
export type LoopbackDurableObjectClassOptions = {
|
|
134
|
+
readonly props?: unknown;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* ← `LoopbackServiceStub` (`export-loopback.h:18-109`).
|
|
138
|
+
*
|
|
139
|
+
* Upstream is a `Fetcher` on the loopback channel and holds the channel number a
|
|
140
|
+
* second time so `callImpl` can re-specialize it. Here the `Fetcher` is the
|
|
141
|
+
* transport's — `api/http.{h,c++}` is not ported — so the unspecialized stub is
|
|
142
|
+
* what the factory returns for a request with no props and no version, and the
|
|
143
|
+
* factory is the thing held twice over.
|
|
144
|
+
*/
|
|
145
|
+
export declare class LoopbackServiceStub {
|
|
146
|
+
#private;
|
|
147
|
+
constructor(channel: SubrequestChannelFactory);
|
|
148
|
+
/** The `Fetcher` upstream inherits from rather than holds, as `DurableObject`'s is. */
|
|
149
|
+
getFetcher(): Fetcher;
|
|
150
|
+
/**
|
|
151
|
+
* ← `LoopbackServiceStub::callImpl` (`export-loopback.c++:11-29`) reached
|
|
152
|
+
* through `callWithVersion` (`export-loopback.h:53-55`), which is the callable
|
|
153
|
+
* when `enableVersionApi` is on. "Create a specialized Fetcher which can be
|
|
154
|
+
* passed over RPC."
|
|
155
|
+
*/
|
|
156
|
+
callWithVersion(options: LoopbackServiceStubOptions): Fetcher;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* ← `js.alloc<LoopbackServiceStub>(…)` plus `JSG_CALLABLE(callWithVersion)`.
|
|
160
|
+
*
|
|
161
|
+
* The declared type is a superset of `@cloudflare/workers-types`' by exactly the
|
|
162
|
+
* `version` field, for the reason in this module's header.
|
|
163
|
+
*/
|
|
164
|
+
export type LoopbackServiceStubValue<T extends Rpc.WorkerEntrypointBranded | undefined = undefined> = Fetcher<T> & ((options?: LoopbackServiceStubOptions) => Fetcher<T>);
|
|
165
|
+
export declare function asLoopbackServiceStub<T extends Rpc.WorkerEntrypointBranded | undefined = undefined>(stub: LoopbackServiceStub): LoopbackServiceStubValue<T>;
|
|
166
|
+
/**
|
|
167
|
+
* ← `LoopbackDurableObjectClass` (`export-loopback.h:116-148`). "Similar to
|
|
168
|
+
* LoopbackServiceStub, but for actor classes … this is used for actor classes
|
|
169
|
+
* that do *not* have any storage configured. If you simply export a class
|
|
170
|
+
* extending `DurableObject` but you don't configure storage for it, it shows up
|
|
171
|
+
* in `ctx.exports` as this type. This can be used to create a Durable Object
|
|
172
|
+
* facet."
|
|
173
|
+
*
|
|
174
|
+
* Upstream's base `DurableObjectClass` holds the channel *number*, and
|
|
175
|
+
* `getChannel(ioctx)` resolves it lazily. There is no numbered arm here, so the
|
|
176
|
+
* unspecialized channel is requested once, in the constructor — which is the same
|
|
177
|
+
* value `getActorClass(channel)` with default props would have produced.
|
|
178
|
+
*/
|
|
179
|
+
export declare class LoopbackDurableObjectClass<T extends Rpc.DurableObjectBranded | undefined = undefined> extends DurableObjectClass<T> {
|
|
180
|
+
#private;
|
|
181
|
+
constructor(channel: ActorClassChannelFactory);
|
|
182
|
+
/**
|
|
183
|
+
* ← `LoopbackDurableObjectClass::call` (`export-loopback.c++:31-40`). "Create a
|
|
184
|
+
* specialized DurableObjectClass which can be passed over RPC."
|
|
185
|
+
*
|
|
186
|
+
* The result is a plain `DurableObjectClass`, as `js.alloc<DurableObjectClass>`
|
|
187
|
+
* is: specializing a loopback class does not produce another loopback class.
|
|
188
|
+
*/
|
|
189
|
+
call(options: LoopbackDurableObjectClassOptions): DurableObjectClass<T>;
|
|
190
|
+
}
|
|
191
|
+
/** ← `js.alloc<LoopbackDurableObjectClass>(…)` plus `JSG_CALLABLE(call)`. */
|
|
192
|
+
export type LoopbackDurableObjectClassValue<T extends Rpc.DurableObjectBranded | undefined = undefined> = DurableObjectClass<T> & ((options?: LoopbackDurableObjectClassOptions) => DurableObjectClass<T>);
|
|
193
|
+
export declare function asLoopbackDurableObjectClass<T extends Rpc.DurableObjectBranded | undefined = undefined>(actorClass: LoopbackDurableObjectClass<T>): LoopbackDurableObjectClassValue<T>;
|
|
194
|
+
/**
|
|
195
|
+
* ← `LoopbackDurableObjectNamespace` (`export-loopback.h:155-189`).
|
|
196
|
+
*
|
|
197
|
+
* Upstream: "used when the class has storage configured. In this case, we want a
|
|
198
|
+
* binding that behaves *both* like a LoopbackDurableObjectClass *and* like a
|
|
199
|
+
* DurableObjectNamespace binding. Easy enough, we'll inherit
|
|
200
|
+
* DurableObjectNamespace, but also make the binding invokable as a function like
|
|
201
|
+
* LoopbackDurableObjectClass."
|
|
202
|
+
*/
|
|
203
|
+
export declare class LoopbackDurableObjectNamespace<T extends Rpc.DurableObjectBranded | undefined = undefined> extends DurableObjectNamespace<T> {
|
|
204
|
+
#private;
|
|
205
|
+
constructor(channel: ActorChannelFactory, idFactory: ActorIdFactory, loopbackClass: LoopbackDurableObjectClass<T>);
|
|
206
|
+
/** ← `getClass()`. "getClass() accessor for use from C++ only." */
|
|
207
|
+
getClass(): LoopbackDurableObjectClass<T>;
|
|
208
|
+
/** ← `call`. "Invoking the binding creates a specialization of the class -- not the namespace." */
|
|
209
|
+
call(options: LoopbackDurableObjectClassOptions): DurableObjectClass<T>;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* ← `js.alloc<LoopbackDurableObjectNamespace>(…)` plus `JSG_CALLABLE(call)`.
|
|
213
|
+
*
|
|
214
|
+
* This is the type of a `ctx.exports` entry for a Durable Object class with
|
|
215
|
+
* storage, and the reason it is stated in terms of this package's classes rather
|
|
216
|
+
* than `@cloudflare/workers-types`' `LoopbackDurableObjectNamespace` is that the
|
|
217
|
+
* pinned interface is `interface LoopbackDurableObjectNamespace extends
|
|
218
|
+
* DurableObjectNamespace {}` — no call signature, because that resource type
|
|
219
|
+
* carries no `JSG_TS_OVERRIDE` to generate one from. `Cloudflare.Exports`
|
|
220
|
+
* describes the same value correctly, as `LoopbackDurableObjectClass<T> &
|
|
221
|
+
* DurableObjectNamespace<T>`, and `PinnedLoopbackTypes` below checks against
|
|
222
|
+
* that rather than against the interface.
|
|
223
|
+
*
|
|
224
|
+
* `call` is omitted because `JSG_CALLABLE` registers it as the object's call
|
|
225
|
+
* behaviour rather than as a property: on the value, `.call` is
|
|
226
|
+
* `Function.prototype.call`, which is what `asCallable`'s `get` trap answers.
|
|
227
|
+
*/
|
|
228
|
+
export type LoopbackDurableObjectNamespaceValue<T extends Rpc.DurableObjectBranded | undefined = undefined> = Omit<LoopbackDurableObjectNamespace<T>, "call"> & ((options?: LoopbackDurableObjectClassOptions) => DurableObjectClass<T>);
|
|
229
|
+
export declare function asLoopbackDurableObjectNamespace<T extends Rpc.DurableObjectBranded | undefined = undefined>(namespace: LoopbackDurableObjectNamespace<T>): LoopbackDurableObjectNamespaceValue<T>;
|
|
230
|
+
/**
|
|
231
|
+
* ← `LoopbackColoLocalActorNamespace` (`export-loopback.h:192-220`). "Like
|
|
232
|
+
* LoopbackDurableObjectNamespace, but for colo-local (ephemeral) actor
|
|
233
|
+
* namespaces."
|
|
234
|
+
*/
|
|
235
|
+
export declare class LoopbackColoLocalActorNamespace extends ColoLocalActorNamespace {
|
|
236
|
+
#private;
|
|
237
|
+
constructor(channel: ColoLocalActorChannelFactory, loopbackClass: LoopbackDurableObjectClass);
|
|
238
|
+
/** ← `getClass()`. "getClass() accessor for use from C++ only." */
|
|
239
|
+
getClass(): LoopbackDurableObjectClass;
|
|
240
|
+
/** ← `call`. "Invoking the binding creates a specialization of the class -- not the namespace." */
|
|
241
|
+
call(options: LoopbackDurableObjectClassOptions): DurableObjectClass;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* ← `js.alloc<LoopbackColoLocalActorNamespace>(…)` plus `JSG_CALLABLE(call)`,
|
|
245
|
+
* with `call` omitted for the reason given on the durable namespace above.
|
|
246
|
+
*/
|
|
247
|
+
export type LoopbackColoLocalActorNamespaceValue = Omit<LoopbackColoLocalActorNamespace, "call"> & ((options?: LoopbackDurableObjectClassOptions) => DurableObjectClass);
|
|
248
|
+
export declare function asLoopbackColoLocalActorNamespace(namespace: LoopbackColoLocalActorNamespace): LoopbackColoLocalActorNamespaceValue;
|
|
249
|
+
/** `Value` must be assignable to `Declared`; declaring the constraint is the check. */
|
|
250
|
+
type Assignable<Value extends Declared, Declared> = Value;
|
|
251
|
+
/**
|
|
252
|
+
* Checked rather than claimed: every value this module produces satisfies the
|
|
253
|
+
* shape `@cloudflare/workers-types` 4.20260702.1 declares for it. The last two
|
|
254
|
+
* are checked against `Cloudflare.Exports`' own description of a `ctx.exports`
|
|
255
|
+
* entry — `LoopbackForExport<T>` intersected with the namespace — because the
|
|
256
|
+
* two named interfaces there are call-signature-less, per the note above.
|
|
257
|
+
*/
|
|
258
|
+
export type PinnedLoopbackTypes = [
|
|
259
|
+
Assignable<LoopbackServiceStubValue, globalThis.LoopbackServiceStub>,
|
|
260
|
+
Assignable<LoopbackDurableObjectClassValue, globalThis.LoopbackDurableObjectClass>,
|
|
261
|
+
Assignable<LoopbackDurableObjectNamespaceValue, globalThis.LoopbackDurableObjectClass & globalThis.DurableObjectNamespace>,
|
|
262
|
+
Assignable<LoopbackColoLocalActorNamespaceValue, globalThis.LoopbackDurableObjectClass & globalThis.ColoLocalActorNamespace>
|
|
263
|
+
];
|
|
264
|
+
export {};
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ← workerd `src/workerd/api/global-scope.{h,c++}` — the alarm half, and the
|
|
3
|
+
* async-primitive half `ServiceWorkerGlobalScope` exposes to an application.
|
|
4
|
+
*
|
|
5
|
+
* The event surface (`fetch`/`scheduled`/`trace`/`queue` handlers) still has no
|
|
6
|
+
* port: that belongs to layers this package does not have. What is here is the
|
|
7
|
+
* other thing that class is, and the thing a Durable Object actually reaches —
|
|
8
|
+
* `JSG_METHOD(setTimeout)`, `clearTimeout`, `setInterval`, `clearInterval`,
|
|
9
|
+
* `JSG_METHOD(fetch)`, and `JSG_LAZY_INSTANCE_PROPERTY(scheduler, getScheduler)`
|
|
10
|
+
* (`global-scope.h:776-808`). `Scheduler` itself is `api/basics.h:781-797`; it
|
|
11
|
+
* is one class with one method and it lives beside its only exposure rather than
|
|
12
|
+
* in a `api/basics.ts` that would hold nothing else, since everything else in
|
|
13
|
+
* that file — `Event`, `EventTarget`, `AbortController`, `AbortSignal` — the
|
|
14
|
+
* substrate already provides.
|
|
15
|
+
*
|
|
16
|
+
* **Why this file gained a half.** Workerd's globals hold no context: each one
|
|
17
|
+
* reads `IoContext::current()` at call time (`global-scope.c++:944`, `:961`,
|
|
18
|
+
* `:989`, `:1160`), because acquisition is structural and every entry into the
|
|
19
|
+
* isolate has already taken the lock. There is no isolate hook here, so a
|
|
20
|
+
* continuation that resumes from a promise the runtime does not own comes back
|
|
21
|
+
* with an empty invocation stack and its next `ctx.storage` call throws `no
|
|
22
|
+
* input lock available in this context`. Every host-provided async primitive
|
|
23
|
+
* therefore has to gate itself, and this is where they do.
|
|
24
|
+
*
|
|
25
|
+
* The three primitives take three different mechanisms, and flattening them into
|
|
26
|
+
* "wrap it in awaitIo" would be wrong three ways:
|
|
27
|
+
*
|
|
28
|
+
* - **Timers** capture the critical section at the ARMING call and re-enter
|
|
29
|
+
* through `ctx.run(callback, cs)` when they fire. Not `awaitIo`, deliberately
|
|
30
|
+
* — see `TimeoutManager` in `io/io-context.ts` for upstream's own reason.
|
|
31
|
+
* - **`fetch`** is `awaitIo` (`http.c++` has ten of them and zero
|
|
32
|
+
* `awaitIoWithInputLock`), preceded by an output-gate wait so nothing departs
|
|
33
|
+
* ahead of the writes it might reveal (`http.c++:1488`). §1.3.
|
|
34
|
+
* - **WebSocket** is neither: `api/web-socket.ts`, because a socket is a long
|
|
35
|
+
* stream of events rather than one result.
|
|
36
|
+
*
|
|
37
|
+
* **The context is held, not looked up, and that is the whole of the
|
|
38
|
+
* enforcement substitution.** One scope per actor. See `requireOwnSlice` for
|
|
39
|
+
* what happens when a facet reaches a scope that is not its own.
|
|
40
|
+
*
|
|
41
|
+
* Spec: §1.2, §1.3, §1.8 and decisions 1 and 16 in
|
|
42
|
+
* docs/decisions.md.
|
|
43
|
+
*/
|
|
44
|
+
import { type IoContext } from "../io/io-context.js";
|
|
45
|
+
/**
|
|
46
|
+
* ← `AlarmInvocationInfo` (`api/global-scope.h:386-412`): "a jsg::Object used to
|
|
47
|
+
* pass alarm invocation info to an alarm handler."
|
|
48
|
+
*
|
|
49
|
+
* `scheduledTime` is already milliseconds here where upstream converts a
|
|
50
|
+
* `kj::Date` to them at construction (`global-scope.h:390`), which is the same
|
|
51
|
+
* unit `@cloudflare/workers-types` declares and the same one `setAlarm` takes.
|
|
52
|
+
*/
|
|
53
|
+
export declare class AlarmInvocationInfo implements globalThis.AlarmInvocationInfo {
|
|
54
|
+
readonly scheduledTime: number;
|
|
55
|
+
readonly retryCount: number;
|
|
56
|
+
constructor(scheduledTime: number, retry: number);
|
|
57
|
+
get isRetry(): boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* ← `isAlarmFailureUserError` (`api/global-scope.c++:501-515`), whose own
|
|
61
|
+
* comment lists the three arms: "Returns true if an alarm failure should count
|
|
62
|
+
* against the user's retry limit. A failure is user-generated if any of: the
|
|
63
|
+
* exception was explicitly tagged with EXCEPTION_IS_USER_ERROR at construction
|
|
64
|
+
* time (e.g. state.abort(), exceededCpu, exceededMemory, overload queue); the
|
|
65
|
+
* exception originated from user code throwing inside blockConcurrencyWhile,
|
|
66
|
+
* which breaks the input gate as a secondary side-effect; the exception is a
|
|
67
|
+
* plain jsg.* error without broken.* or jsg-internal.* prefixes, meaning the
|
|
68
|
+
* user's handler threw directly."
|
|
69
|
+
*
|
|
70
|
+
* The first two arms port exactly: this package writes both markers itself —
|
|
71
|
+
* `DurableObjectState.abort()` sets the detail, and `IoContext` annotates a
|
|
72
|
+
* broken input gate with upstream's own prefix.
|
|
73
|
+
*
|
|
74
|
+
* **The third arm has no input here, and its default is inverted deliberately.**
|
|
75
|
+
* Upstream reads it off jsg's exception tunnelling: a `jsg.Error:` prefix that
|
|
76
|
+
* is neither `jsg-internal.` nor a Durable Object reset means the user's handler
|
|
77
|
+
* threw. There is no tunnelling in this runtime — an `Error` out of a handler
|
|
78
|
+
* carries no provenance at all — so a plain exception is reported here as NOT a
|
|
79
|
+
* user error, where upstream would report it as one.
|
|
80
|
+
*
|
|
81
|
+
* That inversion is narrower than it sounds, and it is the safe direction. The
|
|
82
|
+
* caller is
|
|
83
|
+
* `shouldRetryCountsAgainstLimits = !isOutputGateBroken() || isUserGeneratedError`
|
|
84
|
+
* (`global-scope.c++:624`), so for an intact actor a handler failure counts
|
|
85
|
+
* whatever this answers; the only case the two readings disagree on is a handler
|
|
86
|
+
* failure that arrives together with a broken output gate. Upstream counts that
|
|
87
|
+
* and eventually abandons the alarm. This does not, so the alarm outlives the
|
|
88
|
+
* actor's reset and is retried after the restart — which is what
|
|
89
|
+
* `!tunneled.isDurableObjectReset` (`:514`) is reaching for on the arm above it
|
|
90
|
+
* and what the product ranking asks for outright. A default of "user error"
|
|
91
|
+
* would abandon exactly the alarms that most need keeping.
|
|
92
|
+
*/
|
|
93
|
+
export declare function isAlarmFailureUserError(exception: unknown): boolean;
|
|
94
|
+
/** ← `Scheduler::WaitOptions` (`api/basics.h:775-778`). */
|
|
95
|
+
export type SchedulerWaitOptions = {
|
|
96
|
+
signal?: AbortSignal;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* ← `Scheduler` (`api/basics.h:781-797`), whose own comment is: "The scheduler
|
|
100
|
+
* class is an emerging web platform standard API that is meant to be global and
|
|
101
|
+
* provides task scheduling APIs. We currently only implement a subset of the API
|
|
102
|
+
* that is being defined."
|
|
103
|
+
*
|
|
104
|
+
* `wait` is "essentially an awaitable alternative to setTimeout()", and upstream
|
|
105
|
+
* implements it as exactly that — `setTimeoutInternal` onto the same timeout
|
|
106
|
+
* manager (`basics.c++:1007`), which is why it inherits the gating rather than
|
|
107
|
+
* having any of its own.
|
|
108
|
+
*/
|
|
109
|
+
export declare class Scheduler {
|
|
110
|
+
#private;
|
|
111
|
+
constructor(scope: ActorGlobalScope);
|
|
112
|
+
/** ← `Scheduler::wait` (`basics.c++:989-1020`). */
|
|
113
|
+
wait(delay: number, options?: SchedulerWaitOptions): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* NO upstream correspondence: `scheduler.yield()` is the Prioritized Task
|
|
116
|
+
* Scheduling API's, which workerd does not implement — `Scheduler` above has
|
|
117
|
+
* exactly one `JSG_METHOD`. It is here because Chrome ships a `scheduler`
|
|
118
|
+
* global in workers that DOES have `yield` and no `wait`, so a scope that
|
|
119
|
+
* replaced Chrome's and dropped `yield` would break page-shaped code that a
|
|
120
|
+
* Durable Object never runs but a shared worker global might. A zero-delay
|
|
121
|
+
* gated timer is the closest honest reading and it keeps the lock property.
|
|
122
|
+
*/
|
|
123
|
+
yield(): Promise<void>;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* ← `ServiceWorkerGlobalScope`'s `crypto`. The synchronous members are the
|
|
127
|
+
* platform's own; `subtle` is the gated one above.
|
|
128
|
+
*/
|
|
129
|
+
declare class GatedCrypto {
|
|
130
|
+
#private;
|
|
131
|
+
readonly subtle: SubtleCrypto;
|
|
132
|
+
constructor(requireOwnSlice: (op: string) => void, ctx: IoContext, crypto: Crypto);
|
|
133
|
+
getRandomValues<T extends ArrayBufferView | null>(array: T): T;
|
|
134
|
+
randomUUID(): `${string}-${string}-${string}-${string}-${string}`;
|
|
135
|
+
}
|
|
136
|
+
/** What the host supplies beneath `ServiceWorkerGlobalScope::fetch`. */
|
|
137
|
+
export type FetchPort = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
138
|
+
export type ActorGlobalScopeOptions = {
|
|
139
|
+
/** Opaque identity of the external entry whose synchronous body is running. */
|
|
140
|
+
readonly currentExternalEntry?: (() => object | undefined) | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* The `Crypto` the gated one delegates to. Defaults to the realm's own, which
|
|
143
|
+
* is what a host wants: unlike `fetch`, there is no per-actor outbound to
|
|
144
|
+
* route this through — `SubtleCrypto` is pure computation, and the only thing
|
|
145
|
+
* the actor's scope adds is the gate around its promise.
|
|
146
|
+
*/
|
|
147
|
+
readonly crypto?: Crypto | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* ← the global outbound `Fetcher` `ServiceWorkerGlobalScope::fetch` resolves
|
|
150
|
+
* (`global-scope.c++:1160`). Absent means this actor has no ambient outbound,
|
|
151
|
+
* which is upstream's `globalOutbound: null` posture (§1.11) — `fetch` then
|
|
152
|
+
* refuses by name rather than reaching a `fetch` this package does not own.
|
|
153
|
+
*/
|
|
154
|
+
readonly fetch?: FetchPort | undefined;
|
|
155
|
+
};
|
|
156
|
+
/** Thrown where `globalOutbound` is absent. Asserted rather than skipped, so it cannot drift. */
|
|
157
|
+
export declare const NO_GLOBAL_OUTBOUND_MESSAGE = "fetch(): this actor has no global outbound, so an ambient fetch cannot be gated.";
|
|
158
|
+
/**
|
|
159
|
+
* The message a scope answers with when it is reached from another actor's
|
|
160
|
+
* slice. Exported because the failure it names is the one thing about this layer
|
|
161
|
+
* that cannot be found by reading the calling code — see `requireOwnSlice`.
|
|
162
|
+
*/
|
|
163
|
+
export declare const FOREIGN_SLICE_MESSAGE: string;
|
|
164
|
+
/**
|
|
165
|
+
* ← `ServiceWorkerGlobalScope`, the async-primitive half. One per actor.
|
|
166
|
+
*
|
|
167
|
+
* A consumer installs this into whatever scope its actor's code reads —
|
|
168
|
+
* `globalThis` for a class in the worker's own module graph, a module-scoped
|
|
169
|
+
* binding for a class that arrived as a dynamically-loaded Worker source, which
|
|
170
|
+
* is upstream's own arrangement (a dynamic Worker has its own global scope bound
|
|
171
|
+
* to its own context, §1.11).
|
|
172
|
+
*/
|
|
173
|
+
export declare class ActorGlobalScope {
|
|
174
|
+
#private;
|
|
175
|
+
readonly scheduler: Scheduler;
|
|
176
|
+
readonly crypto: GatedCrypto;
|
|
177
|
+
constructor(ctx: IoContext, options?: ActorGlobalScopeOptions);
|
|
178
|
+
/** Opaque identity available only during an external entry's synchronous body. */
|
|
179
|
+
get currentExternalEntry(): object | undefined;
|
|
180
|
+
/** Re-enter this actor after a host promise settles. */
|
|
181
|
+
awaitIo<T>(promise: Promise<T>): Promise<T>;
|
|
182
|
+
/** ← `ServiceWorkerGlobalScope::setTimeout` (`global-scope.c++:944-950`). */
|
|
183
|
+
setTimeout(callback: (...args: never[]) => void, msDelay?: number, ...args: unknown[]): number;
|
|
184
|
+
/** ← `ServiceWorkerGlobalScope::clearTimeout` (`global-scope.c++:967-975`). */
|
|
185
|
+
clearTimeout(id?: number | null): void;
|
|
186
|
+
/** ← `ServiceWorkerGlobalScope::setInterval` (`global-scope.c++:959-965`). */
|
|
187
|
+
setInterval(callback: (...args: never[]) => void, msDelay?: number, ...args: unknown[]): number;
|
|
188
|
+
/** ← `ServiceWorkerGlobalScope::clearInterval`, which is `clearTimeout`'s own body. */
|
|
189
|
+
clearInterval(id?: number | null): void;
|
|
190
|
+
/**
|
|
191
|
+
* ← `ServiceWorkerGlobalScope::fetch` (`global-scope.h:703-705`) reaching
|
|
192
|
+
* `fetchImpl` (`http.c++:1740-1760`).
|
|
193
|
+
*
|
|
194
|
+
* Two gates, in upstream's order. The OUTPUT gate first, because an outbound
|
|
195
|
+
* request is exactly the observation §1.1 exists to hold back — "blocks all
|
|
196
|
+
* outgoing messages from an actor that would allow the rest of the world to
|
|
197
|
+
* observe the actor's state" — and `fetchImpl` waits on it before the request
|
|
198
|
+
* departs (`http.c++:1488`, `:1759`). The INPUT gate is released for the
|
|
199
|
+
* duration and re-taken on resumption, which is `awaitIo` and which is what
|
|
200
|
+
* makes an actor awaiting the network stay re-entrant (§1.3).
|
|
201
|
+
*/
|
|
202
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The bound form of `ActorGlobalScope`, which is what a scope object actually
|
|
206
|
+
* holds. Bound, because these are read as free variables — `setTimeout(…)`, not
|
|
207
|
+
* `scope.setTimeout(…)` — so a method that needed its receiver would break the
|
|
208
|
+
* moment it was destructured, which is exactly how a dynamically-loaded Worker
|
|
209
|
+
* source receives them.
|
|
210
|
+
*/
|
|
211
|
+
export type ActorScopeBindings = {
|
|
212
|
+
readonly awaitIo: <T>(promise: Promise<T>) => Promise<T>;
|
|
213
|
+
readonly scheduler: {
|
|
214
|
+
wait(delay: number, options?: SchedulerWaitOptions): Promise<void>;
|
|
215
|
+
yield(): Promise<void>;
|
|
216
|
+
};
|
|
217
|
+
readonly setTimeout: (callback: (...args: never[]) => void, msDelay?: number, ...args: unknown[]) => number;
|
|
218
|
+
readonly clearTimeout: (id?: number | null) => void;
|
|
219
|
+
readonly setInterval: (callback: (...args: never[]) => void, msDelay?: number, ...args: unknown[]) => number;
|
|
220
|
+
readonly clearInterval: (id?: number | null) => void;
|
|
221
|
+
readonly fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
222
|
+
readonly crypto: Crypto;
|
|
223
|
+
readonly currentExternalEntry?: object | undefined;
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* The capabilities an actor's code reads, bound to one scope.
|
|
227
|
+
*
|
|
228
|
+
* `resolve` is a thunk because the owner may change across root respawns, or a
|
|
229
|
+
* shared realm may select the actor whose synchronous slice is running. It is
|
|
230
|
+
* consulted only when an operation begins; it does not propagate identity
|
|
231
|
+
* across a promise continuation. Actor-owned code should retain its explicit
|
|
232
|
+
* scope instead. A single-actor host simply writes `() => scope`.
|
|
233
|
+
*/
|
|
234
|
+
export declare function actorScopeBindings(resolve: () => ActorGlobalScope): ActorScopeBindings;
|
|
235
|
+
/**
|
|
236
|
+
* Write the web-platform bindings onto a scope object — `globalThis` for a class in the worker's
|
|
237
|
+
* own module graph, a plain object a dynamically-loaded source destructures for
|
|
238
|
+
* one that is not.
|
|
239
|
+
*
|
|
240
|
+
* **A host should call this rather than assigning the names itself**, and the
|
|
241
|
+
* reason is the failure it prevents: a host that installs five of the six leaves
|
|
242
|
+
* one primitive ungated, and an ungated primitive that WORKS is invisible until
|
|
243
|
+
* a continuation after it touches storage — possibly never, on the path that
|
|
244
|
+
* matters. The set is the package's, so it can grow without every host growing
|
|
245
|
+
* with it.
|
|
246
|
+
*
|
|
247
|
+
* **It ASSIGNS, and that is not incidental.** Chrome ships a `scheduler` global
|
|
248
|
+
* in dedicated workers — the Prioritized Task Scheduling API, `postTask` and
|
|
249
|
+
* `yield`, no `wait` — so a host writing `??=` silently keeps Chrome's and every
|
|
250
|
+
* timer await fails somewhere else entirely with `scheduler.wait is not a
|
|
251
|
+
* function`. Measured on the browser conformance lane, and the extension meets
|
|
252
|
+
* the same global at cutover.
|
|
253
|
+
*
|
|
254
|
+
* **What a host must do first:** capture whatever raw timers its own substrate
|
|
255
|
+
* needs. Everything BELOW the runtime — a `Timer` port, a transport's own
|
|
256
|
+
* retries — has to keep the platform's, or arming a timeout goes through a
|
|
257
|
+
* timeout. That is not hypothetical: pointing the node lane at these primitives
|
|
258
|
+
* without capturing first produced `RangeError: Maximum call stack size
|
|
259
|
+
* exceeded` on the first row.
|
|
260
|
+
*/
|
|
261
|
+
export declare function installActorScope(target: object, resolve: () => ActorGlobalScope): void;
|
|
262
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ← workerd `src/workerd/api/http.{h,c++}` — the gating, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* `http.c++` is 2,400 lines of `Request`, `Response`, `Headers`, `Body`,
|
|
5
|
+
* `Fetcher` and the redirect machine. None of it is ported: the substrate ships
|
|
6
|
+
* all of it, to the same specification, and re-implementing WHATWG Fetch over
|
|
7
|
+
* `fetch` would be the feature-subset failure the porting philosophy describes,
|
|
8
|
+
* with a much larger surface than the eighty lines it saves.
|
|
9
|
+
*
|
|
10
|
+
* What the substrate's copy cannot have is the half that is not in the spec at
|
|
11
|
+
* all: **every asynchronous step of a fetch is an io-context operation**, so on
|
|
12
|
+
* workerd the code after `await res.json()` resumes holding an input lock the
|
|
13
|
+
* same way the code after `await fetch(…)` does. §1.3 is the whole of it —
|
|
14
|
+
* `api/http.c++` contains ten `awaitIo(` calls and zero
|
|
15
|
+
* `awaitIoWithInputLock`, so an outbound request releases the input gate and its
|
|
16
|
+
* continuation re-takes one.
|
|
17
|
+
*
|
|
18
|
+
* A `Response` is where that matters and where it is easiest to miss. `fetch`
|
|
19
|
+
* itself is one `awaitIo` in `api/global-scope.ts`, which is obvious; the body
|
|
20
|
+
* is a SECOND await, arbitrarily later, and a raw `Response` would resolve it
|
|
21
|
+
* from a promise this package does not own. The continuation would come back
|
|
22
|
+
* with an empty invocation stack and the next `ctx.storage` call would throw —
|
|
23
|
+
* divergence 147, arriving from a line that looks like it only parses JSON.
|
|
24
|
+
*
|
|
25
|
+
* Upstream reaches the same place by construction rather than by wrapping: a
|
|
26
|
+
* `Response`'s body is an `IoOwn<ReadableStream>`, and `IoOwn` is precisely "a
|
|
27
|
+
* thing that may only be touched from inside its IoContext"
|
|
28
|
+
* (`io-context.h`'s `IoOwn`/`IoPtr`/`DeleteQueue` block). There is no such
|
|
29
|
+
* ownership here — GC makes a cross-context dereference impossible in the way
|
|
30
|
+
* that block guards against, which is why the package does not port it — so the
|
|
31
|
+
* property it produced has to be produced by the wrapper below.
|
|
32
|
+
*
|
|
33
|
+
* Spec: §1.3 and decision 1 in
|
|
34
|
+
* docs/decisions.md.
|
|
35
|
+
*/
|
|
36
|
+
type IoAwaiter = {
|
|
37
|
+
awaitIo<T>(promise: Promise<T>): Promise<T>;
|
|
38
|
+
};
|
|
39
|
+
/** Wrap a host-provided request so consuming or streaming its body resumes gated. */
|
|
40
|
+
export declare function gateRequestBody(ctx: IoAwaiter, request: Request): Request;
|
|
41
|
+
/** Wrap an outbound response so consuming or streaming its body resumes gated. */
|
|
42
|
+
export declare function gateResponseBody(ctx: IoAwaiter, response: Response): Response;
|
|
43
|
+
/**
|
|
44
|
+
* ← the same property one layer down: a body read through `getReader()` is a
|
|
45
|
+
* sequence of awaits, so each `read()` is one.
|
|
46
|
+
*
|
|
47
|
+
* Only the default reader is covered. A BYOB reader is refused rather than
|
|
48
|
+
* passed through ungated — see `BYOB_READER_UNGATABLE_MESSAGE`.
|
|
49
|
+
*/
|
|
50
|
+
export declare const BYOB_READER_UNGATABLE_MESSAGE: string;
|
|
51
|
+
export declare function gateReadableStream<T>(ctx: IoAwaiter, stream: ReadableStream<T>): ReadableStream<T>;
|
|
52
|
+
export {};
|