@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
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What resident node processes read synchronously and did not have, per
|
|
3
|
+
* installed package, shared across sessions.
|
|
4
|
+
*
|
|
5
|
+
* A launch holds its data plan (data-plan.ts) and module map; a file neither
|
|
6
|
+
* names is a first miss: the read fails with EAGAIN naming it, and the facet
|
|
7
|
+
* faults the file in with an async read through the supervisor. Such a path
|
|
8
|
+
* belongs to a package, not to a session (`dist/runtime/x.js` of one tarball
|
|
9
|
+
* is the same file for everyone), so it is recorded under the package's
|
|
10
|
+
* integrity (the hash the lockfile pins the tarball to; for a package no
|
|
11
|
+
* lockfile pins, the content key of its package.json), and a later launch
|
|
12
|
+
* that loads that exact tarball can hold the file from its first instruction.
|
|
13
|
+
*
|
|
14
|
+
* The profile is shared by every tenant, so nothing in it is taken on a
|
|
15
|
+
* program's word:
|
|
16
|
+
* - Evidence (`verifiedEvidence`) is a reported miss the SUPERVISOR served
|
|
17
|
+
* an async read for, for that process, that is a regular file inside a
|
|
18
|
+
* package as the process's own credential stats it. A program that lies
|
|
19
|
+
* about its misses names paths it was never served, and they are dropped.
|
|
20
|
+
* - Who observed or vouched is a PRINCIPAL: the verified tenant and
|
|
21
|
+
* subject the router put in the session's Durable Object name, never
|
|
22
|
+
* anything the session or the program says. Session ids are free to mint,
|
|
23
|
+
* so counting sessions would bound nothing. Anonymous sessions
|
|
24
|
+
* (legacy-public, or the `anon` tenant) are one principal anyone can be:
|
|
25
|
+
* they read profiles and never write to them.
|
|
26
|
+
* - An entry is shared only once two different principals have observed
|
|
27
|
+
* it, so one party alone cannot seed what every other tenant stages.
|
|
28
|
+
* - A principal's writes to one package's profile are capped per hour,
|
|
29
|
+
* the count kept in the profile itself.
|
|
30
|
+
* - What a shared profile adds to one launch is bounded in bytes, a share of
|
|
31
|
+
* the launch's own plan budget, not in paths.
|
|
32
|
+
* - Entries earn their place, and only the supervisor can raise one: a
|
|
33
|
+
* launch that staged an entry and was never asked to fault it in raises
|
|
34
|
+
* its score, once per principal, so a score counts the distinct
|
|
35
|
+
* principals that vouched for it; the program saying it never read the entry lowers
|
|
36
|
+
* it (a program's word can only lower); a launch that reported nothing
|
|
37
|
+
* is no information either way; a plan that found no regular file there
|
|
38
|
+
* removes it; at zero it is gone.
|
|
39
|
+
* - It stores package-relative paths only, validated on the way in and on
|
|
40
|
+
* the way out, never content. At launch an entry becomes a path inside a
|
|
41
|
+
* package directory of the session's OWN filesystem, planned only where
|
|
42
|
+
* the credentialed listing shows a regular file and read through the same
|
|
43
|
+
* credentialed authority as every other planned file. So the worst a
|
|
44
|
+
* poisoned profile can do is stage more of the session's own files,
|
|
45
|
+
* within the byte share.
|
|
46
|
+
*/
|
|
47
|
+
import { packageRootOf } from './data-plan.js';
|
|
48
|
+
import { ANONYMOUS_TENANT } from '../_shared/session-router.js';
|
|
49
|
+
import { ID_COMPONENT_RE } from '../auth/types.js';
|
|
50
|
+
/**
|
|
51
|
+
* Profiles live in the npm tarball cache bucket (NPM_TARBALL_CACHE), per
|
|
52
|
+
* package version like the tarballs, under their own prefix: tarball keys are
|
|
53
|
+
* `v2/t/...` (npm/r2-cache.ts), so the keyspaces never meet.
|
|
54
|
+
*/
|
|
55
|
+
const PREFIX = 'read-profiles/v3/';
|
|
56
|
+
/** How long a listing of which packages have profiles is reused. */
|
|
57
|
+
const INDEX_TTL_MS = 60_000;
|
|
58
|
+
/** Entries one package's profile stores (a storage bound, not what a launch stages). */
|
|
59
|
+
export const READ_PROFILE_MAX_ENTRIES = 1024;
|
|
60
|
+
/** Bytes of one profile path. */
|
|
61
|
+
export const READ_PROFILE_MAX_PATH_LENGTH = 512;
|
|
62
|
+
/** Distinct principals an entry must be observed by before it is shared. */
|
|
63
|
+
export const READ_PROFILE_SHARE_AFTER = 2;
|
|
64
|
+
/** Principal tags an entry keeps. */
|
|
65
|
+
const MAX_SEEN = 4;
|
|
66
|
+
/** Writes one principal may make to one package's profile per window. */
|
|
67
|
+
export const READ_PROFILE_WRITES_PER_WINDOW = 8;
|
|
68
|
+
const WRITE_WINDOW_MS = 60 * 60_000;
|
|
69
|
+
/** Principals whose write counts one profile keeps (the oldest window goes first). */
|
|
70
|
+
const MAX_WRITERS = 256;
|
|
71
|
+
/**
|
|
72
|
+
* Tries of one read-modify-write. A write is conditional on the object being
|
|
73
|
+
* the one read (R2's etag), so a writer that raced another re-reads and
|
|
74
|
+
* applies its change again rather than overwriting the other's. A try is lost
|
|
75
|
+
* only to another writer's success, so up to this many concurrent writers of
|
|
76
|
+
* one profile all land.
|
|
77
|
+
*/
|
|
78
|
+
const WRITE_ATTEMPTS = 16;
|
|
79
|
+
/** A score's ceiling: one unread launch per point before an entry is dropped. */
|
|
80
|
+
const MAX_SCORE = 8;
|
|
81
|
+
/** A tarball integrity (SRI), or the content key of an unpinned package's package.json. */
|
|
82
|
+
const IDENTITY = /^(?:sha(?:256|384|512)-[A-Za-z0-9+/]+={0,2}|pkgjson:[0-9a-f]{32,128})$/;
|
|
83
|
+
const TAG = /^[0-9a-f]{16}$/;
|
|
84
|
+
/** A package-relative path a profile may hold, or false. */
|
|
85
|
+
export function validProfilePath(rel) {
|
|
86
|
+
if (typeof rel !== 'string' || rel.length === 0 || rel.length > READ_PROFILE_MAX_PATH_LENGTH)
|
|
87
|
+
return false;
|
|
88
|
+
if (rel.includes('\0') || rel.includes('\\'))
|
|
89
|
+
return false;
|
|
90
|
+
const segments = rel.split('/');
|
|
91
|
+
return segments.every((s) => s !== '' && s !== '.' && s !== '..') && !segments.includes('node_modules');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The principal a session writes to profiles as: its Durable Object name's
|
|
95
|
+
* tenant segment (`<tn>:<sub>`, set by the router from the verified token),
|
|
96
|
+
* or null when the session is anonymous or has no such name, and so may only
|
|
97
|
+
* read.
|
|
98
|
+
*/
|
|
99
|
+
export function profilePrincipal(tenantSegment) {
|
|
100
|
+
// Only the shape the router mints from a verified token, `<tn>:<sub or _>`
|
|
101
|
+
// (auth/token.ts doInstanceName): legacy-public, a fanout peer's
|
|
102
|
+
// `nbf:<tag>:<coord>` and every other DO name write nothing.
|
|
103
|
+
if (typeof tenantSegment !== 'string')
|
|
104
|
+
return null;
|
|
105
|
+
const parts = tenantSegment.split(':');
|
|
106
|
+
if (parts.length !== 2 || !parts.every((part) => ID_COMPONENT_RE.test(part)))
|
|
107
|
+
return null;
|
|
108
|
+
if (parts[0] === ANONYMOUS_TENANT)
|
|
109
|
+
return null;
|
|
110
|
+
return tenantSegment;
|
|
111
|
+
}
|
|
112
|
+
/** A principal's tag in a profile: never the principal itself. */
|
|
113
|
+
export async function principalTag(principal) {
|
|
114
|
+
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(principal)));
|
|
115
|
+
return Array.from(digest.subarray(0, 8), (b) => b.toString(16).padStart(2, '0')).join('');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The misses worth recording: those in `reported` (what the program says it
|
|
119
|
+
* missed) that the supervisor itself `served` an async read for, and that
|
|
120
|
+
* `stat` (as the process's credential) shows as a regular file inside a
|
|
121
|
+
* package. Everything else the program claims is dropped.
|
|
122
|
+
*/
|
|
123
|
+
export async function verifiedEvidence(reported, served, stat) {
|
|
124
|
+
const out = [];
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
for (const raw of reported) {
|
|
127
|
+
if (typeof raw !== 'string')
|
|
128
|
+
continue;
|
|
129
|
+
const path = raw.replace(/^\/+/, '');
|
|
130
|
+
if (seen.has(path) || !served.has(path))
|
|
131
|
+
continue;
|
|
132
|
+
seen.add(path);
|
|
133
|
+
const root = packageRootOf(path);
|
|
134
|
+
if (root === null || !validProfilePath(path.slice(root.length + 1)))
|
|
135
|
+
continue;
|
|
136
|
+
let st;
|
|
137
|
+
try {
|
|
138
|
+
st = await stat('/' + path);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (st === null || st.type !== 'file')
|
|
144
|
+
continue;
|
|
145
|
+
out.push({ path, size: st.size });
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The paths a supervisor served async reads for, per process. Bounded per
|
|
151
|
+
* process: evidence is what a process was served after a miss, and a process
|
|
152
|
+
* that reads more than this many distinct files keeps its first ones.
|
|
153
|
+
*/
|
|
154
|
+
export class ServedReads {
|
|
155
|
+
static MAX_PER_PROCESS = 4096;
|
|
156
|
+
byPid = new Map();
|
|
157
|
+
note(pid, path) {
|
|
158
|
+
if (typeof path !== 'string' || !Number.isInteger(pid) || pid <= 0)
|
|
159
|
+
return;
|
|
160
|
+
const key = path.replace(/^\/+/, '');
|
|
161
|
+
if (key === '')
|
|
162
|
+
return;
|
|
163
|
+
let set = this.byPid.get(pid);
|
|
164
|
+
if (!set)
|
|
165
|
+
this.byPid.set(pid, set = new Set());
|
|
166
|
+
if (set.size < ServedReads.MAX_PER_PROCESS)
|
|
167
|
+
set.add(key);
|
|
168
|
+
}
|
|
169
|
+
/** What `pid` was served, and forget it. */
|
|
170
|
+
take(pid) {
|
|
171
|
+
const set = this.byPid.get(pid) ?? new Set();
|
|
172
|
+
this.byPid.delete(pid);
|
|
173
|
+
return set;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export class ReadProfile {
|
|
177
|
+
bucket;
|
|
178
|
+
now;
|
|
179
|
+
onConflict;
|
|
180
|
+
index = null;
|
|
181
|
+
/** onConflict reports a change after every conditional write fails. */
|
|
182
|
+
constructor(bucket, now = Date.now, onConflict) {
|
|
183
|
+
this.bucket = bucket;
|
|
184
|
+
this.now = now;
|
|
185
|
+
this.onConflict = onConflict;
|
|
186
|
+
}
|
|
187
|
+
static key(integrity) {
|
|
188
|
+
return IDENTITY.test(integrity) ? PREFIX + encodeURIComponent(integrity) : null;
|
|
189
|
+
}
|
|
190
|
+
/** Group paths under their package's profile key. */
|
|
191
|
+
static byPackage(items, integrityOf) {
|
|
192
|
+
const out = new Map();
|
|
193
|
+
for (const item of items) {
|
|
194
|
+
const path = item.path.replace(/^\/+/, '');
|
|
195
|
+
const root = packageRootOf(path);
|
|
196
|
+
if (root === null)
|
|
197
|
+
continue;
|
|
198
|
+
const rel = path.slice(root.length + 1);
|
|
199
|
+
if (!validProfilePath(rel))
|
|
200
|
+
continue;
|
|
201
|
+
const integrity = integrityOf(root);
|
|
202
|
+
const key = integrity === null ? null : ReadProfile.key(integrity);
|
|
203
|
+
if (key === null)
|
|
204
|
+
continue;
|
|
205
|
+
let list = out.get(key);
|
|
206
|
+
if (!list)
|
|
207
|
+
out.set(key, list = []);
|
|
208
|
+
list.push({ item, rel });
|
|
209
|
+
}
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* File what one principal's process observed (`verifiedEvidence`). Each
|
|
214
|
+
* entry keeps the distinct principals that observed it; it is shared once
|
|
215
|
+
* there are two. `tag` is null for a session that may not write (anonymous).
|
|
216
|
+
*/
|
|
217
|
+
async observe(evidence, tag, integrityOf) {
|
|
218
|
+
if (tag === null || !TAG.test(tag))
|
|
219
|
+
return 0;
|
|
220
|
+
let changed = 0;
|
|
221
|
+
for (const [key, items] of ReadProfile.byPackage(evidence, integrityOf)) {
|
|
222
|
+
let observed = 0;
|
|
223
|
+
const wrote = await this.update(key, tag, 'observe', ({ entries }) => {
|
|
224
|
+
let dirty = false;
|
|
225
|
+
observed = 0;
|
|
226
|
+
for (const { item, rel } of items) {
|
|
227
|
+
const size = Math.max(0, Math.floor(item.size));
|
|
228
|
+
let entry = entries.get(rel);
|
|
229
|
+
if (!entry) {
|
|
230
|
+
if (!ReadProfile.makeRoom(entries))
|
|
231
|
+
continue;
|
|
232
|
+
entry = { size, seen: [], vouched: [], score: 0 };
|
|
233
|
+
entries.set(rel, entry);
|
|
234
|
+
}
|
|
235
|
+
entry.size = size;
|
|
236
|
+
if (!entry.seen.includes(tag)) {
|
|
237
|
+
entry.seen = [...entry.seen, tag].slice(-MAX_SEEN);
|
|
238
|
+
dirty = true;
|
|
239
|
+
observed++;
|
|
240
|
+
}
|
|
241
|
+
if (entry.score < 1) {
|
|
242
|
+
entry.score = 1;
|
|
243
|
+
dirty = true;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return dirty;
|
|
247
|
+
});
|
|
248
|
+
if (wrote === 'written') {
|
|
249
|
+
this.index?.keys.add(key);
|
|
250
|
+
changed += observed;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return changed;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* One read-modify-write of `key` by `tag`: `mutate` changes the profile
|
|
257
|
+
* read and says whether it did. The write is conditional on the object
|
|
258
|
+
* still being the one read, and is tried again from a fresh read when
|
|
259
|
+
* another writer got there first, so concurrent writers each land. A
|
|
260
|
+
* change that lost every try is a `conflict`: said, and counted by the
|
|
261
|
+
* owner (`onConflict`), never dropped silently.
|
|
262
|
+
*/
|
|
263
|
+
async update(key, tag, kind, mutate) {
|
|
264
|
+
for (let attempt = 0; attempt < WRITE_ATTEMPTS; attempt++) {
|
|
265
|
+
const { profile, etag } = await this.readVersioned(key);
|
|
266
|
+
if (!mutate(profile))
|
|
267
|
+
return 'unchanged';
|
|
268
|
+
if (!this.admitWrite(profile, tag))
|
|
269
|
+
return 'over-cap';
|
|
270
|
+
if (await this.write(key, profile, etag))
|
|
271
|
+
return 'written';
|
|
272
|
+
}
|
|
273
|
+
console.warn(`[read-profile] ${kind} of ${key} lost ${WRITE_ATTEMPTS} write races and was dropped`);
|
|
274
|
+
this.onConflict?.(key, kind);
|
|
275
|
+
return 'conflict';
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Count one write by `tag` to `profile`, or refuse it: a principal writes
|
|
279
|
+
* one package's profile at most READ_PROFILE_WRITES_PER_WINDOW times per
|
|
280
|
+
* window, so no one party can churn an object every tenant reads.
|
|
281
|
+
*/
|
|
282
|
+
admitWrite(profile, tag) {
|
|
283
|
+
const now = this.now();
|
|
284
|
+
const current = profile.writes.get(tag);
|
|
285
|
+
const count = current && now - current[0] < WRITE_WINDOW_MS ? current[1] : 0;
|
|
286
|
+
if (count >= READ_PROFILE_WRITES_PER_WINDOW)
|
|
287
|
+
return false;
|
|
288
|
+
profile.writes.delete(tag);
|
|
289
|
+
profile.writes.set(tag, [count === 0 ? now : current[0], count + 1]);
|
|
290
|
+
for (const [writer, [start]] of profile.writes) {
|
|
291
|
+
if (profile.writes.size <= MAX_WRITERS && now - start < WRITE_WINDOW_MS)
|
|
292
|
+
break;
|
|
293
|
+
profile.writes.delete(writer);
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* A full profile evicts its weakest unshared entry for a new one; shared
|
|
299
|
+
* entries are never evicted for an observation only one principal made.
|
|
300
|
+
*/
|
|
301
|
+
static makeRoom(entries) {
|
|
302
|
+
if (entries.size < READ_PROFILE_MAX_ENTRIES)
|
|
303
|
+
return true;
|
|
304
|
+
let weakest = null;
|
|
305
|
+
for (const [rel, entry] of entries) {
|
|
306
|
+
if (entry.seen.length >= READ_PROFILE_SHARE_AFTER)
|
|
307
|
+
continue;
|
|
308
|
+
if (weakest === null || entry.score < entries.get(weakest).score)
|
|
309
|
+
weakest = rel;
|
|
310
|
+
}
|
|
311
|
+
if (weakest === null)
|
|
312
|
+
return false;
|
|
313
|
+
entries.delete(weakest);
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* The shared entries for the packages at `roots` (namespace keys), best
|
|
318
|
+
* first (score, then smaller files), whose sizes add up to at most
|
|
319
|
+
* `budgetBytes`.
|
|
320
|
+
*/
|
|
321
|
+
async lookup(roots, integrityOf, budgetBytes) {
|
|
322
|
+
const index = await this.listIndex();
|
|
323
|
+
if (index.size === 0)
|
|
324
|
+
return [];
|
|
325
|
+
const candidates = [];
|
|
326
|
+
for (const root of new Set(roots)) {
|
|
327
|
+
const integrity = integrityOf(root);
|
|
328
|
+
const key = integrity === null ? null : ReadProfile.key(integrity);
|
|
329
|
+
if (key === null || !index.has(key))
|
|
330
|
+
continue;
|
|
331
|
+
for (const [rel, entry] of (await this.read(key)).entries) {
|
|
332
|
+
if (entry.seen.length < READ_PROFILE_SHARE_AFTER || entry.score < 1)
|
|
333
|
+
continue;
|
|
334
|
+
candidates.push({ path: `${root}/${rel}`, size: entry.size, score: entry.score, key, rel });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
candidates.sort((a, b) => b.score - a.score || a.size - b.size || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
338
|
+
const out = [];
|
|
339
|
+
let used = 0;
|
|
340
|
+
for (const c of candidates) {
|
|
341
|
+
if (used + c.size > budgetBytes)
|
|
342
|
+
continue;
|
|
343
|
+
used += c.size;
|
|
344
|
+
out.push({ path: c.path, size: c.size, object: c.key, rel: c.rel });
|
|
345
|
+
}
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* What one launch did with the entries `lookup` gave it. `unread` is what
|
|
350
|
+
* the process reported it never read (its word can only lower a score), or
|
|
351
|
+
* null when it reported no list at all (a launch that died before its
|
|
352
|
+
* report), which says nothing about any entry; `served` is what the
|
|
353
|
+
* supervisor served it async reads for during the launch (a staged file the
|
|
354
|
+
* process used is never faulted in, so an entry staged and not in `served`
|
|
355
|
+
* is the supervisor's evidence it was held); `unresolved` is what the plan
|
|
356
|
+
* found no regular file for; `tag` is the launching session's principal's,
|
|
357
|
+
* or null for a session that may not write (anonymous), whose launch
|
|
358
|
+
* changes nothing.
|
|
359
|
+
* unresolved -> removed
|
|
360
|
+
* no report -> unchanged
|
|
361
|
+
* reported unread -> score - 1
|
|
362
|
+
* staged, never served, tag not vouched -> score + 1 (at most MAX_SCORE)
|
|
363
|
+
* otherwise -> unchanged
|
|
364
|
+
* A score of zero removes the entry.
|
|
365
|
+
*/
|
|
366
|
+
async settle(staged, unread, served, unresolved, tag) {
|
|
367
|
+
if (tag === null || !TAG.test(tag))
|
|
368
|
+
return;
|
|
369
|
+
const key = (p) => p.replace(/^\/+/, '');
|
|
370
|
+
const unreadKeys = unread === null ? null : new Set([...unread].map(key));
|
|
371
|
+
const unresolvedKeys = new Set([...unresolved].map(key));
|
|
372
|
+
const byKey = new Map();
|
|
373
|
+
for (const entry of staged) {
|
|
374
|
+
// Only an object this module names, for a path it validates.
|
|
375
|
+
if (!entry.object.startsWith(PREFIX) || !validProfilePath(entry.rel))
|
|
376
|
+
continue;
|
|
377
|
+
let list = byKey.get(entry.object);
|
|
378
|
+
if (!list)
|
|
379
|
+
byKey.set(entry.object, list = []);
|
|
380
|
+
list.push({ rel: entry.rel, path: key(entry.path) });
|
|
381
|
+
}
|
|
382
|
+
for (const [objectKey, items] of byKey) {
|
|
383
|
+
await this.update(objectKey, tag, 'settle', ({ entries }) => {
|
|
384
|
+
let dirty = false;
|
|
385
|
+
for (const { rel, path } of items) {
|
|
386
|
+
const entry = entries.get(rel);
|
|
387
|
+
if (!entry)
|
|
388
|
+
continue;
|
|
389
|
+
if (unresolvedKeys.has(path)) {
|
|
390
|
+
entries.delete(rel);
|
|
391
|
+
dirty = true;
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
if (unreadKeys === null)
|
|
395
|
+
continue;
|
|
396
|
+
if (unreadKeys.has(path))
|
|
397
|
+
entry.score -= 1;
|
|
398
|
+
else if (!served.has(path) && !entry.vouched.includes(tag)) {
|
|
399
|
+
entry.vouched = [...entry.vouched, tag].slice(-MAX_SCORE);
|
|
400
|
+
entry.score = Math.min(MAX_SCORE, entry.score + 1);
|
|
401
|
+
}
|
|
402
|
+
else
|
|
403
|
+
continue;
|
|
404
|
+
dirty = true;
|
|
405
|
+
if (entry.score <= 0)
|
|
406
|
+
entries.delete(rel);
|
|
407
|
+
}
|
|
408
|
+
return dirty;
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/** Store `profile` if `key` is still the object `etag` names (null: still absent). */
|
|
413
|
+
async write(key, profile, etag) {
|
|
414
|
+
const body = {};
|
|
415
|
+
for (const rel of [...profile.entries.keys()].sort())
|
|
416
|
+
body[rel] = profile.entries.get(rel);
|
|
417
|
+
const stored = await this.bucket.put(key, JSON.stringify({ entries: body, writes: Object.fromEntries(profile.writes) }), { onlyIf: etag === null ? { etagDoesNotMatch: '*' } : { etagMatches: etag } });
|
|
418
|
+
return stored !== null;
|
|
419
|
+
}
|
|
420
|
+
async read(key) {
|
|
421
|
+
return (await this.readVersioned(key)).profile;
|
|
422
|
+
}
|
|
423
|
+
async readVersioned(key) {
|
|
424
|
+
const entries = new Map();
|
|
425
|
+
const writes = new Map();
|
|
426
|
+
const profile = { entries, writes };
|
|
427
|
+
const object = await this.bucket.get(key);
|
|
428
|
+
if (!object)
|
|
429
|
+
return { profile, etag: null };
|
|
430
|
+
const etag = typeof object.etag === 'string' ? object.etag : null;
|
|
431
|
+
try {
|
|
432
|
+
const parsed = JSON.parse(await object.text());
|
|
433
|
+
if (typeof parsed.writes === 'object' && parsed.writes !== null) {
|
|
434
|
+
for (const [tag, raw] of Object.entries(parsed.writes)) {
|
|
435
|
+
if (writes.size >= MAX_WRITERS)
|
|
436
|
+
break;
|
|
437
|
+
if (!TAG.test(tag) || !Array.isArray(raw) || raw.length !== 2)
|
|
438
|
+
continue;
|
|
439
|
+
const [start, count] = raw;
|
|
440
|
+
if (typeof start !== 'number' || !Number.isFinite(start) || !Number.isInteger(count) || count < 0)
|
|
441
|
+
continue;
|
|
442
|
+
writes.set(tag, [start, count]);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (typeof parsed.entries !== 'object' || parsed.entries === null)
|
|
446
|
+
return { profile, etag };
|
|
447
|
+
for (const [rel, raw] of Object.entries(parsed.entries)) {
|
|
448
|
+
if (entries.size >= READ_PROFILE_MAX_ENTRIES)
|
|
449
|
+
break;
|
|
450
|
+
if (!validProfilePath(rel) || typeof raw !== 'object' || raw === null)
|
|
451
|
+
continue;
|
|
452
|
+
const { size, seen, vouched, score } = raw;
|
|
453
|
+
if (typeof size !== 'number' || !Number.isFinite(size) || size < 0)
|
|
454
|
+
continue;
|
|
455
|
+
if (typeof score !== 'number' || !Number.isInteger(score) || score < 1)
|
|
456
|
+
continue;
|
|
457
|
+
const tagsOf = (list, max) => Array.isArray(list) ? [...new Set(list.filter((t) => typeof t === 'string' && TAG.test(t)))].slice(-max) : [];
|
|
458
|
+
const vouchers = tagsOf(vouched, MAX_SCORE);
|
|
459
|
+
// A score is observation (1) plus distinct vouching principals; a stored
|
|
460
|
+
// score past that is not one this module wrote.
|
|
461
|
+
entries.set(rel, { size: Math.floor(size), seen: tagsOf(seen, MAX_SEEN), vouched: vouchers, score: Math.min(score, 1 + vouchers.length, MAX_SCORE) });
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
// A malformed object is an empty profile.
|
|
466
|
+
}
|
|
467
|
+
return { profile, etag };
|
|
468
|
+
}
|
|
469
|
+
async listIndex() {
|
|
470
|
+
if (this.index && this.now() - this.index.at < INDEX_TTL_MS)
|
|
471
|
+
return this.index.keys;
|
|
472
|
+
const keys = new Set();
|
|
473
|
+
let cursor;
|
|
474
|
+
do {
|
|
475
|
+
const page = await this.bucket.list({ prefix: PREFIX, ...(cursor ? { cursor } : {}) });
|
|
476
|
+
for (const object of page.objects)
|
|
477
|
+
keys.add(object.key);
|
|
478
|
+
cursor = page.truncated ? page.cursor : undefined;
|
|
479
|
+
} while (cursor);
|
|
480
|
+
this.index = { at: this.now(), keys };
|
|
481
|
+
return keys;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
* fs shim is streaming VFS events.
|
|
36
36
|
*/
|
|
37
37
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
38
|
+
import type { HostRoute } from '@nimbus-sh/fabric/composition.js';
|
|
38
39
|
/**
|
|
39
40
|
* Supervisor-side registry of active HMR connections for a single
|
|
40
41
|
* real-vite session. One instance lives on each NimbusSession that has
|
|
@@ -110,6 +111,7 @@ export declare function registerHmrBridge(doId: string, holder: {
|
|
|
110
111
|
*/
|
|
111
112
|
export declare class CirrusHmrRPC extends WorkerEntrypoint<object, {
|
|
112
113
|
doId?: string;
|
|
114
|
+
route?: HostRoute;
|
|
113
115
|
}> {
|
|
114
116
|
private _bridge;
|
|
115
117
|
private _stub;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"real-vite-hmr.d.ts","sourceRoot":"","sources":["../../src/facets/real-vite-hmr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AASH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"real-vite-hmr.d.ts","sourceRoot":"","sources":["../../src/facets/real-vite-hmr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AASH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAalE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,SAAS;IACpB,2BAA2B;IAC3B,OAAO,CAAC,OAAO,CAAgC;IAC/C,kDAAkD;IAClD,OAAO,CAAC,OAAO,CAAiH;IAChI,8DAA8D;IAC9D,OAAO,CAAC,QAAQ,CAA0C;IAC1D,oEAAoE;IAC7D,kBAAkB,UAAS;IAClC,OAAO,CAAC,OAAO,CAAK;IAEpB,wEAAwE;IACxE,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM;IAOnC,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK9B,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAInD,6EAA6E;IAC7E,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAapD;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAIjE,OAAO,CAAC,IAAI;IAWZ;;;;OAIG;IACG,UAAU,CAAC,SAAS,GAAE,MAAe,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAkB5D,2BAA2B;IAC3B,IAAI,IAAI,IAAI,MAAM,CAA8B;IAEhD,uDAAuD;IACvD,QAAQ,IAAI,IAAI;CAYjB;AAUD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;IAAE,GAAG,EAAE,SAAS,CAAA;CAAE,GAAG,IAAI,CAEhF;AAKD;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAa,SAAQ,gBAAgB,CAAC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;IAC9F,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,KAAK;IAeP,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5D,YAAY,CAAC,SAAS,GAAE,MAAe,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;CAO/D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CA2HjD;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CA0EvD"}
|
|
@@ -233,9 +233,10 @@ export class CirrusHmrRPC extends WorkerEntrypoint {
|
|
|
233
233
|
return null;
|
|
234
234
|
let stub = null;
|
|
235
235
|
try {
|
|
236
|
-
const
|
|
236
|
+
const route = this.ctx.props?.route;
|
|
237
|
+
const binding = hostNamespaceBinding(this.env, 'CirrusHmrRPC', route);
|
|
237
238
|
stub = binding.get(binding.idFromString(doId));
|
|
238
|
-
return { stub, dispatch: hostOpDispatch(stub, 'CirrusHmrRPC') };
|
|
239
|
+
return { stub, dispatch: hostOpDispatch(stub, 'CirrusHmrRPC', route) };
|
|
239
240
|
}
|
|
240
241
|
catch (error) {
|
|
241
242
|
disposeRpcResource(stub);
|
|
@@ -19,5 +19,4 @@
|
|
|
19
19
|
export declare const DERIVED_OWNER_PREFIX = "auto:";
|
|
20
20
|
/** `auto:` + the first 24 hex of sha256(cwd ++ NUL ++ argv.join(NUL)). */
|
|
21
21
|
export declare function deriveResidentOwner(cwd: string, argv: readonly string[]): Promise<string>;
|
|
22
|
-
export declare function isDerivedOwner(owner: string): boolean;
|
|
23
22
|
//# sourceMappingURL=resident-identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resident-identity.d.ts","sourceRoot":"","sources":["../../src/facets/resident-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,0EAA0E;AAC1E,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAM/F
|
|
1
|
+
{"version":3,"file":"resident-identity.d.ts","sourceRoot":"","sources":["../../src/facets/resident-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,0EAA0E;AAC1E,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAM/F"}
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
* and native-artifact classification.
|
|
4
4
|
*
|
|
5
5
|
* The contract:
|
|
6
|
-
* - swaps :
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
6
|
+
* - swaps : an npm alias the policy declares on the user's behalf —
|
|
7
|
+
* `esbuild` installs as `esbuild@npm:esbuild-wasm@<range>`,
|
|
8
|
+
* so the swap target lands under the DECLARED name's
|
|
9
|
+
* directory (`applySwaps` / `swapAliasRange`). Only
|
|
10
|
+
* `compat: 'drop-in'` swaps qualify (the consumer's
|
|
11
|
+
* `require()` call site works unchanged against the
|
|
12
|
+
* target's API). Different-API candidates (bcrypt →
|
|
13
|
+
* bcryptjs, argon2 → hash-wasm, …) are NOT swaps: aliasing
|
|
14
|
+
* them would satisfy `require(originalName)` with a module
|
|
15
|
+
* whose API differs. They live in `rejects` with a
|
|
12
16
|
* code-change suggestion.
|
|
13
17
|
*
|
|
14
18
|
* - rejects: deny list with helpful messages. Every entry is
|
|
@@ -71,14 +75,32 @@ export declare function applyStagedArtifact(pkg: {
|
|
|
71
75
|
optionalDependencies?: Record<string, string>;
|
|
72
76
|
}, entry: PackageStagedArtifactEntry): void;
|
|
73
77
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
78
|
+
* The npm alias range a swap declares on the user's behalf:
|
|
79
|
+
* `esbuild@^0.20` becomes `esbuild@npm:esbuild-wasm@^0.20`.
|
|
76
80
|
*
|
|
77
|
-
*
|
|
81
|
+
* A swap IS an alias dependency. Expressing it as one means the installer's
|
|
82
|
+
* single alias path does the rest: the packument comes from the swap
|
|
83
|
+
* target, the package lands under the DECLARED name's directory
|
|
84
|
+
* (`node_modules/esbuild`), and require/import, bin links, the fs bundle
|
|
85
|
+
* and the lockfile all see the name the program asked for. Rewriting the
|
|
86
|
+
* KEY instead (`esbuild` → `esbuild-wasm`) is what left `require('esbuild')`
|
|
87
|
+
* unresolvable after `npm install esbuild`, and it collided with a sibling
|
|
88
|
+
* `esbuild-wasm` spec the project also declared.
|
|
78
89
|
*
|
|
79
|
-
* Range carry-over:
|
|
80
|
-
*
|
|
81
|
-
*
|
|
90
|
+
* Range carry-over: swap targets publish the same version numbers as the
|
|
91
|
+
* packages they stand in for, so the user's requested range is honoured
|
|
92
|
+
* against the target.
|
|
93
|
+
*/
|
|
94
|
+
export declare function swapAliasRange(swap: PackageSwapEntry, range: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Pure: return a new specs map with every swap `from` key's range rewritten
|
|
97
|
+
* to the alias range of its swap target (see `swapAliasRange`). Keys are
|
|
98
|
+
* never renamed, so every spec the caller declared is still present under
|
|
99
|
+
* its own name. Records the swaps actually performed.
|
|
100
|
+
*
|
|
101
|
+
* Idempotent: a range that already names its registry package (`npm:…`)
|
|
102
|
+
* is left alone, whether the policy wrote it on a previous pass or the user
|
|
103
|
+
* typed an explicit alias — an explicit alias is authoritative.
|
|
82
104
|
*/
|
|
83
105
|
export declare function applySwaps(specs: Record<string, string>): {
|
|
84
106
|
specs: Record<string, string>;
|
|
@@ -94,16 +116,6 @@ export declare function findRejects(specs: Record<string, string>, ctx: 'top' |
|
|
|
94
116
|
* `[npm] [swap] esbuild → esbuild-wasm (Native esbuild not available …)`
|
|
95
117
|
*/
|
|
96
118
|
export declare function formatSwapNotice(s: PackageSwapEntry): string;
|
|
97
|
-
/**
|
|
98
|
-
* Single-line yellow notice emitted for a `[skip]`.
|
|
99
|
-
* `[npm] [skip] fsevents — macOS-only filesystem watcher; never runs in Workers`
|
|
100
|
-
*
|
|
101
|
-
* When the entry carries an actionable suggestion it is appended inline
|
|
102
|
-
* (`… try: <hint>`) — the same line shape for optional-shard skips and
|
|
103
|
-
* required-package skips, so one grep explains every package the install
|
|
104
|
-
* left out.
|
|
105
|
-
*/
|
|
106
|
-
export declare function formatTransitiveSkip(r: PackageRejectEntry): string;
|
|
107
119
|
/**
|
|
108
120
|
* The discriminated-union event emitted by the supervisor whenever the
|
|
109
121
|
* registry takes a decision.
|
|
@@ -151,7 +163,6 @@ export type RegistryEventSink = (e: RegistryEvent) => void;
|
|
|
151
163
|
* after the facet returns.
|
|
152
164
|
*/
|
|
153
165
|
export declare function setRegistryEventSink(s: RegistryEventSink | null): void;
|
|
154
|
-
export declare function getRegistryEventSink(): RegistryEventSink | null;
|
|
155
166
|
/**
|
|
156
167
|
* Forward an event to the sink. Sink throws are caught (telemetry must
|
|
157
168
|
* never break install) and counted.
|
|
@@ -248,9 +259,7 @@ export declare function policyNativePlatformReject(policy: PackageAbiPolicy, pkg
|
|
|
248
259
|
* skip classifier, which treats either native shape as skippable from
|
|
249
260
|
* an optional edge.
|
|
250
261
|
*/
|
|
251
|
-
export declare function policyNativeArtifactReject(policy: PackageAbiPolicy, pkg: PackageBinManifest): PackageRejectEntry | undefined;
|
|
252
262
|
export declare function isOptionalNativeBinding(p: MinimalPackument): boolean;
|
|
253
|
-
export declare function nativeExecutableReject(pkg: PackageBinManifest): PackageRejectEntry | undefined;
|
|
254
263
|
/**
|
|
255
264
|
* Select which entries in `peerDependencies` should be auto-installed.
|
|
256
265
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm-swap-registry.d.ts","sourceRoot":"","sources":["../../src/facets/wasm-swap-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"wasm-swap-registry.d.ts","sourceRoot":"","sources":["../../src/facets/wasm-swap-registry.ts"],"names":[],"mappings":"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"}
|