@nimbus-sh/worker 0.9.0 → 0.11.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 (286) hide show
  1. package/NOTICE.md +5 -0
  2. package/README.md +10 -0
  3. package/dist/_shared/session-router.d.ts +7 -0
  4. package/dist/_shared/session-router.d.ts.map +1 -1
  5. package/dist/_shared/session-router.js +7 -0
  6. package/dist/bindings/body.d.ts +6 -0
  7. package/dist/bindings/body.d.ts.map +1 -0
  8. package/dist/bindings/body.js +37 -0
  9. package/dist/bindings/kv.d.ts +0 -2
  10. package/dist/bindings/kv.d.ts.map +1 -1
  11. package/dist/bindings/kv.js +3 -42
  12. package/dist/bindings/r2.d.ts +0 -2
  13. package/dist/bindings/r2.d.ts.map +1 -1
  14. package/dist/bindings/r2.js +4 -44
  15. package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
  16. package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
  17. package/dist/esbuild-cli-artifact.generated.js +17 -0
  18. package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
  19. package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
  20. package/dist/esbuild-wasm-bundle.generated.js +24 -24
  21. package/dist/facets/cirrus-real.d.ts.map +1 -1
  22. package/dist/facets/cirrus-real.js +11 -6
  23. package/dist/facets/compose.d.ts +11 -7
  24. package/dist/facets/compose.d.ts.map +1 -1
  25. package/dist/facets/compose.js +8 -31
  26. package/dist/facets/data-plan.d.ts +79 -0
  27. package/dist/facets/data-plan.d.ts.map +1 -0
  28. package/dist/facets/data-plan.js +477 -0
  29. package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
  30. package/dist/facets/esbuild-bundle-pool.js +3 -3
  31. package/dist/facets/esbuild-transform.d.ts +38 -8
  32. package/dist/facets/esbuild-transform.d.ts.map +1 -1
  33. package/dist/facets/esbuild-transform.js +219 -19
  34. package/dist/facets/exec-telemetry.d.ts +7 -3
  35. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  36. package/dist/facets/manager.d.ts +198 -69
  37. package/dist/facets/manager.d.ts.map +1 -1
  38. package/dist/facets/manager.js +1276 -652
  39. package/dist/facets/opencode-staging.d.ts +0 -2
  40. package/dist/facets/opencode-staging.d.ts.map +1 -1
  41. package/dist/facets/opencode-staging.js +5 -11
  42. package/dist/facets/process.d.ts +4 -0
  43. package/dist/facets/process.d.ts.map +1 -1
  44. package/dist/facets/process.js +3 -0
  45. package/dist/facets/read-profile.d.ts +149 -0
  46. package/dist/facets/read-profile.d.ts.map +1 -0
  47. package/dist/facets/read-profile.js +483 -0
  48. package/dist/facets/real-vite-hmr.d.ts +2 -0
  49. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  50. package/dist/facets/real-vite-hmr.js +3 -2
  51. package/dist/facets/resident-identity.d.ts +0 -1
  52. package/dist/facets/resident-identity.d.ts.map +1 -1
  53. package/dist/facets/resident-identity.js +0 -3
  54. package/dist/facets/wasm-swap-registry.d.ts +34 -25
  55. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  56. package/dist/facets/wasm-swap-registry.js +62 -56
  57. package/dist/facets/ws-terminal.d.ts +4 -4
  58. package/dist/facets/ws-terminal.d.ts.map +1 -1
  59. package/dist/facets/ws-terminal.js +4 -5
  60. package/dist/git/commands.d.ts +33 -10
  61. package/dist/git/commands.d.ts.map +1 -1
  62. package/dist/git/commands.js +1891 -197
  63. package/dist/git/network-facet.d.ts +12 -2
  64. package/dist/git/network-facet.d.ts.map +1 -1
  65. package/dist/git/network-facet.js +69 -18
  66. package/dist/git/unified-diff.d.ts +74 -0
  67. package/dist/git/unified-diff.d.ts.map +1 -0
  68. package/dist/git/unified-diff.js +676 -0
  69. package/dist/git-bundle.generated.d.ts +7 -11
  70. package/dist/git-bundle.generated.d.ts.map +1 -1
  71. package/dist/git-bundle.generated.js +7 -11
  72. package/dist/hosted/commands.d.ts.map +1 -1
  73. package/dist/hosted/commands.js +64 -245
  74. package/dist/hosted/runtime.d.ts +22 -15
  75. package/dist/hosted/runtime.d.ts.map +1 -1
  76. package/dist/hosted/runtime.js +72 -14
  77. package/dist/hosted/services.d.ts +8 -1
  78. package/dist/hosted/services.d.ts.map +1 -1
  79. package/dist/hosted/services.js +12 -13
  80. package/dist/hosted/session.d.ts +165 -0
  81. package/dist/hosted/session.d.ts.map +1 -0
  82. package/dist/hosted/session.js +132 -0
  83. package/dist/loaders/generated-workers.d.ts +6 -3
  84. package/dist/loaders/generated-workers.d.ts.map +1 -1
  85. package/dist/loaders/generated-workers.js +8 -5
  86. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  87. package/dist/loaders/npm-resolve-preamble.js +0 -27
  88. package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
  89. package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
  90. package/dist/loaders/pre-bundle-preamble.js +13 -8
  91. package/dist/node-shims-artifact.generated.d.ts +13 -4
  92. package/dist/node-shims-artifact.generated.d.ts.map +1 -1
  93. package/dist/node-shims-artifact.generated.js +16 -7
  94. package/dist/npm/bin-links.d.ts +3 -1
  95. package/dist/npm/bin-links.d.ts.map +1 -1
  96. package/dist/npm/bin-links.js +32 -8
  97. package/dist/npm/cache.d.ts +11 -1
  98. package/dist/npm/cache.d.ts.map +1 -1
  99. package/dist/npm/cache.js +21 -7
  100. package/dist/npm/install-batch-facet.d.ts +4 -2
  101. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  102. package/dist/npm/install-batch-facet.js +32 -18
  103. package/dist/npm/installer.d.ts +23 -3
  104. package/dist/npm/installer.d.ts.map +1 -1
  105. package/dist/npm/installer.js +330 -131
  106. package/dist/npm/npx-install.d.ts +3 -1
  107. package/dist/npm/npx-install.d.ts.map +1 -1
  108. package/dist/npm/npx-install.js +4 -1
  109. package/dist/npm/package-lock.d.ts +32 -0
  110. package/dist/npm/package-lock.d.ts.map +1 -0
  111. package/dist/npm/package-lock.js +65 -0
  112. package/dist/npm/placement.d.ts +16 -0
  113. package/dist/npm/placement.d.ts.map +1 -0
  114. package/dist/npm/placement.js +33 -0
  115. package/dist/npm/pre-bundle-facet.d.ts +1 -30
  116. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  117. package/dist/npm/pre-bundle-facet.js +3 -5
  118. package/dist/npm/r2-cache.d.ts +12 -6
  119. package/dist/npm/r2-cache.d.ts.map +1 -1
  120. package/dist/npm/r2-cache.js +34 -16
  121. package/dist/npm/resolve-one-facet.d.ts +3 -0
  122. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  123. package/dist/npm/resolve-one-facet.js +15 -3
  124. package/dist/npm/resolver.d.ts +11 -13
  125. package/dist/npm/resolver.d.ts.map +1 -1
  126. package/dist/npm/resolver.js +12 -25
  127. package/dist/opencode-artifact.generated.js +2 -2
  128. package/dist/replica/routing.d.ts +2 -38
  129. package/dist/replica/routing.d.ts.map +1 -1
  130. package/dist/replica/routing.js +3 -55
  131. package/dist/router/index.d.ts.map +1 -1
  132. package/dist/router/index.js +15 -2
  133. package/dist/router/public-directory.d.ts +18 -0
  134. package/dist/router/public-directory.d.ts.map +1 -1
  135. package/dist/router/public-directory.js +1 -1
  136. package/dist/router/remote-api.d.ts +3 -1
  137. package/dist/router/remote-api.d.ts.map +1 -1
  138. package/dist/router/remote-api.js +42 -79
  139. package/dist/runtime/bash-repl.js +2 -2
  140. package/dist/runtime/bun-repl.d.ts.map +1 -1
  141. package/dist/runtime/bun-repl.js +2 -13
  142. package/dist/runtime/cpython-resident.d.ts.map +1 -1
  143. package/dist/runtime/cpython-resident.js +2 -10
  144. package/dist/runtime/esbuild-wasm-bytes.d.ts +37 -18
  145. package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
  146. package/dist/runtime/esbuild-wasm-bytes.js +66 -92
  147. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  148. package/dist/runtime/facet-loader-host.js +0 -7
  149. package/dist/runtime/git-bundle-artifact.d.ts +17 -0
  150. package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
  151. package/dist/runtime/git-bundle-artifact.js +25 -0
  152. package/dist/runtime/node-repl.d.ts.map +1 -1
  153. package/dist/runtime/node-repl.js +2 -13
  154. package/dist/runtime/node-shims-artifact.d.ts +22 -23
  155. package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
  156. package/dist/runtime/node-shims-artifact.js +48 -78
  157. package/dist/runtime/node-shims.d.ts.map +1 -1
  158. package/dist/runtime/node-shims.js +2358 -996
  159. package/dist/runtime/opencode-artifact.d.ts.map +1 -1
  160. package/dist/runtime/opencode-artifact.js +17 -53
  161. package/dist/runtime/opencode-facet-runner.d.ts +3 -6
  162. package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
  163. package/dist/runtime/opencode-facet-runner.js +45 -10
  164. package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
  165. package/dist/runtime/opentui-wasm-bytes.js +16 -49
  166. package/dist/runtime/package-manager.d.ts +0 -2
  167. package/dist/runtime/package-manager.d.ts.map +1 -1
  168. package/dist/runtime/package-manager.js +0 -3
  169. package/dist/runtime/python-repl.d.ts.map +1 -1
  170. package/dist/runtime/python-repl.js +4 -35
  171. package/dist/runtime/repl-session.d.ts +10 -0
  172. package/dist/runtime/repl-session.d.ts.map +1 -1
  173. package/dist/runtime/repl-session.js +7 -0
  174. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  175. package/dist/runtime/ruby-repl.js +2 -2
  176. package/dist/runtime/ruby-resident.d.ts.map +1 -1
  177. package/dist/runtime/ruby-resident.js +41 -51
  178. package/dist/runtime/runtime-catalog.d.ts +10 -3
  179. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  180. package/dist/runtime/runtime-catalog.js +125 -15
  181. package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
  182. package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
  183. package/dist/runtime/sqlite-wasm-bytes.js +21 -57
  184. package/dist/runtime/staged-source.d.ts +67 -0
  185. package/dist/runtime/staged-source.d.ts.map +1 -0
  186. package/dist/runtime/staged-source.js +113 -0
  187. package/dist/runtime/wasi/preamble.d.ts +0 -22
  188. package/dist/runtime/wasi/preamble.d.ts.map +1 -1
  189. package/dist/runtime/wasi/preamble.js +98 -1425
  190. package/dist/runtime-catalog.generated.js +1 -1
  191. package/dist/session/agent.d.ts +14 -2
  192. package/dist/session/agent.d.ts.map +1 -1
  193. package/dist/session/agent.js +57 -19
  194. package/dist/session/ai.d.ts +0 -11
  195. package/dist/session/ai.d.ts.map +1 -1
  196. package/dist/session/ai.js +0 -4
  197. package/dist/session/fs-watch.d.ts +0 -11
  198. package/dist/session/fs-watch.d.ts.map +1 -1
  199. package/dist/session/fs-watch.js +0 -21
  200. package/dist/session/hibernation.d.ts +68 -2
  201. package/dist/session/hibernation.d.ts.map +1 -1
  202. package/dist/session/hibernation.js +95 -1
  203. package/dist/session/init-phases.d.ts +1 -2
  204. package/dist/session/init-phases.d.ts.map +1 -1
  205. package/dist/session/init-phases.js +1 -2
  206. package/dist/session/init.d.ts.map +1 -1
  207. package/dist/session/init.js +7 -20
  208. package/dist/session/keys.d.ts +0 -3
  209. package/dist/session/keys.d.ts.map +1 -1
  210. package/dist/session/keys.js +0 -3
  211. package/dist/session/legacy-reset.d.ts +11 -0
  212. package/dist/session/legacy-reset.d.ts.map +1 -0
  213. package/dist/session/legacy-reset.js +16 -0
  214. package/dist/session/nimbus-session.d.ts +50 -16
  215. package/dist/session/nimbus-session.d.ts.map +1 -1
  216. package/dist/session/nimbus-session.js +77 -71
  217. package/dist/session/npm-install-port.d.ts.map +1 -1
  218. package/dist/session/npm-install-port.js +2 -0
  219. package/dist/session/programmatic.d.ts +13 -18
  220. package/dist/session/programmatic.d.ts.map +1 -1
  221. package/dist/session/programmatic.js +53 -39
  222. package/dist/session/replica-routes.d.ts +2 -3
  223. package/dist/session/replica-routes.d.ts.map +1 -1
  224. package/dist/session/replica-routes.js +3 -10
  225. package/dist/session/routes.d.ts.map +1 -1
  226. package/dist/session/routes.js +11 -12
  227. package/dist/session/rpc.d.ts +108 -21
  228. package/dist/session/rpc.d.ts.map +1 -1
  229. package/dist/session/rpc.js +194 -39
  230. package/dist/session/start-real-vite.js +2 -2
  231. package/dist/session/state-store.d.ts +1 -17
  232. package/dist/session/state-store.d.ts.map +1 -1
  233. package/dist/session/state-store.js +3 -53
  234. package/dist/session/supervisor-op.d.ts +7 -0
  235. package/dist/session/supervisor-op.d.ts.map +1 -1
  236. package/dist/session/supervisor-op.js +6 -1
  237. package/dist/session/supervisor-rpc.d.ts +116 -19
  238. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  239. package/dist/session/supervisor-rpc.js +194 -84
  240. package/dist/session/vite-command.d.ts.map +1 -1
  241. package/dist/session/vite-command.js +17 -14
  242. package/dist/session/ws.d.ts.map +1 -1
  243. package/dist/session/ws.js +20 -8
  244. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  245. package/dist/shell/npm-bin-entrypoints.js +30 -5
  246. package/dist/vfs/facet-resident-limits.d.ts +33 -0
  247. package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
  248. package/dist/vfs/facet-resident-limits.js +33 -0
  249. package/dist/vfs/facet-resident-store.d.ts +2 -10
  250. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  251. package/dist/vfs/facet-resident-store.js +1594 -219
  252. package/dist/workspace-host.d.ts +3 -1
  253. package/dist/workspace-host.d.ts.map +1 -1
  254. package/dist/workspace-host.js +2 -0
  255. package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
  256. package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
  257. package/dist/wrangler/nimbus-wrangler.js +8 -22
  258. package/package.json +34 -7
  259. package/public/_assets/esbuild-0.24.2.js +2380 -0
  260. package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
  261. package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
  262. package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
  263. package/public/_assets/runtime/{node-shims-acaa037e6d26ec0d.js → node-shims-06565b121555c194.js} +2879 -992
  264. package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
  265. package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
  266. package/scripts/build-opencode-attach-entry.mjs +51 -1
  267. package/scripts/bundle-esbuild-wasm.mjs +55 -39
  268. package/scripts/bundle-facet-workers.mjs +159 -10
  269. package/scripts/bundle-git.mjs +88 -27
  270. package/scripts/bundle-node-shims.mjs +72 -46
  271. package/scripts/bundle-runtime.mjs +18 -421
  272. package/scripts/cf-git-patch.mjs +137 -0
  273. package/scripts/patch-install-deps.mjs +49 -96
  274. package/scripts/runtime-specs.mjs +435 -0
  275. package/vendor/git-http.generated.d.ts +82 -0
  276. package/vendor/git-upstream.generated.d.ts +4378 -0
  277. package/vendor/git.LICENSE +7 -0
  278. package/vendor/git.generated.d.mts +21 -0
  279. package/vendor/git.generated.mjs +103 -0
  280. package/dist/replica/suspension.d.ts +0 -36
  281. package/dist/replica/suspension.d.ts.map +0 -1
  282. package/dist/replica/suspension.js +0 -49
  283. package/dist/runtime/static-server.d.ts +0 -3
  284. package/dist/runtime/static-server.d.ts.map +0 -1
  285. package/dist/runtime/static-server.js +0 -133
  286. package/scripts/clean-dist.mjs +0 -7
@@ -24,4 +24,4 @@
24
24
  * The empty string means "not pinned yet" — the catalog stays out of L2 and
25
25
  * the supervisor warns once per isolate.
26
26
  */
27
- export const RUNTIME_CATALOG_SHA256 = "9cdc9cc0d96667234c6fed2adc81e7890fef96b3afe5bd80dd80612e822d3d3a";
27
+ export const RUNTIME_CATALOG_SHA256 = "2827a7f7245403cb7644c27f0075423dd1ba00313b8c40f70f4dfa5bcd097ed0";
@@ -13,13 +13,25 @@ interface Host extends ProgrammaticHost, SessionAiHost {
13
13
  ctx: ProgrammaticHost['ctx'];
14
14
  env: ProgrammaticHost['env'] & Record<string, unknown>;
15
15
  }
16
- interface OAuthStatePayload {
16
+ export interface OAuthStatePayload {
17
17
  v: 1;
18
18
  nonce: string;
19
19
  sessionId: string;
20
20
  tenantSegment: string;
21
+ /** Expiry (ms since the epoch), signed with the rest. */
22
+ exp: number;
21
23
  }
22
24
  export declare function handleAgentRequest(self: Host, request: Request, url: URL): Promise<Response>;
23
- export declare function parseAgentOAuthStateParam(state: string | null): OAuthStatePayload | null;
25
+ /**
26
+ * The OAuth `state` a callback carries, if this deployment signed it. The
27
+ * router routes a callback by the session and tenant segment in `state`, so an
28
+ * unsigned one would let any client wake or create a Durable Object under any
29
+ * tenant segment; the signature (HMAC-SHA256 under the agent cookie secret)
30
+ * makes the router refuse it before routing. An expired one (its signed `exp`
31
+ * at or before `now`) is refused the same way. Null for anything else.
32
+ */
33
+ export declare function parseAgentOAuthStateParam(state: string | null, env: Record<string, unknown>, now?: number): Promise<OAuthStatePayload | null>;
34
+ /** The `state` an OAuth flow carries: `<payload>.<signature>`, both base64url. */
35
+ export declare function signAgentOAuthState(payload: OAuthStatePayload, env: Record<string, unknown>): Promise<string>;
24
36
  export {};
25
37
  //# sourceMappingURL=agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/session/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgCH,OAAO,EASL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAYL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAkB3B,UAAU,IAAK,SAAQ,gBAAgB,EAAE,aAAa;IACpD,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC7B,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxD;AAED,UAAU,iBAAiB;IACzB,CAAC,EAAE,CAAC,CAAC;IACL,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AA2BD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2ClG;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,GAAG,IAAI,CAQxF"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/session/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkCH,OAAO,EASL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAYL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAkB3B,UAAU,IAAK,SAAQ,gBAAgB,EAAE,aAAa;IACpD,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC7B,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,CAAC,CAAC;IACL,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;CACb;AA0BD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2ClG;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,GAAG,SAAa,GACf,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAWnC;AAs/BD,kFAAkF;AAClF,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAKnH"}
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { generateText, isLoopFinished, jsonSchema, streamText, tool as aiTool, } from 'ai';
11
11
  import { BASE_PATH_HEADER, TENANT_HEADER } from '../_shared/session-router.js';
12
- import { decodeJsonBase64Url, encodeJsonBase64Url, pkceChallenge, randomBase64Url, sealJson, unsealJson, } from '@nimbus-sh/core/_shared/crypto.js';
12
+ import { base64Url, base64UrlDecode, decodeJsonBase64Url, encodeJsonBase64Url, pkceChallenge, randomBase64Url, sealJson, unsealJson, } from '@nimbus-sh/core/_shared/crypto.js';
13
13
  import { clearNimbusAgentOAuthCookie, fetchNimbusCloudflareAccounts, isNimbusCloudflareAccountId, isNimbusTenantSegment, NIMBUS_CF_OAUTH_AUTH_URL, readNimbusCookie, readNimbusAgentCookieSecret, readNimbusAgentOAuthConfig, requestNimbusCloudflareOAuthToken, serializeNimbusCookie, } from './agent-oauth.js';
14
14
  import { clearSessionAiCredential, createSessionAiModel, describeSessionAiConnection, readSessionAiConfig, resolveSessionAiCredential, sessionAiAccountIsAvailable, setSessionAiAccount, storeSessionAiCredential, } from './ai.js';
15
15
  import { ensureProgrammaticReady, rpcExec, rpcEnsureRuntimes, rpcInstallRuntime, rpcExposeApp, rpcKillProcess, rpcListApps, rpcListPorts, rpcListProcesses, rpcProcessLogs, rpcStartProcess, } from './programmatic.js';
@@ -68,12 +68,29 @@ export async function handleAgentRequest(self, request, url) {
68
68
  }
69
69
  return json({ error: 'unknown agent endpoint' }, 404);
70
70
  }
71
- export function parseAgentOAuthStateParam(state) {
71
+ /**
72
+ * The OAuth `state` a callback carries, if this deployment signed it. The
73
+ * router routes a callback by the session and tenant segment in `state`, so an
74
+ * unsigned one would let any client wake or create a Durable Object under any
75
+ * tenant segment; the signature (HMAC-SHA256 under the agent cookie secret)
76
+ * makes the router refuse it before routing. An expired one (its signed `exp`
77
+ * at or before `now`) is refused the same way. Null for anything else.
78
+ */
79
+ export async function parseAgentOAuthStateParam(state, env, now = Date.now()) {
72
80
  if (!state)
73
81
  return null;
74
- const payload = decodeState(state);
82
+ let secret;
83
+ try {
84
+ secret = readNimbusAgentCookieSecret(env);
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ const payload = await decodeState(state, secret);
75
90
  if (!payload || payload.v !== 1)
76
91
  return null;
92
+ if (!Number.isSafeInteger(payload.exp) || payload.exp <= now)
93
+ return null;
77
94
  if (!isSessionId(payload.sessionId))
78
95
  return null;
79
96
  if (!isNimbusTenantSegment(payload.tenantSegment))
@@ -139,16 +156,19 @@ async function oauthStart(self, request, url) {
139
156
  const codeVerifier = randomBase64Url(48);
140
157
  const codeChallenge = await pkceChallenge(codeVerifier);
141
158
  const redirectUri = config.redirectUri;
142
- const payload = { v: 1, nonce, sessionId, tenantSegment };
143
- const state = encodeState(payload);
144
159
  const now = Date.now();
145
- const stored = {
146
- ...payload,
147
- codeVerifier,
148
- redirectUri,
149
- createdAt: now,
150
- expiresAt: now + OAUTH_STATE_TTL_MS,
151
- };
160
+ const payload = { v: 1, nonce, sessionId, tenantSegment, exp: now + OAUTH_STATE_TTL_MS };
161
+ let state;
162
+ try {
163
+ state = await signAgentOAuthState(payload, self.env);
164
+ }
165
+ catch (e) {
166
+ return json({
167
+ error: e?.message || String(e),
168
+ code: 'E_AGENT_COOKIE_SECRET',
169
+ }, 409);
170
+ }
171
+ const stored = { ...payload, codeVerifier, redirectUri, createdAt: now };
152
172
  const authUrl = new URL(NIMBUS_CF_OAUTH_AUTH_URL);
153
173
  authUrl.searchParams.set('client_id', config.oauthClientId);
154
174
  authUrl.searchParams.set('response_type', 'code');
@@ -169,18 +189,18 @@ async function oauthStart(self, request, url) {
169
189
  code: 'E_AGENT_COOKIE_SECRET',
170
190
  }, 409);
171
191
  }
172
- return json({ ok: true, authUrl: authUrl.toString(), expiresAt: stored.expiresAt }, 200, headers);
192
+ return json({ ok: true, authUrl: authUrl.toString(), expiresAt: stored.exp }, 200, headers);
173
193
  }
174
194
  async function oauthCallback(self, request, url) {
175
195
  const code = url.searchParams.get('code');
176
196
  const error = url.searchParams.get('error');
177
- const payload = parseAgentOAuthStateParam(url.searchParams.get('state'));
197
+ const payload = await parseAgentOAuthStateParam(url.searchParams.get('state'), self.env);
178
198
  if (error)
179
199
  return oauthResultHtml(false, 'Cloudflare authorization failed.', payload?.sessionId);
180
200
  if (!code || !payload)
181
201
  return oauthResultHtml(false, 'OAuth callback is missing code or state.', payload?.sessionId);
182
202
  const stored = await loadStateCookie(self, request);
183
- if (!stored || stored.expiresAt < Date.now()) {
203
+ if (!stored || !Number.isSafeInteger(stored.exp) || stored.exp <= Date.now()) {
184
204
  return oauthResultHtml(false, 'OAuth session expired. Connect again.', payload.sessionId);
185
205
  }
186
206
  if (stored.sessionId !== payload.sessionId ||
@@ -1071,12 +1091,30 @@ setTimeout(function(){ try { window.close(); } catch {} }, 700);
1071
1091
  headers: responseHeaders,
1072
1092
  });
1073
1093
  }
1074
- function encodeState(payload) {
1075
- return encodeJsonBase64Url(payload);
1094
+ const STATE_SIGNATURE_PURPOSE = 'nimbus-agent-oauth-state:v1';
1095
+ function stateSigningKey(secret, usage) {
1096
+ return crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, [usage]);
1097
+ }
1098
+ function stateSigned(body) {
1099
+ return new TextEncoder().encode(`${STATE_SIGNATURE_PURPOSE}\0${body}`);
1076
1100
  }
1077
- function decodeState(state) {
1101
+ /** The `state` an OAuth flow carries: `<payload>.<signature>`, both base64url. */
1102
+ export async function signAgentOAuthState(payload, env) {
1103
+ const secret = readNimbusAgentCookieSecret(env);
1104
+ const body = encodeJsonBase64Url(payload);
1105
+ const signature = await crypto.subtle.sign('HMAC', await stateSigningKey(secret, 'sign'), stateSigned(body));
1106
+ return `${body}.${base64Url(new Uint8Array(signature))}`;
1107
+ }
1108
+ async function decodeState(state, secret) {
1109
+ const dot = state.indexOf('.');
1110
+ if (dot <= 0 || dot !== state.lastIndexOf('.'))
1111
+ return null;
1112
+ const body = state.slice(0, dot);
1078
1113
  try {
1079
- return decodeJsonBase64Url(state);
1114
+ const signature = base64UrlDecode(state.slice(dot + 1));
1115
+ if (!await crypto.subtle.verify('HMAC', await stateSigningKey(secret, 'verify'), signature, stateSigned(body)))
1116
+ return null;
1117
+ return decodeJsonBase64Url(body);
1080
1118
  }
1081
1119
  catch {
1082
1120
  return null;
@@ -39,7 +39,6 @@
39
39
  * session; `captureSessionAiCredential` is the one place it is read.
40
40
  */
41
41
  import type { LanguageModel } from 'ai';
42
- import { z } from 'zod/v4';
43
42
  import type { PortRegistry } from '@nimbus-sh/core/runtime/port-registry.js';
44
43
  import { type NimbusCloudflareAccount } from './agent-oauth.js';
45
44
  export interface SessionAiHost {
@@ -82,13 +81,6 @@ export type SessionAiResolution = {
82
81
  ok: false;
83
82
  reason: SessionAiUnavailable;
84
83
  };
85
- declare const StoredCredentialSchema: z.ZodObject<{
86
- accessToken: z.ZodString;
87
- refreshToken: z.ZodOptional<z.ZodString>;
88
- accountId: z.ZodNullable<z.ZodString>;
89
- expiresAt: z.ZodNullable<z.ZodNumber>;
90
- }, z.core.$strip>;
91
- type StoredCredential = z.infer<typeof StoredCredentialSchema>;
92
84
  /** Base URL of the in-session endpoint. The one true address of this gateway. */
93
85
  export declare function sessionAiBaseUrl(): string;
94
86
  /**
@@ -183,13 +175,10 @@ export declare function createSessionAiModel(self: SessionAiHost): LanguageModel
183
175
  export declare function setSessionAiAccount(self: SessionAiHost, accountId: string): Promise<boolean>;
184
176
  /** Forget this session's credential (agent logout). */
185
177
  export declare function clearSessionAiCredential(self: SessionAiHost): Promise<void>;
186
- /** The stored credential, for surfaces that report connection state. */
187
- export declare function readSessionAiCredential(self: SessionAiHost): Promise<StoredCredential | null>;
188
178
  /**
189
179
  * Serve one OpenAI-compatible request. This is the whole gateway: the loopback
190
180
  * router calls it for the session's tools, and agent.ts calls it directly for
191
181
  * the Nimbus agent.
192
182
  */
193
183
  export declare function handleSessionAiRequest(self: SessionAiHost, request: Request): Promise<Response>;
194
- export {};
195
184
  //# sourceMappingURL=ai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/session/ai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/session/ai.ts"],"names":[],"mappings":"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"}
@@ -320,10 +320,6 @@ export async function clearSessionAiCredential(self) {
320
320
  lastSeenCookie.delete(self);
321
321
  await self.ctx.storage.delete(SESSION_AI_CREDENTIAL_KEY);
322
322
  }
323
- /** The stored credential, for surfaces that report connection state. */
324
- export async function readSessionAiCredential(self) {
325
- return readStoredCredential(self);
326
- }
327
323
  // ── The OpenAI-compatible endpoint ────────────────────────────────────────
328
324
  /**
329
325
  * Serve one OpenAI-compatible request. This is the whole gateway: the loopback
@@ -118,15 +118,4 @@ export declare function handleFsWatchUnsubscribe(host: FsWatchHost, ws: WebSocke
118
118
  * wsError. Idempotent + no-op when nothing pending.
119
119
  */
120
120
  export declare function cleanupFsWatchOnClose(host: FsWatchHost, ws: WebSocket): void;
121
- /**
122
- * Diagnostic: total subscriber + pending-event counts across the host.
123
- * Useful for /api/_diag/* surfaces and leak-detection probes (the
124
- * cleanup-on-disconnect probe asserts counts return to 0 after WS close).
125
- */
126
- export declare function getFsWatchStats(host: FsWatchHost): {
127
- wsCount: number;
128
- subCount: number;
129
- pendingTotal: number;
130
- droppedTotal: number;
131
- };
132
121
  //# sourceMappingURL=fs-watch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fs-watch.d.ts","sourceRoot":"","sources":["../../src/session/fs-watch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEnE,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,2DAA2D;IAC3D,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,UAAU,EAAE,GAAG,CAAC;CACjB;AAiBD,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,SAAS,EACb,GAAG,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA6F5D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,SAAS,EACb,GAAG,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgB/B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,GAAG,IAAI,CAS5E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAcA"}
1
+ {"version":3,"file":"fs-watch.d.ts","sourceRoot":"","sources":["../../src/session/fs-watch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEnE,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,2DAA2D;IAC3D,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,UAAU,EAAE,GAAG,CAAC;CACjB;AAiBD,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,SAAS,EACb,GAAG,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA6F5D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,SAAS,EACb,GAAG,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgB/B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,GAAG,IAAI,CAS5E"}
@@ -232,24 +232,3 @@ export function cleanupFsWatchOnClose(host, ws) {
232
232
  }
233
233
  map.delete(ws);
234
234
  }
235
- /**
236
- * Diagnostic: total subscriber + pending-event counts across the host.
237
- * Useful for /api/_diag/* surfaces and leak-detection probes (the
238
- * cleanup-on-disconnect probe asserts counts return to 0 after WS close).
239
- */
240
- export function getFsWatchStats(host) {
241
- const map = host._fsWatchSubs;
242
- if (!map)
243
- return { wsCount: 0, subCount: 0, pendingTotal: 0, droppedTotal: 0 };
244
- let subCount = 0;
245
- let pendingTotal = 0;
246
- let droppedTotal = 0;
247
- for (const list of map.values()) {
248
- subCount += list.length;
249
- for (const sub of list) {
250
- pendingTotal += sub.pending.length;
251
- droppedTotal += sub.dropped;
252
- }
253
- }
254
- return { wsCount: map.size, subCount, pendingTotal, droppedTotal };
255
- }
@@ -18,6 +18,8 @@
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
+ * - ensureResidentKeepalive(host, ctx) — arm the keep-alive alarm that
22
+ * holds this object in memory while a resident process runs.
21
23
  * - dispatchAlarm(host) — alarm() handler body: the fabric's generic
22
24
  * reason dispatcher with this session's handlers registered.
23
25
  * - flushOnClose(host) — synchronous flush on ws close.
@@ -25,7 +27,7 @@
25
27
  * The timer multiplexer itself (reason map, schedule, the per-instance
26
28
  * chain) is fabric machinery — `@nimbus-sh/fabric/timers.js`; this module
27
29
  * registers the session's reasons ('w9-flush' | 'log-janitor' |
28
- * 'resident-launch') on top of it.
30
+ * 'resident-launch' | 'resident-keepalive') on top of it.
29
31
  *
30
32
  * **`ctx` taken as a separate arg from `host`** because the parent
31
33
  * `CloudflareDurableObject` class declares `ctx` as `protected`, which
@@ -56,6 +58,14 @@ export interface HibHost extends TimerHost {
56
58
  _w9FlushTimer: any;
57
59
  /** W1: log-janitor alarm believed armed for this instance (cheap guard). */
58
60
  _w1JanitorArmed: boolean;
61
+ /** W1: resident keep-alive alarm believed armed for this instance. */
62
+ _w1KeepaliveArmed: boolean;
63
+ /**
64
+ * W1: when a client last reached this session over HTTP (an exec, a file
65
+ * read, a port preview, a socket upgrade). Facet RPCs are not clients: a
66
+ * process's own traffic must not keep its abandoned session alive.
67
+ */
68
+ _w1LastClientActivityAt: number;
59
69
  /** W1: destroyed-session tombstone — never re-arm alarms while set. */
60
70
  _w1SessionDestroyed: boolean;
61
71
  }
@@ -103,15 +113,69 @@ export declare function installLogPersistence(host: Pick<HibHost, '_w9PersistWir
103
113
  */
104
114
  export declare function clearDestroyedTombstone(host: HibHost, ctx: any): void;
105
115
  export declare function ensureLogJanitor(host: HibHost, ctx: any): void;
116
+ /** The fields the keep-alive rule reads and keeps; both hosts carry them. */
117
+ export type ResidentKeepaliveHost = Pick<HibHost, 'processes' | '_w1KeepaliveArmed' | '_w1LastClientActivityAt' | '_w1SessionDestroyed'>;
118
+ /** Arm the host's `resident-keepalive` alarm at `at`; resolves false when it could not. */
119
+ export type ResidentKeepaliveSchedule = (at: number) => Promise<boolean>;
120
+ /** Where a host's attached clients are counted: its hibernatable sockets. */
121
+ export type KeepaliveClients = Partial<Pick<DurableObjectState, 'getWebSockets'>>;
122
+ /**
123
+ * W1: arm the keep-alive alarm cycle for this instance, from the spawn hook
124
+ * of a LONG-RUNNING process only.
125
+ *
126
+ * A resident process lives in a facet, and a facet dies with its parent; the
127
+ * platform evicts an idle object after roughly ten seconds, and a pending
128
+ * `ctx.waitUntil` is not the in-flight event that counts (see
129
+ * RESIDENT_KEEPALIVE_MS). A quiet process sends no RPC, so without this the
130
+ * host idles out and the launch journal re-drives the process under a new
131
+ * pid namespace, dropping its attached terminal and its port. The alarm is
132
+ * the event; its dispatch is the whole payload.
133
+ *
134
+ * The one rule for both hosts: the session DO schedules through the fabric
135
+ * timer mux, a hosted runtime through its embedder's lifecycle. Idempotent
136
+ * per instance via `_w1KeepaliveArmed`; `residentKeepaliveFired` clears the
137
+ * flag when the cycle ends, so the next resident spawn re-arms it.
138
+ */
139
+ export declare function armResidentKeepalive(host: ResidentKeepaliveHost, schedule: ResidentKeepaliveSchedule): void;
140
+ /**
141
+ * W1: the keep-alive alarm fired. Deliberately no work: the alarm exists so
142
+ * the object HAS an event, and being dispatched is the entire payload.
143
+ * Returns when to fire next, or null after clearing the armed flag.
144
+ *
145
+ * Re-arms only while a resident process runs AND a client is present — the
146
+ * rule the janitor learned the hard way (see dispatchAlarm): an
147
+ * unconditional self-renewal makes every session boot its DO forever, and
148
+ * the fleet doing that resets live ones. Bounded by the resident alone, an
149
+ * abandoned dev server did exactly that. The next resident spawn, or the
150
+ * client's return, re-arms the cycle.
151
+ */
152
+ export declare function residentKeepaliveFired(host: ResidentKeepaliveHost, ctx: KeepaliveClients, now: number): number | null;
153
+ /**
154
+ * W1: a client reached the host. Records the moment, and re-arms the
155
+ * keep-alive if a resident is running and the cycle had lapsed: a host
156
+ * whose client came back before the platform evicted it still holds its
157
+ * process, and the next quiet stretch must not idle it out mid-session.
158
+ */
159
+ export declare function noteResidentClient(host: ResidentKeepaliveHost, schedule: ResidentKeepaliveSchedule): void;
160
+ export declare function ensureResidentKeepalive(host: HibHost, ctx: any): void;
106
161
  /** W9: idempotent SQL schema bootstrap. */
107
162
  export declare function ensureHibSchema(host: Pick<HibHost, '_w9SchemaInit'>, ctx: any): void;
163
+ /**
164
+ * Whether a client is here: a hibernatable socket attached (terminal,
165
+ * process log, file watch) or a request within the detached grace. The
166
+ * keep-alive re-arms on this and on a running resident, never on the
167
+ * resident alone.
168
+ */
169
+ export declare function residentClientPresent(host: ResidentKeepaliveHost, ctx: KeepaliveClients, now: number): boolean;
170
+ /** W1: a client reached the session DO (see noteResidentClient). */
171
+ export declare function noteClientActivity(host: HibHost, ctx: any): void;
108
172
  /**
109
173
  * W1: this session's canonical alarm-reason strings, registered on the
110
174
  * fabric's reason map. Forward-compat: the dispatcher silently drops unknown
111
175
  * reasons so a rollback from a future deploy that added new reasons doesn't
112
176
  * leave the alarm stuck.
113
177
  */
114
- export type AlarmReason = 'w9-flush' | 'log-janitor' | 'resident-launch';
178
+ export type AlarmReason = 'w9-flush' | 'log-janitor' | 'resident-launch' | 'resident-keepalive';
115
179
  /**
116
180
  * W9: ensure the alarm is set for the next flush window. Cheap to
117
181
  * call repeatedly — we only schedule the in-isolate flush timer if
@@ -126,6 +190,8 @@ export declare function scheduleHibFlush(host: HibHost, ctx: any): void;
126
190
  * - `'resident-launch'` → pumpResidentLaunches()
127
191
  * - `'log-janitor'` → processes.dropLogsOlderThan(orphanCheck); re-arm
128
192
  * for next 60s cycle while the session still has anything to sweep.
193
+ * - `'resident-keepalive'` → no work; the fire IS the work. Re-arms
194
+ * while a resident process is running, so the object stays in memory.
129
195
  *
130
196
  * `janitorOrphanCheck` is the orphan-pid predicate provided by the
131
197
  * caller (typically `(pid) => !host.processes.get(pid)`). Decoupled
@@ -1 +1 @@
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,CAKnE;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,eAAe,GAAG,WAAW,CAAC,EACtE,GAAG,EAAE,kBAAkB,EACvB,UAAU,EAAE,MAAM,IAAI,GACrB,IAAI,CA0GN;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,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAqBpF;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"}
1
+ {"version":3,"file":"hibernation.d.ts","sourceRoot":"","sources":["../../src/session/hibernation.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,8 @@
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
+ * - ensureResidentKeepalive(host, ctx) — arm the keep-alive alarm that
22
+ * holds this object in memory while a resident process runs.
21
23
  * - dispatchAlarm(host) — alarm() handler body: the fabric's generic
22
24
  * reason dispatcher with this session's handlers registered.
23
25
  * - flushOnClose(host) — synchronous flush on ws close.
@@ -25,7 +27,7 @@
25
27
  * The timer multiplexer itself (reason map, schedule, the per-instance
26
28
  * chain) is fabric machinery — `@nimbus-sh/fabric/timers.js`; this module
27
29
  * registers the session's reasons ('w9-flush' | 'log-janitor' |
28
- * 'resident-launch') on top of it.
30
+ * 'resident-launch' | 'resident-keepalive') on top of it.
29
31
  *
30
32
  * **`ctx` taken as a separate arg from `host`** because the parent
31
33
  * `CloudflareDurableObject` class declares `ctx` as `protected`, which
@@ -40,6 +42,7 @@
40
42
  */
41
43
  import { configureWsHibernation } from '@nimbus-sh/fabric/ws-hibernation-config.js';
42
44
  import { timers } from '@nimbus-sh/fabric/timers.js';
45
+ import { RESIDENT_KEEPALIVE_DETACHED_MS, RESIDENT_KEEPALIVE_MS } from '@nimbus-sh/platform/limits.js';
43
46
  import { SESSION_DESTROYED_KEY, W9_FLUSH_DEBOUNCE_MS } from './keys.js';
44
47
  /**
45
48
  * Run at DO ctor time. Returns the result for the class to assign to
@@ -228,6 +231,74 @@ export function ensureLogJanitor(host, ctx) {
228
231
  host._w1JanitorArmed = false;
229
232
  });
230
233
  }
234
+ /**
235
+ * W1: arm the keep-alive alarm cycle for this instance, from the spawn hook
236
+ * of a LONG-RUNNING process only.
237
+ *
238
+ * A resident process lives in a facet, and a facet dies with its parent; the
239
+ * platform evicts an idle object after roughly ten seconds, and a pending
240
+ * `ctx.waitUntil` is not the in-flight event that counts (see
241
+ * RESIDENT_KEEPALIVE_MS). A quiet process sends no RPC, so without this the
242
+ * host idles out and the launch journal re-drives the process under a new
243
+ * pid namespace, dropping its attached terminal and its port. The alarm is
244
+ * the event; its dispatch is the whole payload.
245
+ *
246
+ * The one rule for both hosts: the session DO schedules through the fabric
247
+ * timer mux, a hosted runtime through its embedder's lifecycle. Idempotent
248
+ * per instance via `_w1KeepaliveArmed`; `residentKeepaliveFired` clears the
249
+ * flag when the cycle ends, so the next resident spawn re-arms it.
250
+ */
251
+ export function armResidentKeepalive(host, schedule) {
252
+ if (host._w1KeepaliveArmed)
253
+ return;
254
+ if (host.processes.residentRunning === 0)
255
+ return;
256
+ // Same zombie-alarm rule as the janitor: a destroyed session stays inert,
257
+ // so a straggler facet RPC that wakes the dead DO and spawns cannot leave
258
+ // an eternal keep-alive loop on a session that no longer exists.
259
+ if (host._w1SessionDestroyed)
260
+ return;
261
+ // Optimistic flag (dedupes same-turn spawns), CONFIRMED by the schedule
262
+ // outcome: a failure with the flag left set would mean no alarm AND
263
+ // nothing ever re-arming until the instance recycles.
264
+ host._w1KeepaliveArmed = true;
265
+ void schedule(Date.now() + RESIDENT_KEEPALIVE_MS).then((ok) => {
266
+ if (!ok)
267
+ host._w1KeepaliveArmed = false;
268
+ });
269
+ }
270
+ /**
271
+ * W1: the keep-alive alarm fired. Deliberately no work: the alarm exists so
272
+ * the object HAS an event, and being dispatched is the entire payload.
273
+ * Returns when to fire next, or null after clearing the armed flag.
274
+ *
275
+ * Re-arms only while a resident process runs AND a client is present — the
276
+ * rule the janitor learned the hard way (see dispatchAlarm): an
277
+ * unconditional self-renewal makes every session boot its DO forever, and
278
+ * the fleet doing that resets live ones. Bounded by the resident alone, an
279
+ * abandoned dev server did exactly that. The next resident spawn, or the
280
+ * client's return, re-arms the cycle.
281
+ */
282
+ export function residentKeepaliveFired(host, ctx, now) {
283
+ if (host.processes.residentRunning > 0 && residentClientPresent(host, ctx, now)) {
284
+ return now + RESIDENT_KEEPALIVE_MS;
285
+ }
286
+ host._w1KeepaliveArmed = false;
287
+ return null;
288
+ }
289
+ /**
290
+ * W1: a client reached the host. Records the moment, and re-arms the
291
+ * keep-alive if a resident is running and the cycle had lapsed: a host
292
+ * whose client came back before the platform evicted it still holds its
293
+ * process, and the next quiet stretch must not idle it out mid-session.
294
+ */
295
+ export function noteResidentClient(host, schedule) {
296
+ host._w1LastClientActivityAt = Date.now();
297
+ armResidentKeepalive(host, schedule);
298
+ }
299
+ export function ensureResidentKeepalive(host, ctx) {
300
+ armResidentKeepalive(host, (at) => timers(host, ctx).schedule('resident-keepalive', at));
301
+ }
231
302
  /** W9: idempotent SQL schema bootstrap. */
232
303
  export function ensureHibSchema(host, ctx) {
233
304
  if (host._w9SchemaInit)
@@ -249,6 +320,22 @@ export function ensureHibSchema(host, ctx) {
249
320
  host._w9SchemaInit = false; // retry next time
250
321
  }
251
322
  }
323
+ /**
324
+ * Whether a client is here: a hibernatable socket attached (terminal,
325
+ * process log, file watch) or a request within the detached grace. The
326
+ * keep-alive re-arms on this and on a running resident, never on the
327
+ * resident alone.
328
+ */
329
+ export function residentClientPresent(host, ctx, now) {
330
+ const sockets = typeof ctx?.getWebSockets === 'function' ? ctx.getWebSockets() : [];
331
+ if (sockets.length > 0)
332
+ return true;
333
+ return now - host._w1LastClientActivityAt < RESIDENT_KEEPALIVE_DETACHED_MS;
334
+ }
335
+ /** W1: a client reached the session DO (see noteResidentClient). */
336
+ export function noteClientActivity(host, ctx) {
337
+ noteResidentClient(host, (at) => timers(host, ctx).schedule('resident-keepalive', at));
338
+ }
252
339
  /**
253
340
  * W9: ensure the alarm is set for the next flush window. Cheap to
254
341
  * call repeatedly — we only schedule the in-isolate flush timer if
@@ -286,6 +373,8 @@ export function scheduleHibFlush(host, ctx) {
286
373
  * - `'resident-launch'` → pumpResidentLaunches()
287
374
  * - `'log-janitor'` → processes.dropLogsOlderThan(orphanCheck); re-arm
288
375
  * for next 60s cycle while the session still has anything to sweep.
376
+ * - `'resident-keepalive'` → no work; the fire IS the work. Re-arms
377
+ * while a resident process is running, so the object stays in memory.
289
378
  *
290
379
  * `janitorOrphanCheck` is the orphan-pid predicate provided by the
291
380
  * caller (typically `(pid) => !host.processes.get(pid)`). Decoupled
@@ -321,6 +410,11 @@ export function dispatchAlarm(host, ctx, janitorOrphanCheck, pumpResidentLaunche
321
410
  }
322
411
  host._w1JanitorArmed = false;
323
412
  },
413
+ 'resident-keepalive': (now) => {
414
+ const rearmAt = residentKeepaliveFired(host, ctx, now);
415
+ if (rearmAt !== null)
416
+ return { rearmAt };
417
+ },
324
418
  }, () => {
325
419
  // Legacy path: pre-W1 deploys had no map. dispatchAlarm was called
326
420
  // with no map and unconditionally ran the log flush. Preserve
@@ -15,8 +15,7 @@
15
15
  * (cwd, env, mounts, scrollback). Pure SQL reads;
16
16
  * sets up locals consumed by later phases.
17
17
  * - build: Phase B — constructing Kernel + Shell + registry +
18
- * installing 60+ commands + wiring SqliteVFSProvider
19
- * mounts. Most CPU-intensive phase.
18
+ * installing 60+ commands. Most CPU-intensive phase.
20
19
  * - wire: Phase W — attaching the WebSocketTerminal to the
21
20
  * Shell, replaying persisted scrollback into the WS.
22
21
  * This is the phase B'.5 will be able to re-run on
@@ -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,0CAA0C,CAAC;AAElG,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE7E;;;;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,KAAK,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB,EAAE,OAAO,EAAE,SAAS,SAAS,EAAE,EAAE,GAAG,GAAE,MAAmB,GAAG,iBAAiB,CAG7E;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,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAC5B,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GACnC,IAAI,CAiCN"}
1
+ {"version":3,"file":"init-phases.d.ts","sourceRoot":"","sources":["../../src/session/init-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAElG,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE7E;;;;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,KAAK,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB,EAAE,OAAO,EAAE,SAAS,SAAS,EAAE,EAAE,GAAG,GAAE,MAAmB,GAAG,iBAAiB,CAG7E;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,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAC5B,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GACnC,IAAI,CAiCN"}
@@ -15,8 +15,7 @@
15
15
  * (cwd, env, mounts, scrollback). Pure SQL reads;
16
16
  * sets up locals consumed by later phases.
17
17
  * - build: Phase B — constructing Kernel + Shell + registry +
18
- * installing 60+ commands + wiring SqliteVFSProvider
19
- * mounts. Most CPU-intensive phase.
18
+ * installing 60+ commands. Most CPU-intensive phase.
20
19
  * - wire: Phase W — attaching the WebSocketTerminal to the
21
20
  * Shell, replaying persisted scrollback into the WS.
22
21
  * This is the phase B'.5 will be able to re-run on
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/session/init.ts"],"names":[],"mappings":"AAyBA,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;AAQ3E;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;CAC/B;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,QAAQ,EACd,EAAE,EAAE,SAAS,GAAG,IAAI,EACpB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAkcf"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/session/init.ts"],"names":[],"mappings":"AAyBA,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;AAQ3E;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;CAC/B;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,QAAQ,EACd,EAAE,EAAE,SAAS,GAAG,IAAI,EACpB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqbf"}