@nimbus-sh/worker 0.2.3 → 0.4.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 (146) hide show
  1. package/dist/_shared/session-router.d.ts +8 -0
  2. package/dist/_shared/session-router.d.ts.map +1 -1
  3. package/dist/_shared/session-router.js +8 -0
  4. package/dist/esbuild-wasm-bundle.generated.d.ts +1 -1
  5. package/dist/esbuild-wasm-bundle.generated.js +1 -1
  6. package/dist/facets/cirrus-real.js +1 -1
  7. package/dist/facets/manager.d.ts +43 -129
  8. package/dist/facets/manager.d.ts.map +1 -1
  9. package/dist/facets/manager.js +107 -318
  10. package/dist/facets/opencode-staging.d.ts +1 -1
  11. package/dist/facets/opencode-staging.d.ts.map +1 -1
  12. package/dist/facets/opencode-staging.js +3 -0
  13. package/dist/facets/real-vite-hmr.js +1 -1
  14. package/dist/facets/vite-dev-server.d.ts +4 -4
  15. package/dist/facets/vite-dev-server.js +5 -5
  16. package/dist/git/commands.d.ts +8 -0
  17. package/dist/git/commands.d.ts.map +1 -1
  18. package/dist/git/commands.js +41 -9
  19. package/dist/git/network-facet.d.ts +1 -1
  20. package/dist/git/network-facet.d.ts.map +1 -1
  21. package/dist/git/network-facet.js +39 -15
  22. package/dist/git-bundle.generated.d.ts +2 -2
  23. package/dist/git-bundle.generated.d.ts.map +1 -1
  24. package/dist/git-bundle.generated.js +3 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +9 -1
  27. package/dist/loaders/child-process/spawn-facet.js +1 -1
  28. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  29. package/dist/loaders/child-process/spawn-pool.js +2 -2
  30. package/dist/loaders/generated-workers.d.ts +2 -2
  31. package/dist/loaders/generated-workers.d.ts.map +1 -1
  32. package/dist/loaders/generated-workers.js +3 -3
  33. package/dist/loaders/npm-resolve-preamble.d.ts +3 -3
  34. package/dist/loaders/npm-resolve-preamble.js +3 -3
  35. package/dist/loaders/pre-bundle-preamble.d.ts +5 -5
  36. package/dist/loaders/pre-bundle-preamble.js +6 -6
  37. package/dist/loaders/process-host.d.ts +6 -107
  38. package/dist/loaders/process-host.d.ts.map +1 -1
  39. package/dist/loaders/process-host.js +6 -405
  40. package/dist/npm/install-batch-facet.d.ts +1 -1
  41. package/dist/npm/install-batch-facet.js +1 -1
  42. package/dist/npm/installer.d.ts +6 -6
  43. package/dist/npm/installer.d.ts.map +1 -1
  44. package/dist/npm/installer.js +28 -27
  45. package/dist/npm/pre-bundle-facet.d.ts +2 -2
  46. package/dist/npm/pre-bundle-facet.js +5 -5
  47. package/dist/npm/r2-cache.d.ts +1 -1
  48. package/dist/npm/resolve-facet.d.ts +1 -1
  49. package/dist/npm/resolve-facet.js +1 -1
  50. package/dist/npm/resolve-one-facet.d.ts +5 -5
  51. package/dist/npm/resolve-one-facet.js +5 -5
  52. package/dist/router/index.js +2 -2
  53. package/dist/router/remote-api.js +9 -1
  54. package/dist/runtime/bun-repl.d.ts +1 -1
  55. package/dist/runtime/bun-repl.js +3 -3
  56. package/dist/runtime/esbuild-wasm-bytes.js +1 -1
  57. package/dist/runtime/facet-loader-host.d.ts +5 -8
  58. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  59. package/dist/runtime/facet-loader-host.js +7 -11
  60. package/dist/runtime/node-repl.js +2 -2
  61. package/dist/runtime/node-shims-artifact.js +1 -1
  62. package/dist/runtime/node-shims.js +2 -1
  63. package/dist/runtime/opencode-artifact.js +1 -1
  64. package/dist/runtime/opentui-wasm-bytes.js +1 -1
  65. package/dist/runtime/python-repl.js +3 -3
  66. package/dist/runtime/ruby-repl.js +2 -2
  67. package/dist/runtime/ruby-resident.js +1 -1
  68. package/dist/runtime/sqlite-wasm-bytes.js +1 -1
  69. package/dist/session/diag.js +1 -1
  70. package/dist/session/hibernation.d.ts +20 -53
  71. package/dist/session/hibernation.d.ts.map +1 -1
  72. package/dist/session/hibernation.js +57 -194
  73. package/dist/session/init-phases.d.ts +2 -3
  74. package/dist/session/init-phases.d.ts.map +1 -1
  75. package/dist/session/init-phases.js +3 -2
  76. package/dist/session/init.d.ts.map +1 -1
  77. package/dist/session/init.js +8 -4
  78. package/dist/session/keys.d.ts +14 -37
  79. package/dist/session/keys.d.ts.map +1 -1
  80. package/dist/session/keys.js +18 -37
  81. package/dist/session/nimbus-session.d.ts +10 -15
  82. package/dist/session/nimbus-session.d.ts.map +1 -1
  83. package/dist/session/nimbus-session.js +28 -31
  84. package/dist/session/port-capability.d.ts +43 -0
  85. package/dist/session/port-capability.d.ts.map +1 -0
  86. package/dist/session/port-capability.js +49 -0
  87. package/dist/session/programmatic.d.ts +39 -5
  88. package/dist/session/programmatic.d.ts.map +1 -1
  89. package/dist/session/programmatic.js +150 -19
  90. package/dist/session/routes.d.ts +2 -0
  91. package/dist/session/routes.d.ts.map +1 -1
  92. package/dist/session/routes.js +96 -20
  93. package/dist/session/rpc.d.ts +36 -9
  94. package/dist/session/rpc.d.ts.map +1 -1
  95. package/dist/session/rpc.js +84 -24
  96. package/dist/session/start-real-vite.d.ts.map +1 -1
  97. package/dist/session/start-real-vite.js +3 -1
  98. package/dist/session/state-store.d.ts +3 -2
  99. package/dist/session/state-store.d.ts.map +1 -1
  100. package/dist/session/state-store.js +3 -2
  101. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  102. package/dist/session/supervisor-rpc.js +7 -4
  103. package/dist/session/ws.d.ts +1 -3
  104. package/dist/session/ws.d.ts.map +1 -1
  105. package/dist/session/ws.js +4 -3
  106. package/dist/wrangler/nimbus-wrangler.js +1 -1
  107. package/package.json +4 -2
  108. package/scripts/bundle-esbuild-wasm.mjs +2 -2
  109. package/scripts/bundle-facet-workers.mjs +5 -7
  110. package/scripts/bundle-sqlite-wasm.mjs +1 -1
  111. package/dist/facets/inner-do-registry.d.ts +0 -41
  112. package/dist/facets/inner-do-registry.d.ts.map +0 -1
  113. package/dist/facets/inner-do-registry.js +0 -51
  114. package/dist/facets/launch-pacer.d.ts +0 -111
  115. package/dist/facets/launch-pacer.d.ts.map +0 -1
  116. package/dist/facets/launch-pacer.js +0 -130
  117. package/dist/loaders/fanout-pool.d.ts +0 -207
  118. package/dist/loaders/fanout-pool.d.ts.map +0 -1
  119. package/dist/loaders/fanout-pool.js +0 -363
  120. package/dist/loaders/loader-pool.d.ts +0 -294
  121. package/dist/loaders/loader-pool.d.ts.map +0 -1
  122. package/dist/loaders/loader-pool.js +0 -642
  123. package/dist/loaders/process-fabric.d.ts +0 -509
  124. package/dist/loaders/process-fabric.d.ts.map +0 -1
  125. package/dist/loaders/process-fabric.js +0 -360
  126. package/dist/loaders/vendor/errors.d.ts +0 -24
  127. package/dist/loaders/vendor/errors.d.ts.map +0 -1
  128. package/dist/loaders/vendor/errors.js +0 -46
  129. package/dist/loaders/vendor/serialize.d.ts +0 -3
  130. package/dist/loaders/vendor/serialize.d.ts.map +0 -1
  131. package/dist/loaders/vendor/serialize.js +0 -25
  132. package/dist/loaders/vendor/types.d.ts +0 -69
  133. package/dist/loaders/vendor/types.d.ts.map +0 -1
  134. package/dist/loaders/vendor/types.js +0 -4
  135. package/dist/loaders/workerd-facet-host.d.ts +0 -141
  136. package/dist/loaders/workerd-facet-host.d.ts.map +0 -1
  137. package/dist/loaders/workerd-facet-host.js +0 -284
  138. package/dist/session/bindings.d.ts +0 -209
  139. package/dist/session/bindings.d.ts.map +0 -1
  140. package/dist/session/bindings.js +0 -680
  141. package/dist/session/ctx-exports.d.ts +0 -16
  142. package/dist/session/ctx-exports.d.ts.map +0 -1
  143. package/dist/session/ctx-exports.js +0 -22
  144. package/dist/session/ws-hibernation-config.d.ts +0 -64
  145. package/dist/session/ws-hibernation-config.d.ts.map +0 -1
  146. package/dist/session/ws-hibernation-config.js +0 -89
@@ -18,11 +18,15 @@
18
18
  * w9_proc_logs + w9_proc_exits.
19
19
  * - scheduleHibFlush(host, ctx) — debounced setTimeout + best-effort
20
20
  * setAlarm for post-hibernation drain.
21
- * - dispatchAlarm(host) — alarm() handler body.
22
- * - maybeBumpIsolateGen(host, ctx) — increment + persist isolate-gen
23
- * counter once per fresh isolate.
21
+ * - dispatchAlarm(host) — alarm() handler body: the fabric's generic
22
+ * reason dispatcher with this session's handlers registered.
24
23
  * - flushOnClose(host) — synchronous flush on ws close.
25
24
  *
25
+ * The timer multiplexer itself (reason map, schedule, the per-instance
26
+ * chain) is fabric machinery — `@nimbus-sh/fabric/timers.js`; this module
27
+ * registers the session's reasons ('w9-flush' | 'log-janitor' |
28
+ * 'resident-launch') on top of it.
29
+ *
26
30
  * **`ctx` taken as a separate arg from `host`** because the parent
27
31
  * `CloudflareDurableObject` class declares `ctx` as `protected`, which
28
32
  * is nominal-typed in TS and cannot appear on a public interface
@@ -35,7 +39,8 @@
35
39
  * wireProcessLogPersist again.
36
40
  */
37
41
  import type { SessionProcessSupervisor } from '@nimbus-sh/core/runtime/session-process-supervisor.js';
38
- import { type WsHibernationConfigResult } from './ws-hibernation-config.js';
42
+ import { type WsHibernationConfigResult } from '@nimbus-sh/fabric/ws-hibernation-config.js';
43
+ import { type TimerHost } from '@nimbus-sh/fabric/timers.js';
39
44
  export type { WsHibernationConfigResult };
40
45
  /**
41
46
  * Minimal host shape. `_w9*` fields drop `private` on the class so
@@ -44,10 +49,8 @@ export type { WsHibernationConfigResult };
44
49
  *
45
50
  * `ctx` is NOT in this interface — passed as a separate arg.
46
51
  */
47
- export interface HibHost {
52
+ export interface HibHost extends TimerHost {
48
53
  processes: SessionProcessSupervisor;
49
- _w9IsolateGen: number;
50
- _w9IsolateGenPersisted: boolean;
51
54
  _w9SchemaInit: boolean;
52
55
  _w9PersistWired: boolean;
53
56
  _w9FlushTimer: any;
@@ -55,8 +58,6 @@ export interface HibHost {
55
58
  _w1JanitorArmed: boolean;
56
59
  /** W1: destroyed-session tombstone — never re-arm alarms while set. */
57
60
  _w1SessionDestroyed: boolean;
58
- /** W1: serializes every alarm-map read-modify-write (see scheduleAlarm). */
59
- _w1AlarmChain?: Promise<unknown>;
60
61
  }
61
62
  /**
62
63
  * Run at DO ctor time. Returns the result for the class to assign to
@@ -104,66 +105,32 @@ export declare function ensureLogJanitor(host: HibHost, ctx: any): void;
104
105
  /** W9: idempotent SQL schema bootstrap. */
105
106
  export declare function ensureHibSchema(host: HibHost, ctx: any): void;
106
107
  /**
107
- * W1: canonical alarm-reason strings. Stored in the
108
- * `W1_NEXT_ALARM_REASONS_KEY` map. Forward-compat: dispatcher silently
109
- * drops unknown reasons so a rollback from a future deploy that added
110
- * new reasons doesn't leave the alarm stuck.
108
+ * W1: this session's canonical alarm-reason strings, registered on the
109
+ * fabric's reason map. Forward-compat: the dispatcher silently drops unknown
110
+ * reasons so a rollback from a future deploy that added new reasons doesn't
111
+ * leave the alarm stuck.
111
112
  */
112
113
  export type AlarmReason = 'w9-flush' | 'log-janitor' | 'resident-launch';
113
- /**
114
- * W1: schedule (or re-schedule) an alarm reason. Coordinated via a
115
- * single map in DO storage so multiple subsystems (W9 debounced flush +
116
- * W1 log-janitor sweep) don't clobber each other's `setAlarm()` calls.
117
- *
118
- * Semantics:
119
- * - Reads the existing reasons map.
120
- * - Sets `map[reason] = whenMs` IF `whenMs` is sooner than the
121
- * currently-pending deadline for that reason (or no entry exists).
122
- * Later-than-pending requests are silently ignored — the existing
123
- * alarm will fire and re-arm anyway.
124
- * - Writes the map back and calls `ctx.storage.setAlarm(min(deadlines))`.
125
- *
126
- * Cost: 1 storage read + 1 storage write + 1 setAlarm per call. setAlarm
127
- * itself is billed as 1 row written per DO pricing. At W1's 60s
128
- * cadence, this is ~$0.05/mo/session at scale — dwarfed by the
129
- * hibernation duration savings.
130
- *
131
- * Fail-soft: any throw is swallowed with a warn. On older runtimes /
132
- * wrangler-dev where setAlarm is unavailable, this is a no-op (the
133
- * subsystem's in-isolate setTimeout fallback continues to work).
134
- */
135
- export declare function scheduleAlarm(host: HibHost, ctx: any, reason: AlarmReason, whenMs: number): Promise<boolean>;
136
114
  /**
137
115
  * W9: ensure the alarm is set for the next flush window. Cheap to
138
116
  * call repeatedly — we only schedule the in-isolate flush timer if
139
- * it isn't already set. The persistent alarm goes through scheduleAlarm
117
+ * it isn't already set. The persistent alarm goes through timers.schedule
140
118
  * so it coordinates with W1's log-janitor sweep.
141
119
  */
142
120
  export declare function scheduleHibFlush(host: HibHost, ctx: any): void;
143
121
  /**
144
- * W1: multi-reason alarm dispatcher. Called from the DO's `alarm()`
145
- * handler.
146
- *
147
- * For each pending reason whose deadline has passed, run its handler.
148
- * Reasons supported today:
122
+ * W1: this session's alarm() handler body — the fabric's multi-reason
123
+ * dispatcher with this session's handlers registered:
149
124
  * - `'w9-flush'` → processes.flushLogs()
125
+ * - `'resident-launch'` → pumpResidentLaunches()
150
126
  * - `'log-janitor'` → processes.dropLogsOlderThan(orphanCheck); re-arm
151
- * for next 60s cycle.
127
+ * for next 60s cycle while the session still has anything to sweep.
152
128
  *
153
129
  * `janitorOrphanCheck` is the orphan-pid predicate provided by the
154
130
  * caller (typically `(pid) => !host.processes.get(pid)`). Decoupled
155
131
  * so HibHost doesn't need to import ProcessTable.
156
- *
157
- * After running fireable reasons, re-arms `ctx.storage.setAlarm` at the
158
- * earliest remaining deadline. If no reasons remain, deletes the map
159
- * key and does NOT call setAlarm — the DO becomes hibernation-eligible
160
- * after the 10s idle window.
161
- *
162
- * Forward/back-compat: unknown reasons silently dropped.
163
132
  */
164
- export declare function dispatchAlarm(host: HibHost, ctx: any, janitorOrphanCheck?: (pid: number) => boolean, pumpResidentLaunches?: () => Promise<void>): Promise<void>;
165
- /** W9: increment + persist isolate-gen counter once per fresh isolate. */
166
- export declare function maybeBumpIsolateGen(host: HibHost, ctx: any): Promise<void>;
133
+ export declare function dispatchAlarm(host: HibHost, ctx: any, janitorOrphanCheck?: (pid: number) => boolean, pumpResidentLaunches?: () => Promise<void>, alarmInfo?: AlarmInvocationInfo): Promise<void>;
167
134
  /**
168
135
  * W9: synchronous flush of the process-log ring on session close.
169
136
  * Wraps `processes.flushLogs()` in a try/catch so a flush failure
@@ -1 +1 @@
1
- {"version":3,"file":"hibernation.d.ts","sourceRoot":"","sources":["../../src/session/hibernation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAA0B,KAAK,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGpG,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,wBAAwB,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,OAAO,CAAC;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,GAAG,CAAC;IACnB,4EAA4E;IAC5E,eAAe,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,mBAAmB,EAAE,OAAO,CAAC;IAC7B,4EAA4E;IAC5E,aAAa,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,GAAG,GAAG,yBAAyB,CAY9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CA6GnE;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAMrE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAc9D;AAED,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAqB7D;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAqB9D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,GAAG,EACR,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EAC7C,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC,CASf;AAoFD,0EAA0E;AAC1E,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBhF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAMhD"}
1
+ {"version":3,"file":"hibernation.d.ts","sourceRoot":"","sources":["../../src/session/hibernation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAA0B,KAAK,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AACpH,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAGrE,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,SAAS,EAAE,wBAAwB,CAAC;IACpC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,GAAG,CAAC;IACnB,4EAA4E;IAC5E,eAAe,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,GAAG,GAAG,yBAAyB,CAY9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CA6GnE;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAMrE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAc9D;AAED,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAqB7D;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAEzE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAqB9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,GAAG,EACR,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EAC7C,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC1C,SAAS,CAAC,EAAE,mBAAmB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAMhD"}
@@ -18,11 +18,15 @@
18
18
  * w9_proc_logs + w9_proc_exits.
19
19
  * - scheduleHibFlush(host, ctx) — debounced setTimeout + best-effort
20
20
  * setAlarm for post-hibernation drain.
21
- * - dispatchAlarm(host) — alarm() handler body.
22
- * - maybeBumpIsolateGen(host, ctx) — increment + persist isolate-gen
23
- * counter once per fresh isolate.
21
+ * - dispatchAlarm(host) — alarm() handler body: the fabric's generic
22
+ * reason dispatcher with this session's handlers registered.
24
23
  * - flushOnClose(host) — synchronous flush on ws close.
25
24
  *
25
+ * The timer multiplexer itself (reason map, schedule, the per-instance
26
+ * chain) is fabric machinery — `@nimbus-sh/fabric/timers.js`; this module
27
+ * registers the session's reasons ('w9-flush' | 'log-janitor' |
28
+ * 'resident-launch') on top of it.
29
+ *
26
30
  * **`ctx` taken as a separate arg from `host`** because the parent
27
31
  * `CloudflareDurableObject` class declares `ctx` as `protected`, which
28
32
  * is nominal-typed in TS and cannot appear on a public interface
@@ -34,8 +38,9 @@
34
38
  * responsible for setting `host._w9PersistWired = false` BEFORE calling
35
39
  * wireProcessLogPersist again.
36
40
  */
37
- import { configureWsHibernation } from './ws-hibernation-config.js';
38
- import { SESSION_DESTROYED_KEY, W9_ISOLATE_GEN_KEY, W9_FLUSH_DEBOUNCE_MS, W1_NEXT_ALARM_REASONS_KEY } from './keys.js';
41
+ import { configureWsHibernation } from '@nimbus-sh/fabric/ws-hibernation-config.js';
42
+ import { timers } from '@nimbus-sh/fabric/timers.js';
43
+ import { SESSION_DESTROYED_KEY, W9_FLUSH_DEBOUNCE_MS } from './keys.js';
39
44
  /**
40
45
  * Run at DO ctor time. Returns the result for the class to assign to
41
46
  * `_w9WsConfig`. Failures are non-fatal — older workerd builds may lack
@@ -211,11 +216,11 @@ export function ensureLogJanitor(host, ctx) {
211
216
  if (host._w1SessionDestroyed)
212
217
  return;
213
218
  // Optimistic flag (dedupes same-tick appends), CONFIRMED by the schedule
214
- // outcome: scheduleAlarm swallows storage errors, and a failure with the
219
+ // outcome: timers.schedule swallows storage errors, and a failure with the
215
220
  // flag left set would mean no alarm AND nothing ever re-arming until the
216
221
  // instance recycles.
217
222
  host._w1JanitorArmed = true;
218
- void scheduleAlarm(host, ctx, 'log-janitor', Date.now() + 60_000).then((ok) => {
223
+ void timers(host, ctx).schedule('log-janitor', Date.now() + 60_000).then((ok) => {
219
224
  if (!ok)
220
225
  host._w1JanitorArmed = false;
221
226
  });
@@ -241,63 +246,10 @@ export function ensureHibSchema(host, ctx) {
241
246
  host._w9SchemaInit = false; // retry next time
242
247
  }
243
248
  }
244
- /**
245
- * W1: schedule (or re-schedule) an alarm reason. Coordinated via a
246
- * single map in DO storage so multiple subsystems (W9 debounced flush +
247
- * W1 log-janitor sweep) don't clobber each other's `setAlarm()` calls.
248
- *
249
- * Semantics:
250
- * - Reads the existing reasons map.
251
- * - Sets `map[reason] = whenMs` IF `whenMs` is sooner than the
252
- * currently-pending deadline for that reason (or no entry exists).
253
- * Later-than-pending requests are silently ignored — the existing
254
- * alarm will fire and re-arm anyway.
255
- * - Writes the map back and calls `ctx.storage.setAlarm(min(deadlines))`.
256
- *
257
- * Cost: 1 storage read + 1 storage write + 1 setAlarm per call. setAlarm
258
- * itself is billed as 1 row written per DO pricing. At W1's 60s
259
- * cadence, this is ~$0.05/mo/session at scale — dwarfed by the
260
- * hibernation duration savings.
261
- *
262
- * Fail-soft: any throw is swallowed with a warn. On older runtimes /
263
- * wrangler-dev where setAlarm is unavailable, this is a no-op (the
264
- * subsystem's in-isolate setTimeout fallback continues to work).
265
- */
266
- export function scheduleAlarm(host, ctx, reason, whenMs) {
267
- // Serialize every read-modify-write of the reasons map through one
268
- // per-instance chain: scheduleHibFlush and ensureLogJanitor fire
269
- // back-to-back from the same log-activity hook, and two interleaved
270
- // get→put cycles would silently drop whichever reason wrote first.
271
- const run = async () => {
272
- try {
273
- const setAlarmFn = ctx?.storage?.setAlarm;
274
- if (typeof setAlarmFn !== 'function')
275
- return false;
276
- const existing = (await ctx.storage.get(W1_NEXT_ALARM_REASONS_KEY));
277
- const map = { ...(existing || {}) };
278
- // Earliest-deadline-first: only update if new request is sooner or
279
- // this reason has no pending entry.
280
- if (!(reason in map) || whenMs < map[reason]) {
281
- map[reason] = whenMs;
282
- await ctx.storage.put(W1_NEXT_ALARM_REASONS_KEY, map);
283
- }
284
- const earliest = Math.min(...Object.values(map));
285
- setAlarmFn.call(ctx.storage, earliest);
286
- return true;
287
- }
288
- catch (e) {
289
- console.warn('[nimbus/W1] scheduleAlarm threw:', e?.message);
290
- return false;
291
- }
292
- };
293
- const chained = (host._w1AlarmChain ?? Promise.resolve()).then(run, run);
294
- host._w1AlarmChain = chained;
295
- return chained;
296
- }
297
249
  /**
298
250
  * W9: ensure the alarm is set for the next flush window. Cheap to
299
251
  * call repeatedly — we only schedule the in-isolate flush timer if
300
- * it isn't already set. The persistent alarm goes through scheduleAlarm
252
+ * it isn't already set. The persistent alarm goes through timers.schedule
301
253
  * so it coordinates with W1's log-janitor sweep.
302
254
  */
303
255
  export function scheduleHibFlush(host, ctx) {
@@ -319,154 +271,65 @@ export function scheduleHibFlush(host, ctx) {
319
271
  }, W9_FLUSH_DEBOUNCE_MS);
320
272
  // Persistent alarm: fires post-hibernation if the in-isolate timer
321
273
  // didn't get a chance to run (DO evicted under memory pressure
322
- // before the 250ms debounce expired). Coordinated via scheduleAlarm
274
+ // before the 250ms debounce expired). Coordinated via timers.schedule
323
275
  // so W1's log-janitor doesn't clobber it (or vice-versa).
324
- // Fire-and-forget — scheduleAlarm is fail-soft.
325
- void scheduleAlarm(host, ctx, 'w9-flush', Date.now() + W9_FLUSH_DEBOUNCE_MS * 4);
276
+ // Fire-and-forget — timers.schedule is fail-soft.
277
+ void timers(host, ctx).schedule('w9-flush', Date.now() + W9_FLUSH_DEBOUNCE_MS * 4);
326
278
  }
327
279
  /**
328
- * W1: multi-reason alarm dispatcher. Called from the DO's `alarm()`
329
- * handler.
330
- *
331
- * For each pending reason whose deadline has passed, run its handler.
332
- * Reasons supported today:
280
+ * W1: this session's alarm() handler body — the fabric's multi-reason
281
+ * dispatcher with this session's handlers registered:
333
282
  * - `'w9-flush'` → processes.flushLogs()
283
+ * - `'resident-launch'` → pumpResidentLaunches()
334
284
  * - `'log-janitor'` → processes.dropLogsOlderThan(orphanCheck); re-arm
335
- * for next 60s cycle.
285
+ * for next 60s cycle while the session still has anything to sweep.
336
286
  *
337
287
  * `janitorOrphanCheck` is the orphan-pid predicate provided by the
338
288
  * caller (typically `(pid) => !host.processes.get(pid)`). Decoupled
339
289
  * so HibHost doesn't need to import ProcessTable.
340
- *
341
- * After running fireable reasons, re-arms `ctx.storage.setAlarm` at the
342
- * earliest remaining deadline. If no reasons remain, deletes the map
343
- * key and does NOT call setAlarm — the DO becomes hibernation-eligible
344
- * after the 10s idle window.
345
- *
346
- * Forward/back-compat: unknown reasons silently dropped.
347
290
  */
348
- export function dispatchAlarm(host, ctx, janitorOrphanCheck, pumpResidentLaunches) {
349
- // Same serialization as scheduleAlarm: the dispatcher's read→handlers→write
350
- // cycle must not interleave with a log-activity scheduleAlarm.
351
- const chained = (host._w1AlarmChain ?? Promise.resolve()).then(() => dispatchAlarmBody(host, ctx, janitorOrphanCheck, pumpResidentLaunches), () => dispatchAlarmBody(host, ctx, janitorOrphanCheck, pumpResidentLaunches));
352
- host._w1AlarmChain = chained;
353
- return chained;
354
- }
355
- async function dispatchAlarmBody(host, ctx, janitorOrphanCheck, pumpResidentLaunches) {
356
- try {
357
- const now = Date.now();
358
- const existing = (await ctx?.storage?.get?.(W1_NEXT_ALARM_REASONS_KEY));
291
+ export function dispatchAlarm(host, ctx, janitorOrphanCheck, pumpResidentLaunches, alarmInfo) {
292
+ return timers(host, ctx).dispatch({
293
+ 'w9-flush': () => {
294
+ host.processes.flushLogs();
295
+ },
296
+ 'resident-launch': async () => {
297
+ // Awaited, not fired and forgotten: this invocation is the fresh
298
+ // turn the launch asked for, and it has to stay the one paying for
299
+ // the chunk it just released.
300
+ await pumpResidentLaunches?.();
301
+ },
302
+ 'log-janitor': (now) => {
303
+ host.processes.dropLogsOlderThan(undefined, janitorOrphanCheck);
304
+ // Re-arm only while the session still has running processes or
305
+ // buffered logs to sweep. An idle, abandoned, or destroyed
306
+ // session must NOT keep an eternal 60s alarm loop alive: the
307
+ // janitor used to self-renew unconditionally (and the DO
308
+ // constructor re-armed it on every alarm-triggered boot), so
309
+ // every session ever created kept booting its DO every ~60s
310
+ // forever. The accumulated fleet of deleted probe sessions
311
+ // produced continuous DO-storage churn (measured ~24 zombie
312
+ // boots/s on 2026-07-13) that intermittently reset LIVE
313
+ // session DOs mid-run ("Internal error in Durable Object
314
+ // storage caused object to be reset"). The next log append
315
+ // re-arms the cycle via ensureLogJanitor.
316
+ if (host.processes.stats.running > 0 || host.processes.logStats.totalPids > 0) {
317
+ return { rearmAt: now + 60_000 };
318
+ }
319
+ host._w1JanitorArmed = false;
320
+ },
321
+ }, () => {
359
322
  // Legacy path: pre-W1 deploys had no map. dispatchAlarm was called
360
323
  // with no map and unconditionally ran the log flush. Preserve
361
324
  // that on a missing map (one-time post-deploy, then the map is
362
- // populated by the next scheduleHibFlush / scheduleAlarm call).
363
- if (!existing || Object.keys(existing).length === 0) {
364
- try {
365
- host.processes.flushLogs();
366
- }
367
- catch (e) {
368
- console.warn('[nimbus/W9] legacy flush threw:', e?.message);
369
- }
370
- return;
371
- }
372
- const map = { ...existing };
373
- // Snapshot fireable reasons BEFORE running any of them, so a
374
- // handler that schedules itself for the next cycle doesn't get
375
- // immediately re-fired in the same dispatch.
376
- const fired = [];
377
- for (const [reason, when] of Object.entries(map)) {
378
- if (when <= now)
379
- fired.push(reason);
380
- }
381
- for (const reason of fired) {
382
- delete map[reason];
383
- try {
384
- if (reason === 'w9-flush') {
385
- host.processes.flushLogs();
386
- }
387
- else if (reason === 'resident-launch') {
388
- // Awaited, not fired and forgotten: this invocation is the fresh
389
- // turn the launch asked for, and it has to stay the one paying for
390
- // the chunk it just released.
391
- await pumpResidentLaunches?.();
392
- }
393
- else if (reason === 'log-janitor') {
394
- host.processes.dropLogsOlderThan(undefined, janitorOrphanCheck);
395
- // Re-arm only while the session still has running processes or
396
- // buffered logs to sweep. An idle, abandoned, or destroyed
397
- // session must NOT keep an eternal 60s alarm loop alive: the
398
- // janitor used to self-renew unconditionally (and the DO
399
- // constructor re-armed it on every alarm-triggered boot), so
400
- // every session ever created kept booting its DO every ~60s
401
- // forever. The accumulated fleet of deleted probe sessions
402
- // produced continuous DO-storage churn (measured ~24 zombie
403
- // boots/s on 2026-07-13) that intermittently reset LIVE
404
- // session DOs mid-run ("Internal error in Durable Object
405
- // storage caused object to be reset"). The next log append
406
- // re-arms the cycle via ensureLogJanitor.
407
- if (host.processes.stats.running > 0 || host.processes.logStats.totalPids > 0) {
408
- map['log-janitor'] = now + 60_000;
409
- }
410
- else {
411
- host._w1JanitorArmed = false;
412
- }
413
- }
414
- // Unknown reasons silently dropped (forward-compat).
415
- }
416
- catch (e) {
417
- console.warn(`[nimbus/W1] dispatch ${reason} threw:`, e?.message);
418
- }
419
- }
420
- // Re-arm or clear.
421
- const setAlarmFn = ctx?.storage?.setAlarm;
422
- if (Object.keys(map).length > 0) {
423
- await ctx.storage.put(W1_NEXT_ALARM_REASONS_KEY, map);
424
- const earliest = Math.min(...Object.values(map));
425
- if (typeof setAlarmFn === 'function') {
426
- setAlarmFn.call(ctx.storage, earliest);
427
- }
325
+ // populated by the next scheduleHibFlush / timers.schedule call).
326
+ try {
327
+ host.processes.flushLogs();
428
328
  }
429
- else {
430
- try {
431
- await ctx.storage.delete(W1_NEXT_ALARM_REASONS_KEY);
432
- }
433
- catch { }
434
- // No remaining reasons → no setAlarm call → DO becomes
435
- // hibernation-eligible after the 10s idle window.
329
+ catch (e) {
330
+ console.warn('[nimbus/W9] legacy flush threw:', e?.message);
436
331
  }
437
- }
438
- catch (e) {
439
- console.warn('[nimbus/W1] dispatchAlarm threw:', e?.message);
440
- }
441
- }
442
- /** W9: increment + persist isolate-gen counter once per fresh isolate. */
443
- export async function maybeBumpIsolateGen(host, ctx) {
444
- if (host._w9IsolateGenPersisted)
445
- return;
446
- host._w9IsolateGenPersisted = true;
447
- try {
448
- const prev = (await ctx.storage.get(W9_ISOLATE_GEN_KEY));
449
- // Adopt the persisted truth first, and adopt the bump only after the
450
- // put resolves. An unpersisted `next` would be re-read as `prev` by the
451
- // NEXT boot and re-issued — two instances sharing one generation is
452
- // exactly the pid-aliasing this counter exists to prevent. Running on
453
- // the previous persisted generation is the lesser lapse, and the
454
- // put-failure case is replica-only in practice (replicas never spawn).
455
- //
456
- // What holds the guarantee is the output gate, not this await: measured,
457
- // the block body resolves in 0 ms even with a confirmed put, because
458
- // `await storage.put()` returns before durability. The gate is what
459
- // keeps a pid from generation N from escaping before N is durable, which
460
- // is why marking this put `allowUnconfirmed` is not a free speedup — see
461
- // scratchpad/coldstart-s1.md.
462
- host._w9IsolateGen = typeof prev === 'number' ? prev : 0;
463
- const next = host._w9IsolateGen + 1;
464
- await ctx.storage.put(W9_ISOLATE_GEN_KEY, next);
465
- host._w9IsolateGen = next;
466
- }
467
- catch (e) {
468
- console.warn('[nimbus/W9] isolate-gen bump failed:', e?.message);
469
- }
332
+ }, alarmInfo);
470
333
  }
471
334
  /**
472
335
  * W9: synchronous flush of the process-log ring on session close.
@@ -32,7 +32,7 @@
32
32
  * preserved — old probes still see it. New phase entries are
33
33
  * additional ring entries, not replacements.
34
34
  */
35
- import { type SessionState } from '@nimbus-sh/core/observability/oom-discriminator.js';
35
+ import { type SessionState } from '@nimbus-sh/platform/oom-discriminator.js';
36
36
  /**
37
37
  * Set the current phase + record a transition. Fail-soft on the
38
38
  * observability call; the phase update on `self` is direct and
@@ -40,7 +40,7 @@ import { type SessionState } from '@nimbus-sh/core/observability/oom-discriminat
40
40
  */
41
41
  export declare function setPhase(self: {
42
42
  _b4Phase: SessionState | null;
43
- _w9IsolateGen?: number;
43
+ ctx?: unknown;
44
44
  }, toState: SessionState, trigger: string): void;
45
45
  /**
46
46
  * [B'.5] Identify the original phase-based warm-rejoin case. The /ws
@@ -93,7 +93,6 @@ export declare function joinExistingSession(self: {
93
93
  write(s: string): void;
94
94
  };
95
95
  _b4Phase: SessionState | null;
96
- _w9IsolateGen?: number;
97
96
  _b4WarmJoinCount: number;
98
97
  }, ws: WebSocket, appendScrollback: (ctx: any, data: string, atMs: number) => void, loadScrollback: (ctx: any) => string): void;
99
98
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"init-phases.d.ts","sourceRoot":"","sources":["../../src/session/init-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oDAAoD,CAAC;AAE5G;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE;IAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/D,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,MAAM,GACd,IAAI,CAcN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;CACxC,GAAG,OAAO,CAKV;AAED,KAAK,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB,EAAE,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,iBAAiB,CAmBnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE;IACJ,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE;QAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACpG,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,EACD,EAAE,EAAE,SAAS,EACb,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,EAChE,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GACnC,IAAI,CAsCN"}
1
+ {"version":3,"file":"init-phases.d.ts","sourceRoot":"","sources":["../../src/session/init-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAGlG;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE;IAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,EACtD,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,MAAM,GACd,IAAI,CAcN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;CACxC,GAAG,OAAO,CAKV;AAED,KAAK,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB,EAAE,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,iBAAiB,CAmBnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE;IACJ,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE;QAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACpG,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;CAC1B,EACD,EAAE,EAAE,SAAS,EACb,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,EAChE,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GACnC,IAAI,CAsCN"}
@@ -32,7 +32,8 @@
32
32
  * preserved — old probes still see it. New phase entries are
33
33
  * additional ring entries, not replacements.
34
34
  */
35
- import { recordRecoveryEvent } from '@nimbus-sh/core/observability/oom-discriminator.js';
35
+ import { recordRecoveryEvent } from '@nimbus-sh/platform/oom-discriminator.js';
36
+ import { generation } from '@nimbus-sh/fabric/generation.js';
36
37
  /**
37
38
  * Set the current phase + record a transition. Fail-soft on the
38
39
  * observability call; the phase update on `self` is direct and
@@ -47,7 +48,7 @@ export function setPhase(self, toState, trigger) {
47
48
  fromState,
48
49
  toState,
49
50
  trigger,
50
- isolateGen: self._w9IsolateGen ?? 0,
51
+ isolateGen: generation(self.ctx),
51
52
  dataLoss: false,
52
53
  snapshotKeysRehydrated: 0,
53
54
  });
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/session/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AA6EH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;;;GAQG;AACH,KAAK,QAAQ,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;CAAE,CAAC;AAa3E,wBAAsB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAksF9E"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/session/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AA+EH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;;;GAQG;AACH,KAAK,QAAQ,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;CAAE,CAAC;AAa3E,wBAAsB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAosF9E"}
@@ -68,14 +68,16 @@ import { listInstalledRuntimes, rehydrateInstalledRuntimes, registerRunnerFactor
68
68
  // one-time Worker Startup Time paid on every fresh-isolate cold run.
69
69
  import { hasSeededProject, SEED_PROJECT_DIR } from '@nimbus-sh/core/vfs/seed-project.js';
70
70
  import { notifyTerminalEvent } from '../runtime/process-logs-api.js';
71
+ import { generation } from '@nimbus-sh/fabric/generation.js';
71
72
  import { stripAnsi } from '@nimbus-sh/core/runtime/process-logs.js';
72
73
  import { DEFAULT_MOUNT_POINTS, NODE_VERSION, } from '@nimbus-sh/core/constants.js';
73
74
  import { ensureSessionStateSchema, loadShellState, stampHydratedAt, countSessionStateKeys, loadKernelMounts, persistKernelMounts, appendScrollback, loadScrollback, } from './state-store.js';
74
- import { recordRecoveryEvent } from '@nimbus-sh/core/observability/oom-discriminator.js';
75
+ import { recordRecoveryEvent } from '@nimbus-sh/platform/oom-discriminator.js';
75
76
  import { sessionAiEnv } from './ai.js';
76
77
  import { routeSessionLoopback } from './loopback.js';
77
78
  import { setPhase } from './init-phases.js';
78
79
  import { VITE_CONFIG_KEY } from './keys.js';
80
+ import { clearPortCapability } from './port-capability.js';
79
81
  function resolveNpmPrefix(prefix, cwd) {
80
82
  return prefix.startsWith('/')
81
83
  ? normalizeVfsPath(prefix)
@@ -165,7 +167,7 @@ export async function initSession(self, ws) {
165
167
  + 'running was lost with the old one — re-run it if it had not finished.\x1b[0m\r\n');
166
168
  }
167
169
  // A reset that killed a resident launch left its journal row behind
168
- // (facets/manager.ts, _recoverInterruptedLaunches). The alarm the dying
170
+ // (fabric's FencedWork.recoverInterrupted). The alarm the dying
169
171
  // instance was using for launch turns is NOT a trigger recovery can rely
170
172
  // on — measured live, a launch killed early in its first chunks rolls the
171
173
  // alarm-map put back with the rest of the dying turn, so the replacement
@@ -480,7 +482,7 @@ export async function initSession(self, ws) {
480
482
  registerRunnerFactory('cpython-runner', (manifest, installRoot, binName, binKind) => async function pythonReplOrOneShot(ctx) {
481
483
  const argv = ctx.args || [];
482
484
  // No args at all → REPL session. Hand off to runPythonRepl
483
- // which builds its own NimbusLoaderPool (separate from the
485
+ // which builds its own IsolatePool (separate from the
484
486
  // one-shot dispatch's pool) and drives a ReplSession.
485
487
  if (argv.length === 0 && self.terminal) {
486
488
  const { runPythonRepl } = await import('../runtime/python-repl.js');
@@ -1243,6 +1245,7 @@ export async function initSession(self, ws) {
1243
1245
  try {
1244
1246
  const previewStub = makeLongRunningPortStub(self.viteDevServer);
1245
1247
  self.portRegistry.bindFacetStub(previewProcEntry.pid, previewStub);
1248
+ await clearPortCapability(self, previewPort);
1246
1249
  self.portRegistry.register(previewPort, previewProcEntry.pid);
1247
1250
  self._viteShimPid = previewProcEntry.pid;
1248
1251
  self._viteShimPort = previewPort;
@@ -1457,6 +1460,7 @@ export async function initSession(self, ws) {
1457
1460
  // facet uses (Express, Bun.serve, http.createServer().listen()).
1458
1461
  const viteStub = makeLongRunningPortStub(self.viteDevServer);
1459
1462
  self.portRegistry.bindFacetStub(viteProcEntry.pid, viteStub);
1463
+ await clearPortCapability(self, resolvedPort);
1460
1464
  self.portRegistry.register(resolvedPort, viteProcEntry.pid);
1461
1465
  // Track the wiring so `vite stop` and crash-handlers can tear it
1462
1466
  // down without searching the registry.
@@ -2702,7 +2706,7 @@ export async function initSession(self, ws) {
2702
2706
  fromState: fromState,
2703
2707
  toState: 'hydrated',
2704
2708
  trigger: 'init-session',
2705
- isolateGen: self._w9IsolateGen,
2709
+ isolateGen: generation(self.ctx),
2706
2710
  dataLoss: false,
2707
2711
  snapshotKeysRehydrated: snapshotKeys,
2708
2712
  });
@@ -17,9 +17,6 @@
17
17
  * These keys persist DO state across deploys. Renaming any key is a
18
18
  * storage migration — never do it without an explicit migration plan.
19
19
  */
20
- /** W9: storage key for the isolate-generation counter (cold-start +
21
- * post-hibernation wake; one increment per fresh isolate). */
22
- export declare const W9_ISOLATE_GEN_KEY = "w9_isolate_gen";
23
20
  /** W9: debounce window in ms before flushing pending process-log writes
24
21
  * to SQL. Hot path (every append schedules a flush via this debounce). */
25
22
  export declare const W9_FLUSH_DEBOUNCE_MS = 250;
@@ -34,25 +31,6 @@ export declare const SESSION_BASE_PATH_KEY = "session-base-path";
34
31
  * hibernation so vite resumes serving after wake without re-running
35
32
  * /api/start-vite. */
36
33
  export declare const VITE_CONFIG_KEY = "vite-config";
37
- /** W1: multi-reason alarm coordination map.
38
- *
39
- * JSON-serialised `Record<reason, deadlineMsEpoch>` where keys are
40
- * canonical reason strings (e.g. 'w9-flush', 'log-janitor'). The
41
- * alarm() dispatcher reads this on fire, dispatches every reason
42
- * whose deadline has passed, and re-arms `ctx.storage.setAlarm` at
43
- * the earliest remaining deadline.
44
- *
45
- * Why a map (not a single nextAlarmAt + reason): two subsystems
46
- * (W9 debounced flush + W1 log-janitor sweep) can have distinct
47
- * deadlines. Without the map, the later setAlarm() call would
48
- * overwrite the earlier reason silently, breaking whichever
49
- * subsystem expected its deadline.
50
- *
51
- * Forward-compat: dispatcher silently drops unknown reasons so a
52
- * rollback from a future deploy that added new reasons doesn't
53
- * leave the alarm stuck.
54
- */
55
- export declare const W1_NEXT_ALARM_REASONS_KEY = "w1_next_alarm_reasons";
56
34
  /**
57
35
  * Destroyed-session tombstone. Written AFTER `storage.deleteAll()` in the
58
36
  * destroy flow so a straggler facet RPC that wakes the dead DO cannot re-arm
@@ -60,24 +38,23 @@ export declare const W1_NEXT_ALARM_REASONS_KEY = "w1_next_alarm_reasons";
60
38
  * metadata is the deliberate cost of keeping destroyed sessions inert.
61
39
  */
62
40
  export declare const SESSION_DESTROYED_KEY = "session_destroyed";
63
- /**
64
- * Prefix for the resident-process journal: one row per resident this session
65
- * owes the user, keyed by the pid it was built for.
66
- *
67
- * A resident holds its state in memory — the process table entry, the facet
68
- * handle, the terminal — so an instance reset destroys it silently. The row
69
- * is what a LATER instance reads to know a resident ended that way rather
70
- * than on purpose: a pid at or below the reader's own pid base was allocated
71
- * by a previous generation (see PID_GEN_STRIDE). Written (and synced) before
72
- * the launch's first byte of work, rewritten as `running` when the launch
73
- * settles, and released only when the PROCESS ends — because the resets this
74
- * row survives strike after the launch as often as during it (measured live,
75
- * staging 2026-08-13: every observed reset landed seconds AFTER settle).
76
- */
77
- export declare const RESIDENT_LAUNCH_KEY_PREFIX = "resident-launch:";
78
41
  /** Prefix for consumed single-use attach bootstrap token ids (`jti`).
79
42
  * Written set-if-absent by `_rpcConsumeAttachBootstrap` on the attach
80
43
  * exchange; an existing row means the bootstrap URL was replayed.
81
44
  * Bounded: at most one row per `POST /new` bootstrap actually attached. */
82
45
  export declare const ATTACH_BOOTSTRAP_JTI_KEY_PREFIX = "attach-bootstrap-jti:";
46
+ /**
47
+ * Prefix for a port's durable preview capability, keyed by port number. The
48
+ * registry mints the value in memory per registration; this is what lets a
49
+ * preview URL the embedder was already handed survive a rebuild. Owned by
50
+ * `session/port-capability.ts`, which is the only module that reads or writes
51
+ * these rows.
52
+ */
53
+ export declare const PORT_CAPABILITY_KEY_PREFIX = "nimbus_preview_capability:";
54
+ /**
55
+ * Prefix for a named programmatic shell's durable cwd+env, keyed by shell id.
56
+ * One row per id the embedder has actually used; bounded by the embedder's own
57
+ * naming, the way a terminal tab is.
58
+ */
59
+ export declare const SHELL_STATE_KEY_PREFIX = "nimbus_programmatic_shell:";
83
60
  //# sourceMappingURL=keys.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/session/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;+DAC+D;AAC/D,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AAEnD;2EAC2E;AAC3E,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;yDAEyD;AACzD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD;0DAC0D;AAC1D,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;uBAEuB;AACvB,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,0BAA0B,qBAAqB,CAAC;AAE7D;;;4EAG4E;AAC5E,eAAO,MAAM,+BAA+B,0BAA0B,CAAC"}
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/session/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH;2EAC2E;AAC3E,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;yDAEyD;AACzD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD;0DAC0D;AAC1D,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;uBAEuB;AACvB,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;;4EAG4E;AAC5E,eAAO,MAAM,+BAA+B,0BAA0B,CAAC;AAEvE;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AAEvE;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,+BAA+B,CAAC"}