@nimbus-sh/fabric 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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +487 -0
  3. package/dist/alarms.d.ts +134 -0
  4. package/dist/alarms.d.ts.map +1 -0
  5. package/dist/alarms.js +214 -0
  6. package/dist/bindings.d.ts +316 -0
  7. package/dist/bindings.d.ts.map +1 -0
  8. package/dist/bindings.js +678 -0
  9. package/dist/ctx-exports.d.ts +47 -0
  10. package/dist/ctx-exports.d.ts.map +1 -0
  11. package/dist/ctx-exports.js +54 -0
  12. package/dist/facet-image-store.d.ts +112 -0
  13. package/dist/facet-image-store.d.ts.map +1 -0
  14. package/dist/facet-image-store.js +181 -0
  15. package/dist/fanout-pool.d.ts +223 -0
  16. package/dist/fanout-pool.d.ts.map +1 -0
  17. package/dist/fanout-pool.js +368 -0
  18. package/dist/index.d.ts +26 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +25 -0
  21. package/dist/inner-do-registry.d.ts +41 -0
  22. package/dist/inner-do-registry.d.ts.map +1 -0
  23. package/dist/inner-do-registry.js +51 -0
  24. package/dist/launch-journal.d.ts +170 -0
  25. package/dist/launch-journal.d.ts.map +1 -0
  26. package/dist/launch-journal.js +154 -0
  27. package/dist/launch-pacer.d.ts +173 -0
  28. package/dist/launch-pacer.d.ts.map +1 -0
  29. package/dist/launch-pacer.js +193 -0
  30. package/dist/loader-ledger.d.ts +57 -0
  31. package/dist/loader-ledger.d.ts.map +1 -0
  32. package/dist/loader-ledger.js +91 -0
  33. package/dist/loader-pool.d.ts +315 -0
  34. package/dist/loader-pool.d.ts.map +1 -0
  35. package/dist/loader-pool.js +666 -0
  36. package/dist/process-fabric.d.ts +524 -0
  37. package/dist/process-fabric.d.ts.map +1 -0
  38. package/dist/process-fabric.js +388 -0
  39. package/dist/process-host.d.ts +132 -0
  40. package/dist/process-host.d.ts.map +1 -0
  41. package/dist/process-host.js +444 -0
  42. package/dist/vendor/errors.d.ts +24 -0
  43. package/dist/vendor/errors.d.ts.map +1 -0
  44. package/dist/vendor/errors.js +46 -0
  45. package/dist/vendor/serialize.d.ts +3 -0
  46. package/dist/vendor/serialize.d.ts.map +1 -0
  47. package/dist/vendor/serialize.js +25 -0
  48. package/dist/vendor/types.d.ts +69 -0
  49. package/dist/vendor/types.d.ts.map +1 -0
  50. package/dist/vendor/types.js +4 -0
  51. package/dist/workerd-facet-host.d.ts +207 -0
  52. package/dist/workerd-facet-host.d.ts.map +1 -0
  53. package/dist/workerd-facet-host.js +508 -0
  54. package/dist/ws-hibernation-config.d.ts +73 -0
  55. package/dist/ws-hibernation-config.d.ts.map +1 -0
  56. package/dist/ws-hibernation-config.js +93 -0
  57. package/package.json +62 -0
  58. package/src/alarms.ts +275 -0
  59. package/src/bindings.ts +871 -0
  60. package/src/ctx-exports.ts +77 -0
  61. package/src/facet-image-store.ts +196 -0
  62. package/src/fanout-pool.ts +503 -0
  63. package/src/index.ts +26 -0
  64. package/src/inner-do-registry.ts +58 -0
  65. package/src/launch-journal.ts +229 -0
  66. package/src/launch-pacer.ts +231 -0
  67. package/src/loader-ledger.ts +112 -0
  68. package/src/loader-pool.ts +984 -0
  69. package/src/process-fabric.ts +729 -0
  70. package/src/process-host.ts +566 -0
  71. package/src/vendor/errors.ts +56 -0
  72. package/src/vendor/serialize.ts +37 -0
  73. package/src/vendor/types.ts +75 -0
  74. package/src/workerd-facet-host.ts +694 -0
  75. package/src/ws-hibernation-config.ts +123 -0
package/dist/alarms.js ADDED
@@ -0,0 +1,214 @@
1
+ /**
2
+ * alarms.ts — Durable Object alarm multiplexing + isolate-generation
3
+ * machinery, persisted across hibernation.
4
+ *
5
+ * Workerd hibernates Durable Objects between requests to free memory. On
6
+ * wake, the new isolate must rebuild its in-memory state from SQL — but it
7
+ * also needs to know "is this the same lifecycle as before, or did workerd
8
+ * recycle me?" That distinction matters for recovery (warmJoin vs cold init)
9
+ * and is captured by the isolate generation, a counter persisted across
10
+ * hibernations.
11
+ *
12
+ * A Durable Object has ONE alarm, and a second `setAlarm()` silently
13
+ * overwrites the first — so every alarm-driven subsystem coordinates through
14
+ * a single reason→deadline map and one dispatcher. Reasons are plain strings
15
+ * registered by the embedder: `scheduleAlarm` arms one, and `dispatchAlarm`
16
+ * runs the embedder-supplied handler for every reason whose deadline has
17
+ * passed.
18
+ */
19
+ import { errorText } from '@nimbus-sh/core/_shared/error-text.js';
20
+ /**
21
+ * Multi-reason alarm coordination map.
22
+ *
23
+ * JSON-serialised `Record<reason, deadlineMsEpoch>` where keys are the
24
+ * embedder's canonical reason strings (e.g. 'w9-flush', 'log-janitor'). The
25
+ * alarm() dispatcher reads this on fire, dispatches every reason whose
26
+ * deadline has passed, and re-arms `ctx.storage.setAlarm` at the earliest
27
+ * remaining deadline.
28
+ *
29
+ * Why a map (not a single nextAlarmAt + reason): two subsystems can have
30
+ * distinct deadlines. Without the map, the later setAlarm() call would
31
+ * overwrite the earlier reason silently, breaking whichever subsystem
32
+ * expected its deadline.
33
+ *
34
+ * Forward-compat: the dispatcher silently drops unknown reasons so a
35
+ * rollback from a future deploy that added new reasons doesn't leave the
36
+ * alarm stuck.
37
+ *
38
+ * The VALUE is live production DO storage ('w1_next_alarm_reasons', from the
39
+ * workstream that introduced it) and must never change — renaming a storage
40
+ * key is a migration, and orphaned rows are the least of what it breaks.
41
+ */
42
+ export const ALARM_REASONS_KEY = 'w1_next_alarm_reasons';
43
+ /**
44
+ * Storage key for the isolate-generation counter (cold-start +
45
+ * post-hibernation wake; one increment per fresh isolate).
46
+ *
47
+ * The VALUE is live production DO storage ('w9_isolate_gen') and must never
48
+ * change, same contract as {@link ALARM_REASONS_KEY}.
49
+ */
50
+ export const ISOLATE_GEN_KEY = 'w9_isolate_gen';
51
+ /**
52
+ * Schedule (or re-schedule) an alarm reason. Coordinated via a single map in
53
+ * DO storage so multiple subsystems don't clobber each other's `setAlarm()`
54
+ * calls.
55
+ *
56
+ * Semantics:
57
+ * - Reads the existing reasons map.
58
+ * - Sets `map[reason] = whenMs` IF `whenMs` is sooner than the
59
+ * currently-pending deadline for that reason (or no entry exists).
60
+ * Later-than-pending requests are silently ignored — the existing
61
+ * alarm will fire and re-arm anyway.
62
+ * - Writes the map back and calls `ctx.storage.setAlarm(min(deadlines))`.
63
+ *
64
+ * Cost: 1 storage read + 1 storage write + 1 setAlarm per call. setAlarm
65
+ * itself is billed as 1 row written per DO pricing. At a 60s janitor
66
+ * cadence, this is ~$0.05/mo/session at scale — dwarfed by the
67
+ * hibernation duration savings.
68
+ *
69
+ * Fail-soft: any throw is swallowed with a warn. On older runtimes /
70
+ * wrangler-dev where setAlarm is unavailable, this is a no-op (the
71
+ * subsystem's in-isolate setTimeout fallback continues to work).
72
+ */
73
+ export function scheduleAlarm(host, ctx, reason, whenMs) {
74
+ // Serialize every read-modify-write of the reasons map through one
75
+ // per-instance chain: two schedulers firing back-to-back from one activity
76
+ // hook would otherwise interleave their get→put cycles and silently drop
77
+ // whichever reason wrote first.
78
+ const run = async () => {
79
+ try {
80
+ const setAlarmFn = ctx?.storage?.setAlarm;
81
+ if (typeof setAlarmFn !== 'function')
82
+ return false;
83
+ const existing = (await ctx.storage.get(ALARM_REASONS_KEY));
84
+ const map = { ...(existing || {}) };
85
+ // Earliest-deadline-first: only update if new request is sooner or
86
+ // this reason has no pending entry.
87
+ if (!(reason in map) || whenMs < map[reason]) {
88
+ map[reason] = whenMs;
89
+ await ctx.storage.put(ALARM_REASONS_KEY, map);
90
+ }
91
+ const earliest = Math.min(...Object.values(map));
92
+ setAlarmFn.call(ctx.storage, earliest);
93
+ return true;
94
+ }
95
+ catch (e) {
96
+ console.warn('[nimbus/W1] scheduleAlarm threw:', errorText(e));
97
+ return false;
98
+ }
99
+ };
100
+ const chained = (host._alarmChain ?? Promise.resolve()).then(run, run);
101
+ host._alarmChain = chained;
102
+ return chained;
103
+ }
104
+ /**
105
+ * Multi-reason alarm dispatcher. Called from the DO's `alarm()` handler with
106
+ * the embedder's handler map.
107
+ *
108
+ * For each pending reason whose deadline has passed, run its handler.
109
+ * Handlers are awaited in place: the alarm invocation is the fresh turn a
110
+ * re-entering subsystem asked for, and it has to stay the one paying for the
111
+ * work it just released.
112
+ *
113
+ * After running fireable reasons, re-arms `ctx.storage.setAlarm` at the
114
+ * earliest remaining deadline. If no reasons remain, deletes the map key and
115
+ * does NOT call setAlarm — the DO becomes hibernation-eligible after the 10s
116
+ * idle window.
117
+ *
118
+ * Forward/back-compat: unknown reasons silently dropped. `onLegacyAlarm`
119
+ * covers an alarm that fires with no map at all — a deploy from before the
120
+ * map existed left a bare `setAlarm` behind, and the embedder decides what
121
+ * that one-time fire means (one dispatch later the map is populated by the
122
+ * next scheduleAlarm call).
123
+ */
124
+ export function dispatchAlarm(host, ctx, handlers, onLegacyAlarm) {
125
+ // Same serialization as scheduleAlarm: the dispatcher's read→handlers→write
126
+ // cycle must not interleave with an activity-hook scheduleAlarm.
127
+ const chained = (host._alarmChain ?? Promise.resolve()).then(() => dispatchAlarmBody(ctx, handlers, onLegacyAlarm), () => dispatchAlarmBody(ctx, handlers, onLegacyAlarm));
128
+ host._alarmChain = chained;
129
+ return chained;
130
+ }
131
+ async function dispatchAlarmBody(ctx, handlers, onLegacyAlarm) {
132
+ try {
133
+ const now = Date.now();
134
+ const existing = (await ctx?.storage?.get?.(ALARM_REASONS_KEY));
135
+ if (!existing || Object.keys(existing).length === 0) {
136
+ onLegacyAlarm?.();
137
+ return;
138
+ }
139
+ const map = { ...existing };
140
+ // Snapshot fireable reasons BEFORE running any of them, so a
141
+ // handler that schedules itself for the next cycle doesn't get
142
+ // immediately re-fired in the same dispatch.
143
+ const fired = [];
144
+ for (const [reason, when] of Object.entries(map)) {
145
+ if (when <= now)
146
+ fired.push(reason);
147
+ }
148
+ for (const reason of fired) {
149
+ delete map[reason];
150
+ const handler = handlers[reason];
151
+ // Unknown reasons silently dropped (forward-compat).
152
+ if (!handler)
153
+ continue;
154
+ try {
155
+ const result = await handler(now);
156
+ if (result && typeof result.rearmAt === 'number') {
157
+ map[reason] = result.rearmAt;
158
+ }
159
+ }
160
+ catch (e) {
161
+ console.warn(`[nimbus/W1] dispatch ${reason} threw:`, errorText(e));
162
+ }
163
+ }
164
+ // Re-arm or clear.
165
+ const setAlarmFn = ctx?.storage?.setAlarm;
166
+ if (Object.keys(map).length > 0) {
167
+ await ctx.storage.put(ALARM_REASONS_KEY, map);
168
+ const earliest = Math.min(...Object.values(map));
169
+ if (typeof setAlarmFn === 'function') {
170
+ setAlarmFn.call(ctx.storage, earliest);
171
+ }
172
+ }
173
+ else {
174
+ try {
175
+ await ctx.storage.delete(ALARM_REASONS_KEY);
176
+ }
177
+ catch { }
178
+ // No remaining reasons → no setAlarm call → DO becomes
179
+ // hibernation-eligible after the 10s idle window.
180
+ }
181
+ }
182
+ catch (e) {
183
+ console.warn('[nimbus/W1] dispatchAlarm threw:', errorText(e));
184
+ }
185
+ }
186
+ /** Increment + persist the isolate-gen counter once per fresh isolate. */
187
+ export async function maybeBumpIsolateGen(host, ctx) {
188
+ if (host._isolateGenPersisted)
189
+ return;
190
+ host._isolateGenPersisted = true;
191
+ try {
192
+ const prev = (await ctx.storage.get(ISOLATE_GEN_KEY));
193
+ // Adopt the persisted truth first, and adopt the bump only after the
194
+ // put resolves. An unpersisted `next` would be re-read as `prev` by the
195
+ // NEXT boot and re-issued — two instances sharing one generation is
196
+ // exactly the pid-aliasing this counter exists to prevent. Running on
197
+ // the previous persisted generation is the lesser lapse, and the
198
+ // put-failure case is replica-only in practice (replicas never spawn).
199
+ //
200
+ // What holds the guarantee is the output gate, not this await: measured,
201
+ // the block body resolves in 0 ms even with a confirmed put, because
202
+ // `await storage.put()` returns before durability. The gate is what
203
+ // keeps a pid from generation N from escaping before N is durable, which
204
+ // is why marking this put `allowUnconfirmed` is not a free speedup — see
205
+ // scratchpad/coldstart-s1.md.
206
+ host._isolateGen = typeof prev === 'number' ? prev : 0;
207
+ const next = host._isolateGen + 1;
208
+ await ctx.storage.put(ISOLATE_GEN_KEY, next);
209
+ host._isolateGen = next;
210
+ }
211
+ catch (e) {
212
+ console.warn('[nimbus/W9] isolate-gen bump failed:', errorText(e));
213
+ }
214
+ }
@@ -0,0 +1,316 @@
1
+ /**
2
+ * session/bindings.ts — Inner-Worker + assets binding shims (W10).
3
+ *
4
+ * `nimbus-wrangler dev` runs a USER worker as a child process. That
5
+ * child needs working `env` bindings (env.ASSETS, env.LOADER, env.MY_DO,
6
+ * etc.) but the DO's `env` belongs to the supervisor's contract — we
7
+ * can't pass it through directly. Workerd's enable_ctx_exports
8
+ * (compat date 2026-04-01+) auto-populates Service Bindings from
9
+ * top-level WorkerEntrypoint classes; these classes ARE those entry
10
+ * points. They forward each binding kind back to the supervisor DO via
11
+ * RPC stub (`env.NIMBUS_SESSION.idFromString(doId).get()...`).
12
+ *
13
+ * The shims have NO interaction with NimbusSession internals except
14
+ * through that RPC stub. Co-located here for grep-ability.
15
+ *
16
+ * NimbusAssetsRPC, NimbusLoaderRPC, NimbusLoadedWorker,
17
+ * NimbusLoadedEntrypoint, NimbusDurableObjectNamespace and NimbusDOStub are
18
+ * public API of the embedder's Worker: wrangler resolves them by class name
19
+ * and ctx.exports auto-populates them by export name, so the embedder's entry
20
+ * module re-exports them under exactly these names.
21
+ *
22
+ * Bundle-graph note: these classes must remain reachable from the embedder's
23
+ * entry module for Wrangler to bundle the WorkerEntrypoint exports.
24
+ */
25
+ import { WorkerEntrypoint } from 'cloudflare:workers';
26
+ import { z } from 'zod/v4';
27
+ import type { WorkerCode } from './vendor/types.js';
28
+ /**
29
+ * The supervisor DO namespace a shim resolves ONE stub from, by the id its
30
+ * props carry. `Stub` is that DO's RPC surface as the calling shim uses it —
31
+ * the supervisor class belongs to the embedder, so each shim names the methods
32
+ * it calls rather than the class.
33
+ */
34
+ interface SupervisorNamespace<Stub> {
35
+ idFromString(id: string): DurableObjectId;
36
+ get(id: DurableObjectId): Stub;
37
+ }
38
+ /**
39
+ * A dynamic worker's entrypoint, as hop 3 relays to it. `fetch` is the
40
+ * entrypoint contract every loaded worker answers; `handleHttpRequest` is the
41
+ * fabric's own route target, which only a facet that serves ports exposes.
42
+ */
43
+ interface LoadedEntrypoint {
44
+ fetch(request: Request): Promise<Response>;
45
+ handleHttpRequest?(request: Request): Promise<Response>;
46
+ }
47
+ /** A stub for one dynamically-loaded worker, as the shims hop across it. */
48
+ interface LoadedWorker {
49
+ getEntrypoint(name?: string): LoadedEntrypoint;
50
+ getDurableObjectClass(name: string): DurableObjectClass;
51
+ }
52
+ /**
53
+ * The OUTER `env.LOADER` these shims forward to. `load` is the unkeyed arm the
54
+ * inner Worker asked for; `get` is the keyed arm every later hop re-enters in
55
+ * its own request context. `get`'s callback answers with whatever the caller
56
+ * assembled — a staged artifact's module map is the embedder's, so the fabric
57
+ * does not name it (see {@link ./process-fabric.js} StagedBootAssembler).
58
+ */
59
+ interface OuterWorkerLoader {
60
+ load(code: WorkerCode): LoadedWorker;
61
+ get(id: string, getCode: () => Promise<object>): LoadedWorker;
62
+ }
63
+ /**
64
+ * `env` for the three Worker-Loader hops. The depth var rides the env rather
65
+ * than props because it is set on the OUTERMOST session and every nested
66
+ * Nimbus inherits it.
67
+ */
68
+ interface NimbusLoaderShimEnv {
69
+ LOADER?: OuterWorkerLoader;
70
+ NIMBUS_INNER_LOADER_DEPTH?: string;
71
+ }
72
+ /**
73
+ * What the assets shim reads off the supervisor DO: the VFS bytes of one path,
74
+ * or null when it holds no such file.
75
+ */
76
+ interface AssetsSupervisorStub {
77
+ _rpcReadFileBytes(path: string): Promise<ArrayBuffer | Uint8Array | null>;
78
+ }
79
+ /** `env` for the assets shim: the supervisor its VFS reads round-trip through. */
80
+ interface NimbusAssetsEnv {
81
+ NIMBUS_SESSION?: SupervisorNamespace<AssetsSupervisorStub>;
82
+ }
83
+ /** Props the assets shim is minted with. */
84
+ interface NimbusAssetsProps {
85
+ /** Project root in VFS (e.g. "home/user/myapp"). */
86
+ vfsRoot?: string;
87
+ /** Directory declared in wrangler.jsonc.assets.directory. */
88
+ assetsDir?: string;
89
+ /** Supervisor DO id whose VFS holds the assets. */
90
+ doId?: string;
91
+ }
92
+ /**
93
+ * Assets binding shim. The inner Worker calls `env.ASSETS.fetch(request)`
94
+ * and we serve the file from VFS under `<vfsRoot>/<assetsDir>/<pathname>`.
95
+ *
96
+ * Props (passed via ctx.props when this binding is constructed):
97
+ * vfsRoot — project root in VFS (e.g. "home/user/myapp")
98
+ * assetsDir — directory declared in wrangler.jsonc.assets.directory
99
+ * (e.g. "./public" → we trim the leading ./)
100
+ *
101
+ * The hostname on the incoming Request is irrelevant (Workers Assets
102
+ * convention); only pathname matters. Path traversal (`..`) is clamped.
103
+ * Directories resolve to their `index.html` child; missing files fall
104
+ * back to the assetsDir root `index.html` (SPA convention), then 404.
105
+ *
106
+ * The VFS is read from the supervisor DO via the class property
107
+ * `_nimbusVfsResolver` set by NimbusSession at construction. WorkerEntrypoint
108
+ * instances don't have direct access to the supervisor's SqliteVFS, so we
109
+ * reach it through the supervisor stub (env.NIMBUS_SESSION.idFromString).
110
+ * For Phase 1, we use a simpler approach: the props carry a supervisor
111
+ * DO id so we can round-trip through an RPC method that reads the file.
112
+ */
113
+ export declare class NimbusAssetsRPC extends WorkerEntrypoint<NimbusAssetsEnv, NimbusAssetsProps> {
114
+ /**
115
+ * Fetch a static asset. Called by the inner Worker as
116
+ * `env.ASSETS.fetch(request)`. The request URL's pathname is used to
117
+ * resolve a file under the configured assets directory.
118
+ */
119
+ fetch(request: Request): Promise<Response>;
120
+ }
121
+ declare const NimbusLoadedEntrypointPropsSchema: z.ZodObject<{
122
+ key: z.ZodString;
123
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
124
+ depth: z.ZodOptional<z.ZodNumber>;
125
+ supervisor: z.ZodOptional<z.ZodObject<{
126
+ doId: z.ZodString;
127
+ pid: z.ZodNumber;
128
+ writerId: z.ZodString;
129
+ }, z.core.$strip>>;
130
+ stage: z.ZodOptional<z.ZodUnknown>;
131
+ }, z.core.$loose>;
132
+ type NimbusLoadedEntrypointProps = z.infer<typeof NimbusLoadedEntrypointPropsSchema>;
133
+ /**
134
+ * Diagnostic surface for /api/_diag/memory. Returns a snapshot of
135
+ * the Map state — entry count, configured cap, eviction counter
136
+ * since isolate boot. Pure read; no I/O.
137
+ */
138
+ export declare function getLoadedCodesStats(): {
139
+ entries: number;
140
+ maxEntries: number;
141
+ evictions: number;
142
+ };
143
+ /** Props every Worker-Loader hop carries: how deep this Nimbus already is. */
144
+ interface NimbusLoaderDepthProps {
145
+ depth?: number;
146
+ }
147
+ /** Hop 1: env.LOADER.{load,get} forwarded to the outer loader. */
148
+ export declare class NimbusLoaderRPC extends WorkerEntrypoint<NimbusLoaderShimEnv, NimbusLoaderDepthProps> {
149
+ private _currentDepth;
150
+ private _maxDepth;
151
+ private _assertDepthOk;
152
+ /**
153
+ * Inner: env.LOADER.load(code). Stashes the CODE (not a stub — stubs
154
+ * are I/O-bound to the calling request context) and returns a
155
+ * NimbusLoadedWorker RPC stub. Each downstream call re-loads the
156
+ * worker in its own request context via LOADER.get(key, cb).
157
+ */
158
+ load(code: WorkerCode): unknown;
159
+ /**
160
+ * Inner: env.LOADER.get(id, callback). The inner's callback returns
161
+ * a code object; we treat `id` as the outer cache key (prefixed so
162
+ * it doesn't collide with load()-generated keys).
163
+ */
164
+ get(id: string, callback: () => WorkerCode | Promise<WorkerCode>): Promise<unknown>;
165
+ }
166
+ /** Props hop 2 carries: the stashed code it re-loads, and its inherited depth. */
167
+ interface NimbusLoadedWorkerProps extends NimbusLoaderDepthProps {
168
+ key?: string;
169
+ }
170
+ /** Hop 2: the returned "worker" stub. Exposes .getEntrypoint(). */
171
+ export declare class NimbusLoadedWorker extends WorkerEntrypoint<NimbusLoaderShimEnv, NimbusLoadedWorkerProps> {
172
+ /**
173
+ * Returns a NimbusLoadedEntrypoint stub that carries the code key +
174
+ * entrypoint name forward. The actual outer-side load + fetch happens
175
+ * inside NimbusLoadedEntrypoint.fetch() so all outer hops run in a
176
+ * SINGLE outer request context (the cross-request-I/O limitation is
177
+ * real — stubs created in one outer request can't be used by another).
178
+ */
179
+ getEntrypoint(name?: string): unknown;
180
+ /**
181
+ * Pass-through to outer worker.getDurableObjectClass(name). The
182
+ * returned stub is tied to THIS method's outer request context; if
183
+ * the caller (the inner worker) uses the class in a later request
184
+ * it will fail the cross-request-I/O check. For Phase 3 DO binding
185
+ * synthesis we resolve classes directly from nimbus-wrangler's own
186
+ * request context (which is the build-time context), not through
187
+ * this method.
188
+ */
189
+ getDurableObjectClass(name: string): DurableObjectClass;
190
+ }
191
+ /** Hop 3: a named-or-default entrypoint. Exposes .fetch(). */
192
+ export declare class NimbusLoadedEntrypoint extends WorkerEntrypoint<NimbusLoaderShimEnv, NimbusLoadedEntrypointProps> {
193
+ _props(): NimbusLoadedEntrypointProps;
194
+ _supervisorBinding(props: NimbusLoadedEntrypointProps): Promise<unknown>;
195
+ _resolveEntrypoint(): Promise<LoadedEntrypoint>;
196
+ /**
197
+ * Relay the inner entrypoint's Response to the caller with a LIVE body.
198
+ * The body streams through an identity pipe and the entrypoint stub is
199
+ * disposed only once the body finishes — materializing (arrayBuffer) here
200
+ * buffered every routed response to stream-end, which froze SSE/chunked
201
+ * bodies (an agent server's /event live-sync, `curl -N` loopback, external
202
+ * preview) until the facet closed the stream.
203
+ */
204
+ private _relayNestedRpcResponse;
205
+ /**
206
+ * Invoke the facet's HTTP handler.
207
+ *
208
+ * The call must be written as `ep.method(request)`. An RPC stub's method is a
209
+ * JsRpcProperty, whose every property access is a WILDCARD that extends a
210
+ * pipelined path (`JSG_WILDCARD_PROPERTY`, workerd api/worker-rpc.h) — so
211
+ * `method.call(ep, request)` does NOT reach Function.prototype.call. It builds
212
+ * the path `handleHttpRequest.call` and invokes it remotely with `ep` as its
213
+ * first ARGUMENT. Serializing `ep` — an entrypoint to a dynamically-loaded
214
+ * worker — is what workerd refuses:
215
+ *
216
+ * DataCloneError: Entrypoints to dynamically-loaded workers cannot be
217
+ * transferred to other Workers
218
+ *
219
+ * (server.c++ `requireAllowsTransfer` → `throwDynamicEntrypointTransferError`).
220
+ * The facet is never entered, because the failure is in serializing the
221
+ * arguments, before the call is delivered.
222
+ */
223
+ private _callHttpHandler;
224
+ handleHttpRequest(request: Request): Promise<Response>;
225
+ /**
226
+ * Forward fetch() to the outer worker's entrypoint. All three outer
227
+ * hops (load → getEntrypoint → fetch) run in the same outer request
228
+ * context (this method's invocation), which sidesteps the
229
+ * cross-request-I/O limitation.
230
+ */
231
+ fetch(request: Request): Promise<Response>;
232
+ }
233
+ /** Props the synthesized namespace carries: which binding, on which supervisor. */
234
+ interface NimbusDoNamespaceProps {
235
+ bindingName?: string;
236
+ supervisorDoId?: string;
237
+ }
238
+ /**
239
+ * `env.MY_DO` shim — a DurableObjectNamespace-like WorkerEntrypoint.
240
+ *
241
+ * Usage from inner Worker:
242
+ * const id = await env.MY_DO.idFromName('x'); // AWAIT required
243
+ * const stub = env.MY_DO.get(id);
244
+ * await stub.fetch(request);
245
+ *
246
+ * IMPORTANT: unlike the real DurableObjectNamespace, idFromName /
247
+ * newUniqueId / idFromString here return **Promises**, because they're
248
+ * RPC-backed WorkerEntrypoint methods. The inner caller MUST `await`
249
+ * them before passing the result to `.get()`. Workers RPC pipelining
250
+ * does not currently allow passing an RpcPromise as a method argument
251
+ * — the no-await form fails with:
252
+ * "Could not serialize object of type \"RpcPromise\"."
253
+ *
254
+ * Typical real-Worker code written for Cloudflare's synchronous
255
+ * DurableObjectNamespace needs a one-word change (add `await`).
256
+ *
257
+ * idFromName produces prefix `name:` (deterministic FNV-style hash);
258
+ * newUniqueId uses `uniq:` (random). The prefixes keep the two id
259
+ * spaces distinct so a name-derived id can't collide with a random
260
+ * one.
261
+ */
262
+ export declare class NimbusDurableObjectNamespace extends WorkerEntrypoint<unknown, NimbusDoNamespaceProps> {
263
+ /** Stable string id derived from a name. Hash is deterministic. */
264
+ idFromName(name: string): string;
265
+ /** Fresh random id (matches DurableObjectNamespace.newUniqueId()). */
266
+ newUniqueId(): string;
267
+ /** Accept-through for an already-formatted id. */
268
+ idFromString(s: string): string;
269
+ /** Return a stub bound to the given id. */
270
+ get(id: string): unknown;
271
+ }
272
+ /**
273
+ * What the DO shim reads off the supervisor: one inner-DO request, answered
274
+ * from the facet the supervisor resolves in its own request context.
275
+ */
276
+ interface InnerDoSupervisorStub {
277
+ _rpcInnerDoFetch(request: {
278
+ bindingName: string;
279
+ id: string;
280
+ method: string;
281
+ url: string;
282
+ headers: [string, string][];
283
+ body: ArrayBuffer | null;
284
+ }): Promise<{
285
+ body: ArrayBuffer;
286
+ status: number;
287
+ statusText: string;
288
+ headers: [string, string][];
289
+ }>;
290
+ }
291
+ /** `env` for the DO shim: the supervisor that owns the facet. */
292
+ interface NimbusInnerDoEnv {
293
+ NIMBUS_SESSION?: SupervisorNamespace<InnerDoSupervisorStub>;
294
+ }
295
+ /** Props the DO stub carries: which binding, which supervisor, which id. */
296
+ interface NimbusDoStubProps extends NimbusDoNamespaceProps {
297
+ id?: string;
298
+ }
299
+ /**
300
+ * A Durable-Object-namespace-stub for a specific id. Exposes fetch()
301
+ * and will, if we later need it, forward RPC method calls through a
302
+ * dispatch helper. The important invariant: EVERY call resolves the
303
+ * inner DO class via getInnerDoClass() (./inner-do-registry.js) and
304
+ * spins up / attaches to a facet via the supervisor's ctx.facets in
305
+ * the SAME outer request context — never reusing stubs across requests.
306
+ */
307
+ export declare class NimbusDOStub extends WorkerEntrypoint<NimbusInnerDoEnv, NimbusDoStubProps> {
308
+ /**
309
+ * Resolve the supervisor DO from env.NIMBUS_SESSION and route through
310
+ * its _rpcInnerDoFetch RPC method, which runs ctx.facets.get(...) in
311
+ * its own context and forwards the request.
312
+ */
313
+ fetch(request: Request): Promise<Response>;
314
+ }
315
+ export {};
316
+ //# sourceMappingURL=bindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../src/bindings.ts"],"names":[],"mappings":"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"}