@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.
- package/NOTICE.md +5 -0
- package/README.md +10 -0
- package/dist/_shared/session-router.d.ts +7 -0
- package/dist/_shared/session-router.d.ts.map +1 -1
- package/dist/_shared/session-router.js +7 -0
- package/dist/bindings/body.d.ts +6 -0
- package/dist/bindings/body.d.ts.map +1 -0
- package/dist/bindings/body.js +37 -0
- package/dist/bindings/kv.d.ts +0 -2
- package/dist/bindings/kv.d.ts.map +1 -1
- package/dist/bindings/kv.js +3 -42
- package/dist/bindings/r2.d.ts +0 -2
- package/dist/bindings/r2.d.ts.map +1 -1
- package/dist/bindings/r2.js +4 -44
- package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
- package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
- package/dist/esbuild-cli-artifact.generated.js +17 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
- package/dist/esbuild-wasm-bundle.generated.js +24 -24
- package/dist/facets/cirrus-real.d.ts.map +1 -1
- package/dist/facets/cirrus-real.js +11 -6
- package/dist/facets/compose.d.ts +11 -7
- package/dist/facets/compose.d.ts.map +1 -1
- package/dist/facets/compose.js +8 -31
- package/dist/facets/data-plan.d.ts +79 -0
- package/dist/facets/data-plan.d.ts.map +1 -0
- package/dist/facets/data-plan.js +477 -0
- package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
- package/dist/facets/esbuild-bundle-pool.js +3 -3
- package/dist/facets/esbuild-transform.d.ts +38 -8
- package/dist/facets/esbuild-transform.d.ts.map +1 -1
- package/dist/facets/esbuild-transform.js +219 -19
- package/dist/facets/exec-telemetry.d.ts +7 -3
- package/dist/facets/exec-telemetry.d.ts.map +1 -1
- package/dist/facets/manager.d.ts +198 -69
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +1276 -652
- package/dist/facets/opencode-staging.d.ts +0 -2
- package/dist/facets/opencode-staging.d.ts.map +1 -1
- package/dist/facets/opencode-staging.js +5 -11
- package/dist/facets/process.d.ts +4 -0
- package/dist/facets/process.d.ts.map +1 -1
- package/dist/facets/process.js +3 -0
- package/dist/facets/read-profile.d.ts +149 -0
- package/dist/facets/read-profile.d.ts.map +1 -0
- package/dist/facets/read-profile.js +483 -0
- package/dist/facets/real-vite-hmr.d.ts +2 -0
- package/dist/facets/real-vite-hmr.d.ts.map +1 -1
- package/dist/facets/real-vite-hmr.js +3 -2
- package/dist/facets/resident-identity.d.ts +0 -1
- package/dist/facets/resident-identity.d.ts.map +1 -1
- package/dist/facets/resident-identity.js +0 -3
- package/dist/facets/wasm-swap-registry.d.ts +34 -25
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
- package/dist/facets/wasm-swap-registry.js +62 -56
- package/dist/facets/ws-terminal.d.ts +4 -4
- package/dist/facets/ws-terminal.d.ts.map +1 -1
- package/dist/facets/ws-terminal.js +4 -5
- package/dist/git/commands.d.ts +33 -10
- package/dist/git/commands.d.ts.map +1 -1
- package/dist/git/commands.js +1891 -197
- package/dist/git/network-facet.d.ts +12 -2
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +69 -18
- package/dist/git/unified-diff.d.ts +74 -0
- package/dist/git/unified-diff.d.ts.map +1 -0
- package/dist/git/unified-diff.js +676 -0
- package/dist/git-bundle.generated.d.ts +7 -11
- package/dist/git-bundle.generated.d.ts.map +1 -1
- package/dist/git-bundle.generated.js +7 -11
- package/dist/hosted/commands.d.ts.map +1 -1
- package/dist/hosted/commands.js +64 -245
- package/dist/hosted/runtime.d.ts +22 -15
- package/dist/hosted/runtime.d.ts.map +1 -1
- package/dist/hosted/runtime.js +72 -14
- package/dist/hosted/services.d.ts +8 -1
- package/dist/hosted/services.d.ts.map +1 -1
- package/dist/hosted/services.js +12 -13
- package/dist/hosted/session.d.ts +165 -0
- package/dist/hosted/session.d.ts.map +1 -0
- package/dist/hosted/session.js +132 -0
- package/dist/loaders/generated-workers.d.ts +6 -3
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +8 -5
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
- package/dist/loaders/npm-resolve-preamble.js +0 -27
- package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
- package/dist/loaders/pre-bundle-preamble.js +13 -8
- package/dist/node-shims-artifact.generated.d.ts +13 -4
- package/dist/node-shims-artifact.generated.d.ts.map +1 -1
- package/dist/node-shims-artifact.generated.js +16 -7
- package/dist/npm/bin-links.d.ts +3 -1
- package/dist/npm/bin-links.d.ts.map +1 -1
- package/dist/npm/bin-links.js +32 -8
- package/dist/npm/cache.d.ts +11 -1
- package/dist/npm/cache.d.ts.map +1 -1
- package/dist/npm/cache.js +21 -7
- package/dist/npm/install-batch-facet.d.ts +4 -2
- package/dist/npm/install-batch-facet.d.ts.map +1 -1
- package/dist/npm/install-batch-facet.js +32 -18
- package/dist/npm/installer.d.ts +23 -3
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +330 -131
- package/dist/npm/npx-install.d.ts +3 -1
- package/dist/npm/npx-install.d.ts.map +1 -1
- package/dist/npm/npx-install.js +4 -1
- package/dist/npm/package-lock.d.ts +32 -0
- package/dist/npm/package-lock.d.ts.map +1 -0
- package/dist/npm/package-lock.js +65 -0
- package/dist/npm/placement.d.ts +16 -0
- package/dist/npm/placement.d.ts.map +1 -0
- package/dist/npm/placement.js +33 -0
- package/dist/npm/pre-bundle-facet.d.ts +1 -30
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
- package/dist/npm/pre-bundle-facet.js +3 -5
- package/dist/npm/r2-cache.d.ts +12 -6
- package/dist/npm/r2-cache.d.ts.map +1 -1
- package/dist/npm/r2-cache.js +34 -16
- package/dist/npm/resolve-one-facet.d.ts +3 -0
- package/dist/npm/resolve-one-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.js +15 -3
- package/dist/npm/resolver.d.ts +11 -13
- package/dist/npm/resolver.d.ts.map +1 -1
- package/dist/npm/resolver.js +12 -25
- package/dist/opencode-artifact.generated.js +2 -2
- package/dist/replica/routing.d.ts +2 -38
- package/dist/replica/routing.d.ts.map +1 -1
- package/dist/replica/routing.js +3 -55
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +15 -2
- package/dist/router/public-directory.d.ts +18 -0
- package/dist/router/public-directory.d.ts.map +1 -1
- package/dist/router/public-directory.js +1 -1
- package/dist/router/remote-api.d.ts +3 -1
- package/dist/router/remote-api.d.ts.map +1 -1
- package/dist/router/remote-api.js +42 -79
- package/dist/runtime/bash-repl.js +2 -2
- package/dist/runtime/bun-repl.d.ts.map +1 -1
- package/dist/runtime/bun-repl.js +2 -13
- package/dist/runtime/cpython-resident.d.ts.map +1 -1
- package/dist/runtime/cpython-resident.js +2 -10
- package/dist/runtime/esbuild-wasm-bytes.d.ts +37 -18
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/esbuild-wasm-bytes.js +66 -92
- package/dist/runtime/facet-loader-host.d.ts.map +1 -1
- package/dist/runtime/facet-loader-host.js +0 -7
- package/dist/runtime/git-bundle-artifact.d.ts +17 -0
- package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
- package/dist/runtime/git-bundle-artifact.js +25 -0
- package/dist/runtime/node-repl.d.ts.map +1 -1
- package/dist/runtime/node-repl.js +2 -13
- package/dist/runtime/node-shims-artifact.d.ts +22 -23
- package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
- package/dist/runtime/node-shims-artifact.js +48 -78
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +2358 -996
- package/dist/runtime/opencode-artifact.d.ts.map +1 -1
- package/dist/runtime/opencode-artifact.js +17 -53
- package/dist/runtime/opencode-facet-runner.d.ts +3 -6
- package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
- package/dist/runtime/opencode-facet-runner.js +45 -10
- package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/opentui-wasm-bytes.js +16 -49
- package/dist/runtime/package-manager.d.ts +0 -2
- package/dist/runtime/package-manager.d.ts.map +1 -1
- package/dist/runtime/package-manager.js +0 -3
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +4 -35
- package/dist/runtime/repl-session.d.ts +10 -0
- package/dist/runtime/repl-session.d.ts.map +1 -1
- package/dist/runtime/repl-session.js +7 -0
- package/dist/runtime/ruby-repl.d.ts.map +1 -1
- package/dist/runtime/ruby-repl.js +2 -2
- package/dist/runtime/ruby-resident.d.ts.map +1 -1
- package/dist/runtime/ruby-resident.js +41 -51
- package/dist/runtime/runtime-catalog.d.ts +10 -3
- package/dist/runtime/runtime-catalog.d.ts.map +1 -1
- package/dist/runtime/runtime-catalog.js +125 -15
- package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
- package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/sqlite-wasm-bytes.js +21 -57
- package/dist/runtime/staged-source.d.ts +67 -0
- package/dist/runtime/staged-source.d.ts.map +1 -0
- package/dist/runtime/staged-source.js +113 -0
- package/dist/runtime/wasi/preamble.d.ts +0 -22
- package/dist/runtime/wasi/preamble.d.ts.map +1 -1
- package/dist/runtime/wasi/preamble.js +98 -1425
- package/dist/runtime-catalog.generated.js +1 -1
- package/dist/session/agent.d.ts +14 -2
- package/dist/session/agent.d.ts.map +1 -1
- package/dist/session/agent.js +57 -19
- package/dist/session/ai.d.ts +0 -11
- package/dist/session/ai.d.ts.map +1 -1
- package/dist/session/ai.js +0 -4
- package/dist/session/fs-watch.d.ts +0 -11
- package/dist/session/fs-watch.d.ts.map +1 -1
- package/dist/session/fs-watch.js +0 -21
- package/dist/session/hibernation.d.ts +68 -2
- package/dist/session/hibernation.d.ts.map +1 -1
- package/dist/session/hibernation.js +95 -1
- package/dist/session/init-phases.d.ts +1 -2
- package/dist/session/init-phases.d.ts.map +1 -1
- package/dist/session/init-phases.js +1 -2
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +7 -20
- package/dist/session/keys.d.ts +0 -3
- package/dist/session/keys.d.ts.map +1 -1
- package/dist/session/keys.js +0 -3
- package/dist/session/legacy-reset.d.ts +11 -0
- package/dist/session/legacy-reset.d.ts.map +1 -0
- package/dist/session/legacy-reset.js +16 -0
- package/dist/session/nimbus-session.d.ts +50 -16
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +77 -71
- package/dist/session/npm-install-port.d.ts.map +1 -1
- package/dist/session/npm-install-port.js +2 -0
- package/dist/session/programmatic.d.ts +13 -18
- package/dist/session/programmatic.d.ts.map +1 -1
- package/dist/session/programmatic.js +53 -39
- package/dist/session/replica-routes.d.ts +2 -3
- package/dist/session/replica-routes.d.ts.map +1 -1
- package/dist/session/replica-routes.js +3 -10
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +11 -12
- package/dist/session/rpc.d.ts +108 -21
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +194 -39
- package/dist/session/start-real-vite.js +2 -2
- package/dist/session/state-store.d.ts +1 -17
- package/dist/session/state-store.d.ts.map +1 -1
- package/dist/session/state-store.js +3 -53
- package/dist/session/supervisor-op.d.ts +7 -0
- package/dist/session/supervisor-op.d.ts.map +1 -1
- package/dist/session/supervisor-op.js +6 -1
- package/dist/session/supervisor-rpc.d.ts +116 -19
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +194 -84
- package/dist/session/vite-command.d.ts.map +1 -1
- package/dist/session/vite-command.js +17 -14
- package/dist/session/ws.d.ts.map +1 -1
- package/dist/session/ws.js +20 -8
- package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
- package/dist/shell/npm-bin-entrypoints.js +30 -5
- package/dist/vfs/facet-resident-limits.d.ts +33 -0
- package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
- package/dist/vfs/facet-resident-limits.js +33 -0
- package/dist/vfs/facet-resident-store.d.ts +2 -10
- package/dist/vfs/facet-resident-store.d.ts.map +1 -1
- package/dist/vfs/facet-resident-store.js +1594 -219
- package/dist/workspace-host.d.ts +3 -1
- package/dist/workspace-host.d.ts.map +1 -1
- package/dist/workspace-host.js +2 -0
- package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
- package/dist/wrangler/nimbus-wrangler.js +8 -22
- package/package.json +34 -7
- package/public/_assets/esbuild-0.24.2.js +2380 -0
- package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
- package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
- package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
- package/public/_assets/runtime/{node-shims-acaa037e6d26ec0d.js → node-shims-06565b121555c194.js} +2879 -992
- package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
- package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
- package/scripts/build-opencode-attach-entry.mjs +51 -1
- package/scripts/bundle-esbuild-wasm.mjs +55 -39
- package/scripts/bundle-facet-workers.mjs +159 -10
- package/scripts/bundle-git.mjs +88 -27
- package/scripts/bundle-node-shims.mjs +72 -46
- package/scripts/bundle-runtime.mjs +18 -421
- package/scripts/cf-git-patch.mjs +137 -0
- package/scripts/patch-install-deps.mjs +49 -96
- package/scripts/runtime-specs.mjs +435 -0
- package/vendor/git-http.generated.d.ts +82 -0
- package/vendor/git-upstream.generated.d.ts +4378 -0
- package/vendor/git.LICENSE +7 -0
- package/vendor/git.generated.d.mts +21 -0
- package/vendor/git.generated.mjs +103 -0
- package/dist/replica/suspension.d.ts +0 -36
- package/dist/replica/suspension.d.ts.map +0 -1
- package/dist/replica/suspension.js +0 -49
- package/dist/runtime/static-server.d.ts +0 -3
- package/dist/runtime/static-server.d.ts.map +0 -1
- package/dist/runtime/static-server.js +0 -133
- 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 = "
|
|
27
|
+
export const RUNTIME_CATALOG_SHA256 = "2827a7f7245403cb7644c27f0075423dd1ba00313b8c40f70f4dfa5bcd097ed0";
|
package/dist/session/agent.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
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"}
|
package/dist/session/agent.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
1075
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/dist/session/ai.d.ts
CHANGED
|
@@ -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
|
package/dist/session/ai.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/session/ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/session/ai.ts"],"names":[],"mappings":"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"}
|
package/dist/session/ai.js
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/session/fs-watch.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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"}
|