@nimbus-sh/worker 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +37 -0
  2. package/dist/_shared/crypto.d.ts +15 -0
  3. package/dist/_shared/crypto.d.ts.map +1 -0
  4. package/dist/_shared/crypto.js +122 -0
  5. package/dist/facets/manager.d.ts +24 -0
  6. package/dist/facets/manager.d.ts.map +1 -1
  7. package/dist/facets/manager.js +279 -70
  8. package/dist/facets/process.d.ts +11 -2
  9. package/dist/facets/process.d.ts.map +1 -1
  10. package/dist/facets/process.js +187 -21
  11. package/dist/facets/vite-dev-server.d.ts +2 -0
  12. package/dist/facets/vite-dev-server.d.ts.map +1 -1
  13. package/dist/facets/vite-dev-server.js +39 -12
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/loaders/child-process/spawn-facet.d.ts +1 -3
  18. package/dist/loaders/child-process/spawn-facet.d.ts.map +1 -1
  19. package/dist/loaders/child-process/spawn-facet.js +1 -12
  20. package/dist/loaders/child-process/spawn-pool.d.ts +1 -1
  21. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  22. package/dist/loaders/child-process/spawn-pool.js +1 -6
  23. package/dist/npm/installer.d.ts.map +1 -1
  24. package/dist/npm/installer.js +47 -27
  25. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  26. package/dist/npm/pre-bundle-facet.js +2 -1
  27. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  28. package/dist/npm/resolve-one-facet.js +41 -13
  29. package/dist/npm/resolver.d.ts.map +1 -1
  30. package/dist/npm/resolver.js +70 -35
  31. package/dist/router/index.d.ts.map +1 -1
  32. package/dist/router/index.js +45 -21
  33. package/dist/router/remote-api.d.ts.map +1 -1
  34. package/dist/router/remote-api.js +29 -8
  35. package/dist/runtime/barrel-synthesizer.d.ts +7 -0
  36. package/dist/runtime/barrel-synthesizer.d.ts.map +1 -1
  37. package/dist/runtime/barrel-synthesizer.js +11 -0
  38. package/dist/runtime/clang-runner.d.ts.map +1 -1
  39. package/dist/runtime/clang-runner.js +1 -8
  40. package/dist/runtime/esbuild-service.d.ts +12 -5
  41. package/dist/runtime/esbuild-service.d.ts.map +1 -1
  42. package/dist/runtime/esbuild-service.js +28 -14
  43. package/dist/runtime/node-runner.d.ts +2 -0
  44. package/dist/runtime/node-runner.d.ts.map +1 -1
  45. package/dist/runtime/node-shims.d.ts +4 -2
  46. package/dist/runtime/node-shims.d.ts.map +1 -1
  47. package/dist/runtime/node-shims.js +404 -55
  48. package/dist/runtime/os-contracts.d.ts +128 -0
  49. package/dist/runtime/os-contracts.d.ts.map +1 -0
  50. package/dist/runtime/os-contracts.js +1 -0
  51. package/dist/runtime/package-manager.d.ts.map +1 -1
  52. package/dist/runtime/package-manager.js +32 -7
  53. package/dist/runtime/port-registry.d.ts +5 -0
  54. package/dist/runtime/port-registry.d.ts.map +1 -1
  55. package/dist/runtime/port-registry.js +22 -1
  56. package/dist/runtime/pyodide-runtime-assets.d.ts +19 -0
  57. package/dist/runtime/pyodide-runtime-assets.d.ts.map +1 -0
  58. package/dist/runtime/pyodide-runtime-assets.js +44 -0
  59. package/dist/runtime/python-repl.d.ts +3 -1
  60. package/dist/runtime/python-repl.d.ts.map +1 -1
  61. package/dist/runtime/python-repl.js +11 -29
  62. package/dist/runtime/python-runner.d.ts +8 -9
  63. package/dist/runtime/python-runner.d.ts.map +1 -1
  64. package/dist/runtime/python-runner.js +897 -61
  65. package/dist/runtime/python-socket-shim.d.ts +11 -0
  66. package/dist/runtime/python-socket-shim.d.ts.map +1 -0
  67. package/dist/runtime/python-socket-shim.js +526 -0
  68. package/dist/runtime/require-resolver.d.ts.map +1 -1
  69. package/dist/runtime/require-resolver.js +2 -11
  70. package/dist/runtime/ruby-gems.d.ts +25 -0
  71. package/dist/runtime/ruby-gems.d.ts.map +1 -0
  72. package/dist/runtime/ruby-gems.js +582 -0
  73. package/dist/runtime/ruby-runner.d.ts +2 -4
  74. package/dist/runtime/ruby-runner.d.ts.map +1 -1
  75. package/dist/runtime/ruby-runner.js +335 -34
  76. package/dist/runtime/runtime-catalog.d.ts +16 -4
  77. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  78. package/dist/runtime/runtime-catalog.js +21 -10
  79. package/dist/runtime/runtime-registry.d.ts +3 -0
  80. package/dist/runtime/runtime-registry.d.ts.map +1 -1
  81. package/dist/runtime/runtime-registry.js +4 -0
  82. package/dist/runtime/sqlite-runtime-fs-bridge.d.ts +43 -0
  83. package/dist/runtime/sqlite-runtime-fs-bridge.d.ts.map +1 -0
  84. package/dist/runtime/sqlite-runtime-fs-bridge.js +224 -0
  85. package/dist/runtime/static-server.d.ts +3 -0
  86. package/dist/runtime/static-server.d.ts.map +1 -0
  87. package/dist/runtime/static-server.js +121 -0
  88. package/dist/runtime/vfs-snapshot.d.ts +57 -0
  89. package/dist/runtime/vfs-snapshot.d.ts.map +1 -0
  90. package/dist/runtime/vfs-snapshot.js +141 -0
  91. package/dist/runtime/virtual-socket-kernel.d.ts +16 -0
  92. package/dist/runtime/virtual-socket-kernel.d.ts.map +1 -0
  93. package/dist/runtime/virtual-socket-kernel.js +360 -0
  94. package/dist/runtime/wasi-instance.d.ts +6 -3
  95. package/dist/runtime/wasi-instance.d.ts.map +1 -1
  96. package/dist/runtime/wasm-runner.d.ts +1 -25
  97. package/dist/runtime/wasm-runner.d.ts.map +1 -1
  98. package/dist/runtime/wasm-runner.js +1 -160
  99. package/dist/session/agent.d.ts +43 -0
  100. package/dist/session/agent.d.ts.map +1 -0
  101. package/dist/session/agent.js +1252 -0
  102. package/dist/session/init.d.ts.map +1 -1
  103. package/dist/session/init.js +15 -16
  104. package/dist/session/nimbus-session.d.ts +13 -2
  105. package/dist/session/nimbus-session.d.ts.map +1 -1
  106. package/dist/session/nimbus-session.js +55 -7
  107. package/dist/session/programmatic.d.ts +10 -0
  108. package/dist/session/programmatic.d.ts.map +1 -1
  109. package/dist/session/programmatic.js +121 -0
  110. package/dist/session/routes.d.ts.map +1 -1
  111. package/dist/session/routes.js +19 -1
  112. package/dist/session/rpc.d.ts +11 -0
  113. package/dist/session/rpc.d.ts.map +1 -1
  114. package/dist/session/rpc.js +56 -43
  115. package/dist/session/supervisor-rpc.d.ts +15 -0
  116. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  117. package/dist/session/supervisor-rpc.js +32 -0
  118. package/dist/session/ws.d.ts +4 -3
  119. package/dist/session/ws.d.ts.map +1 -1
  120. package/dist/session/ws.js +11 -1
  121. package/dist/shell/unix-commands.js +12 -16
  122. package/dist/vfs/path.d.ts +8 -4
  123. package/dist/vfs/path.d.ts.map +1 -1
  124. package/dist/vfs/path.js +16 -4
  125. package/dist/vfs/sqlite-vfs.d.ts +2 -0
  126. package/dist/vfs/sqlite-vfs.d.ts.map +1 -1
  127. package/dist/vfs/sqlite-vfs.js +11 -0
  128. package/dist/vfs/symlink-registry.d.ts +7 -1
  129. package/dist/vfs/symlink-registry.d.ts.map +1 -1
  130. package/dist/vfs/symlink-registry.js +16 -11
  131. package/package.json +4 -1
  132. package/public/index.html +240 -0
  133. package/public/s/index.html +1172 -146
  134. package/runtime-contracts/pyodide-workerd-adapter.json +18 -0
  135. package/scripts/bundle-runtime.mjs +99 -24
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * catalog/v1.json ← top-level catalog
12
12
  * manifests/<name>-<version>.json ← per-version manifest
13
- * blobs/<name>-<version>/<file> ← content-addressed blobs
13
+ * blobs/<name>-<version>/<sha256>/<file> ← content-addressed blobs
14
14
  *
15
15
  * Catalog schema (RuntimeCatalog):
16
16
  * { version: 1, runtimes: { <name>: { default, versions: { <ver>: { manifest, size_bytes, license } } } } }
@@ -18,7 +18,8 @@
18
18
  * Manifest schema (RuntimeManifest):
19
19
  * { name, version, license, wasi_namespace, memfs_companion,
20
20
  * files: [{ path, content, sha256, size, mode? }],
21
- * entrypoints: [{ binName, runner, args[], kind? }] }
21
+ * entrypoints: [{ binName, runner, args[], kind? }],
22
+ * runtime_artifacts?: [{ path, kind, id, source_sha256?, sha256 }] }
22
23
  *
23
24
  * R2 and Cache API failures throw; the shell verb formats the diagnostic for
24
25
  * the user.
@@ -70,6 +71,13 @@ export interface ManifestEntrypoint {
70
71
  /** Optional secondary classification (e.g. "linker" for wasm-ld). */
71
72
  kind?: string;
72
73
  }
74
+ export interface RuntimeArtifactMetadata {
75
+ path: string;
76
+ kind: string;
77
+ id: string;
78
+ source_sha256?: string;
79
+ sha256: string;
80
+ }
73
81
  export interface RuntimeManifest {
74
82
  name: string;
75
83
  version: string;
@@ -82,6 +90,7 @@ export interface RuntimeManifest {
82
90
  memfs_companion: string | null;
83
91
  files: ManifestFile[];
84
92
  entrypoints: ManifestEntrypoint[];
93
+ runtime_artifacts?: RuntimeArtifactMetadata[];
85
94
  }
86
95
  /** Fetch the top-level catalog. Throws if neither L2 nor R2 has it. */
87
96
  export declare function fetchCatalog(env: RuntimeCatalogEnv): Promise<RuntimeCatalog>;
@@ -89,8 +98,11 @@ export declare function fetchCatalog(env: RuntimeCatalogEnv): Promise<RuntimeCat
89
98
  export declare function fetchManifest(env: RuntimeCatalogEnv, manifestKey: string): Promise<RuntimeManifest>;
90
99
  /**
91
100
  * Fetch a content-addressed blob by R2 key. Bytes are eternally
92
- * cacheable because the key encodes the version. Verifies sha256 if
93
- * `expectedSha256` is provided.
101
+ * cacheable when the manifest key includes the content digest. Older
102
+ * manifests used version-only keys, so L2 can contain stale bytes after
103
+ * a corrected runtime sync. A cached sha mismatch is therefore treated
104
+ * as a stale cache entry and refetched from R2; an R2 mismatch remains
105
+ * a hard integrity failure.
94
106
  */
95
107
  export declare function fetchBlob(env: RuntimeCatalogEnv, blobKey: string, expectedSha256?: string): Promise<Uint8Array>;
96
108
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-catalog.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,2CAA2C;AAC3C,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACxB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;KACzB,GAAG,IAAI,CAAC,CAAC;CACX,GAAG,IAAI,GAAG,SAAS,CAAC;AAErB,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,oBAAoB,CAAC,EAAE,YAAY,CAAC;CACrC;AAID,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB;4CACwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;oEACgE;IAChE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;iEAC6D;IAC7D,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAaD,uEAAuE;AACvE,wBAAsB,YAAY,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAoBlF;AAED,kDAAkD;AAClD,wBAAsB,aAAa,CACjC,GAAG,EAAE,iBAAiB,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CAoB1B;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,iBAAiB,EACtB,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,UAAU,CAAC,CAwBrB"}
1
+ {"version":3,"file":"runtime-catalog.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,2CAA2C;AAC3C,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACxB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;KACzB,GAAG,IAAI,CAAC,CAAC;CACX,GAAG,IAAI,GAAG,SAAS,CAAC;AAErB,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,oBAAoB,CAAC,EAAE,YAAY,CAAC;CACrC;AAID,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB;4CACwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;oEACgE;IAChE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;iEAC6D;IAC7D,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,iBAAiB,CAAC,EAAE,uBAAuB,EAAE,CAAC;CAC/C;AAaD,uEAAuE;AACvE,wBAAsB,YAAY,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAoBlF;AAED,kDAAkD;AAClD,wBAAsB,aAAa,CACjC,GAAG,EAAE,iBAAiB,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CAoB1B;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,iBAAiB,EACtB,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,UAAU,CAAC,CA0BrB"}
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * catalog/v1.json ← top-level catalog
12
12
  * manifests/<name>-<version>.json ← per-version manifest
13
- * blobs/<name>-<version>/<file> ← content-addressed blobs
13
+ * blobs/<name>-<version>/<sha256>/<file> ← content-addressed blobs
14
14
  *
15
15
  * Catalog schema (RuntimeCatalog):
16
16
  * { version: 1, runtimes: { <name>: { default, versions: { <ver>: { manifest, size_bytes, license } } } } }
@@ -18,7 +18,8 @@
18
18
  * Manifest schema (RuntimeManifest):
19
19
  * { name, version, license, wasi_namespace, memfs_companion,
20
20
  * files: [{ path, content, sha256, size, mode? }],
21
- * entrypoints: [{ binName, runner, args[], kind? }] }
21
+ * entrypoints: [{ binName, runner, args[], kind? }],
22
+ * runtime_artifacts?: [{ path, kind, id, source_sha256?, sha256 }] }
22
23
  *
23
24
  * R2 and Cache API failures throw; the shell verb formats the diagnostic for
24
25
  * the user.
@@ -77,16 +78,19 @@ export async function fetchManifest(env, manifestKey) {
77
78
  }
78
79
  /**
79
80
  * Fetch a content-addressed blob by R2 key. Bytes are eternally
80
- * cacheable because the key encodes the version. Verifies sha256 if
81
- * `expectedSha256` is provided.
81
+ * cacheable when the manifest key includes the content digest. Older
82
+ * manifests used version-only keys, so L2 can contain stale bytes after
83
+ * a corrected runtime sync. A cached sha mismatch is therefore treated
84
+ * as a stale cache entry and refetched from R2; an R2 mismatch remains
85
+ * a hard integrity failure.
82
86
  */
83
87
  export async function fetchBlob(env, blobKey, expectedSha256) {
84
88
  // L2 hot path.
85
89
  const cached = await l2GetBytes(blobL2Key(blobKey));
86
90
  if (cached) {
87
- if (expectedSha256)
88
- await assertSha256(cached, expectedSha256, blobKey);
89
- return cached;
91
+ if (!expectedSha256 || await bytesMatchSha256(cached, expectedSha256)) {
92
+ return cached;
93
+ }
90
94
  }
91
95
  // R2 path.
92
96
  const r2 = env.NIMBUS_RUNTIME_CACHE;
@@ -101,18 +105,25 @@ export async function fetchBlob(env, blobKey, expectedSha256) {
101
105
  const bytes = new Uint8Array(ab);
102
106
  if (expectedSha256)
103
107
  await assertSha256(bytes, expectedSha256, blobKey);
104
- // Eternal-immutable write-back (content-addressed; never changes).
108
+ // Eternal-immutable write-back. Integrity has already been verified
109
+ // against the manifest before writing to L2.
105
110
  await l2PutBytes(blobL2Key(blobKey), bytes);
106
111
  return bytes;
107
112
  }
108
113
  // ── sha256 verifier ──────────────────────────────────────────────────
109
114
  async function assertSha256(bytes, expected, label) {
110
- const digest = await crypto.subtle.digest('SHA-256', bytes);
111
- const hex = bytesToHex(new Uint8Array(digest));
115
+ const hex = await sha256Hex(bytes);
112
116
  if (hex !== expected.toLowerCase()) {
113
117
  throw new Error(`sha256 mismatch for ${label}: expected ${expected} got ${hex}`);
114
118
  }
115
119
  }
120
+ async function bytesMatchSha256(bytes, expected) {
121
+ return await sha256Hex(bytes) === expected.toLowerCase();
122
+ }
123
+ async function sha256Hex(bytes) {
124
+ const digest = await crypto.subtle.digest('SHA-256', bytes);
125
+ return bytesToHex(new Uint8Array(digest));
126
+ }
116
127
  function bytesToHex(b) {
117
128
  let s = '';
118
129
  for (let i = 0; i < b.length; i++)
@@ -63,6 +63,9 @@ export interface RuntimeRunOpts {
63
63
  * runtimes ignore them safely. */
64
64
  skipSpawn?: boolean;
65
65
  callerPid?: number;
66
+ /** Capture stdout/stderr in the result instead of streaming to the
67
+ * terminal supervisor. Used by child_process pipe semantics. */
68
+ captureOutput?: boolean;
66
69
  }
67
70
  export interface RuntimeSpec {
68
71
  /** Shell-command name: 'node' / 'bun' / 'wasm-runner' / 'python'. */
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-registry.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACxC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;uCACmC;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb;oEACgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3F;;;;;OAKG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IACzD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACrF;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE;IACJ,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB;yDACqD;IACrD,UAAU,IAAI,cAAc,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;CACzB,GACA,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAyR/B"}
1
+ {"version":3,"file":"runtime-registry.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACxC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;uCACmC;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;qEACiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb;oEACgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3F;;;;;OAKG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IACzD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACrF;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE;IACJ,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB;yDACqD;IACrD,UAAU,IAAI,cAAc,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;CACzB,GACA,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CA6R/B"}
@@ -49,6 +49,7 @@ export function buildRuntimeHandler(spec, ctx0) {
49
49
  return async function runtimeHandler(ctx) {
50
50
  const args = ctx.args || [];
51
51
  const name = spec.name;
52
+ const captureOutput = !!ctx.__nimbusCaptureOutput;
52
53
  // ── Subcommand dispatch ──
53
54
  //
54
55
  // BEFORE flag-span computation: subcommands like `bun install`
@@ -103,6 +104,7 @@ export function buildRuntimeHandler(spec, ctx0) {
103
104
  filename: '<eval>',
104
105
  dirname: ctx.cwd || '/home/user',
105
106
  command: `${name} -e ...`,
107
+ ...(captureOutput ? { captureOutput: true } : {}),
106
108
  });
107
109
  if (result.stdout)
108
110
  ctx.stdout.write(result.stdout);
@@ -160,6 +162,7 @@ export function buildRuntimeHandler(spec, ctx0) {
160
162
  filename,
161
163
  dirname,
162
164
  command: `${name} ${args.slice(0, scriptIdx + 1).join(' ')}`,
165
+ ...(captureOutput ? { captureOutput: true } : {}),
163
166
  });
164
167
  if (result.stdout)
165
168
  ctx.stdout.write(result.stdout);
@@ -308,6 +311,7 @@ export function buildRuntimeHandler(spec, ctx0) {
308
311
  dirname,
309
312
  command: binSpawn?.command || `${name} ${args.slice(0, scriptIdx + 1).join(' ')}`,
310
313
  ...(binSpawn ? { skipSpawn: true, callerPid: binSpawn.callerPid } : {}),
314
+ ...(captureOutput ? { captureOutput: true } : {}),
311
315
  });
312
316
  if (result.stdout)
313
317
  ctx.stdout.write(result.stdout);
@@ -0,0 +1,43 @@
1
+ import type { SqliteVFS } from '../vfs/sqlite-vfs.js';
2
+ import type { RuntimeFileHandle, RuntimeFsBridge, RuntimeOpenFlags, RuntimeVfsDirEntry, RuntimeVfsStat } from './os-contracts.js';
3
+ export declare class SqliteRuntimeFsBridge implements RuntimeFsBridge {
4
+ private readonly vfs;
5
+ private nextHandleId;
6
+ private handles;
7
+ private symlinks;
8
+ constructor(vfs: SqliteVFS);
9
+ stat(path: string, options?: {
10
+ followSymlinks?: boolean;
11
+ }): Promise<RuntimeVfsStat | null>;
12
+ readFile(path: string, options?: {
13
+ followSymlinks?: boolean;
14
+ }): Promise<Uint8Array | null>;
15
+ writeFile(path: string, bytes: string | Uint8Array, options?: {
16
+ createParents?: boolean;
17
+ expectedRevision?: number;
18
+ }): Promise<void>;
19
+ open(path: string, flags: RuntimeOpenFlags): Promise<RuntimeFileHandle>;
20
+ read(handleId: number, offset: number | null, length: number): Promise<Uint8Array>;
21
+ write(handleId: number, offset: number | null, bytes: Uint8Array): Promise<number>;
22
+ close(handleId: number): Promise<void>;
23
+ readdir(path: string, options?: {
24
+ followSymlinks?: boolean;
25
+ }): Promise<RuntimeVfsDirEntry[]>;
26
+ mkdir(path: string, options?: {
27
+ recursive?: boolean;
28
+ mode?: number;
29
+ }): Promise<void>;
30
+ unlink(path: string): Promise<void>;
31
+ rmdir(path: string): Promise<void>;
32
+ rename(from: string, to: string): Promise<void>;
33
+ readlink(path: string): Promise<string | null>;
34
+ symlink(target: string, path: string): Promise<void>;
35
+ fsync(): Promise<void>;
36
+ revision(): Promise<number>;
37
+ subscribe(path: string, listener: Parameters<NonNullable<RuntimeFsBridge['subscribe']>>[1]): () => void;
38
+ private resolveDataPath;
39
+ private ensureParent;
40
+ private assertExpectedRevision;
41
+ private getHandle;
42
+ }
43
+ //# sourceMappingURL=sqlite-runtime-fs-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-runtime-fs-bridge.d.ts","sourceRoot":"","sources":["../../src/runtime/sqlite-runtime-fs-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,qBAAsB,YAAW,eAAe;IAK/C,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJhC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,QAAQ,CAAkB;gBAEL,GAAG,EAAE,SAAS;IAIrC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA6B9F,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAU9F,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,UAAU,EAC1B,OAAO,GAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAO,GACnE,OAAO,CAAC,IAAI,CAAC;IAOV,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA4BvE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAWlF,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAmBlF,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAehG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI9C,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAIjC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,WAAW,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAIvG,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,SAAS;CAKlB"}
@@ -0,0 +1,224 @@
1
+ import { normalizeVfsPath, parentVfsPath } from '../vfs/path.js';
2
+ import { getSymlinkRegistry } from '../vfs/symlink-registry.js';
3
+ export class SqliteRuntimeFsBridge {
4
+ vfs;
5
+ nextHandleId = 1;
6
+ handles = new Map();
7
+ symlinks;
8
+ constructor(vfs) {
9
+ this.vfs = vfs;
10
+ this.symlinks = getSymlinkRegistry(vfs);
11
+ }
12
+ async stat(path, options = {}) {
13
+ const p = this.resolveDataPath(path, options.followSymlinks !== false);
14
+ if (!p)
15
+ return null;
16
+ if (this.symlinks.isSymlink(p) && options.followSymlinks === false) {
17
+ const target = this.symlinks.readlink(p) || '';
18
+ return {
19
+ type: 'symlink',
20
+ size: new TextEncoder().encode(target).byteLength,
21
+ ctime: Date.now(),
22
+ mtime: Date.now(),
23
+ mode: 0o777,
24
+ revision: this.vfs.revision(),
25
+ };
26
+ }
27
+ try {
28
+ const st = this.vfs.stat(p);
29
+ return {
30
+ type: st.type === 'directory' ? 'directory' : 'file',
31
+ size: st.size,
32
+ ctime: st.ctime,
33
+ mtime: st.mtime,
34
+ mode: st.mode,
35
+ revision: this.vfs.revision(),
36
+ };
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ async readFile(path, options = {}) {
43
+ const p = this.resolveDataPath(path, options.followSymlinks !== false);
44
+ if (!p)
45
+ return null;
46
+ try {
47
+ return this.vfs.readFile(p);
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ async writeFile(path, bytes, options = {}) {
54
+ this.assertExpectedRevision(options.expectedRevision);
55
+ const p = this.resolveDataPath(path, true) || normalizeVfsPath(path);
56
+ if (options.createParents !== false)
57
+ this.ensureParent(p);
58
+ this.vfs.writeFile(p, bytes);
59
+ }
60
+ async open(path, flags) {
61
+ const normalizedFlags = normalizeOpenFlags(flags);
62
+ const p = this.resolveDataPath(path, normalizedFlags.followSymlinks) || normalizeVfsPath(path);
63
+ this.assertExpectedRevision(normalizedFlags.expectedRevision);
64
+ const exists = this.vfs.exists(p);
65
+ if (!exists && !normalizedFlags.create)
66
+ throw fsError('ENOENT', 'open', path);
67
+ if (exists && this.vfs.isDirectory(p))
68
+ throw fsError('EISDIR', 'open', path);
69
+ if (!exists) {
70
+ this.ensureParent(p);
71
+ this.vfs.writeFile(p, new Uint8Array(0));
72
+ }
73
+ else if (normalizedFlags.truncate) {
74
+ this.vfs.writeFile(p, new Uint8Array(0));
75
+ }
76
+ const stat = this.vfs.stat(p);
77
+ const handle = {
78
+ id: this.nextHandleId++,
79
+ path: p,
80
+ flags: normalizedFlags,
81
+ position: normalizedFlags.append ? stat.size : 0,
82
+ baseRevision: this.vfs.revision(),
83
+ closed: false,
84
+ };
85
+ this.handles.set(handle.id, handle);
86
+ return { ...handle };
87
+ }
88
+ async read(handleId, offset, length) {
89
+ const handle = this.getHandle(handleId);
90
+ if (!handle.flags.read)
91
+ throw fsError('EBADF', 'read', handle.path);
92
+ const data = this.vfs.readFile(handle.path);
93
+ const start = offset == null ? handle.position : Math.max(0, offset);
94
+ const end = Math.min(data.byteLength, start + Math.max(0, length));
95
+ const out = data.slice(start, end);
96
+ if (offset == null)
97
+ handle.position = end;
98
+ return out;
99
+ }
100
+ async write(handleId, offset, bytes) {
101
+ const handle = this.getHandle(handleId);
102
+ if (!handle.flags.write)
103
+ throw fsError('EBADF', 'write', handle.path);
104
+ if (handle.baseRevision < this.vfs.revision()) {
105
+ throw fsError('ESTALE', 'write', handle.path);
106
+ }
107
+ const prior = this.vfs.exists(handle.path) ? this.vfs.readFile(handle.path) : new Uint8Array(0);
108
+ const start = handle.flags.append ? prior.byteLength : offset == null ? handle.position : Math.max(0, offset);
109
+ const size = Math.max(prior.byteLength, start + bytes.byteLength);
110
+ const next = new Uint8Array(size);
111
+ next.set(prior.subarray(0, Math.min(prior.byteLength, size)), 0);
112
+ next.set(bytes, start);
113
+ this.vfs.writeFile(handle.path, next);
114
+ const end = start + bytes.byteLength;
115
+ if (offset == null || handle.flags.append)
116
+ handle.position = end;
117
+ handle.baseRevision = this.vfs.revision();
118
+ return bytes.byteLength;
119
+ }
120
+ async close(handleId) {
121
+ const handle = this.getHandle(handleId);
122
+ handle.closed = true;
123
+ this.handles.delete(handleId);
124
+ }
125
+ async readdir(path, options = {}) {
126
+ const p = this.resolveDataPath(path, options.followSymlinks !== false);
127
+ if (!p)
128
+ return [];
129
+ const entries = this.vfs.readdir(p).map((entry) => ({
130
+ name: entry.name,
131
+ type: entry.type === 'directory' ? 'directory' : 'file',
132
+ }));
133
+ const prefix = p ? `${p}/` : '';
134
+ for (const link of this.symlinks.list()) {
135
+ if (parentVfsPath(link.link) !== p)
136
+ continue;
137
+ entries.push({ name: link.link.slice(prefix.length), type: 'symlink' });
138
+ }
139
+ return entries.sort((a, b) => a.name.localeCompare(b.name));
140
+ }
141
+ async mkdir(path, options = {}) {
142
+ this.vfs.mkdir(normalizeVfsPath(path), { recursive: !!options.recursive });
143
+ }
144
+ async unlink(path) {
145
+ const p = normalizeVfsPath(path);
146
+ if (this.symlinks.delete(p))
147
+ return;
148
+ this.vfs.unlink(p);
149
+ }
150
+ async rmdir(path) {
151
+ this.vfs.rmdir(normalizeVfsPath(path));
152
+ }
153
+ async rename(from, to) {
154
+ const oldPath = normalizeVfsPath(from);
155
+ const newPath = normalizeVfsPath(to);
156
+ const linkTarget = this.symlinks.readlink(oldPath);
157
+ if (linkTarget !== null) {
158
+ this.symlinks.delete(oldPath);
159
+ this.symlinks.set(newPath, linkTarget);
160
+ return;
161
+ }
162
+ this.ensureParent(newPath);
163
+ this.vfs.rename(oldPath, newPath);
164
+ }
165
+ async readlink(path) {
166
+ return this.symlinks.readlink(normalizeVfsPath(path));
167
+ }
168
+ async symlink(target, path) {
169
+ const p = normalizeVfsPath(path);
170
+ this.ensureParent(p);
171
+ this.symlinks.set(p, target);
172
+ }
173
+ async fsync() {
174
+ this.vfs.flushAll();
175
+ }
176
+ async revision() {
177
+ return this.vfs.revision();
178
+ }
179
+ subscribe(path, listener) {
180
+ return this.vfs.events.onPath(normalizeVfsPath(path), listener);
181
+ }
182
+ resolveDataPath(path, followSymlinks) {
183
+ const p = normalizeVfsPath(path);
184
+ if (!followSymlinks)
185
+ return p;
186
+ return this.symlinks.resolveChain(p);
187
+ }
188
+ ensureParent(path) {
189
+ const parent = parentVfsPath(path);
190
+ if (parent && !this.vfs.exists(parent))
191
+ this.vfs.mkdir(parent, { recursive: true });
192
+ }
193
+ assertExpectedRevision(expectedRevision) {
194
+ if (expectedRevision === undefined)
195
+ return;
196
+ if (expectedRevision !== this.vfs.revision()) {
197
+ throw fsError('ESTALE', 'write', `revision ${expectedRevision}`);
198
+ }
199
+ }
200
+ getHandle(handleId) {
201
+ const handle = this.handles.get(handleId);
202
+ if (!handle || handle.closed)
203
+ throw fsError('EBADF', 'fd', String(handleId));
204
+ return handle;
205
+ }
206
+ }
207
+ function normalizeOpenFlags(flags) {
208
+ return {
209
+ read: !!flags.read || !flags.write,
210
+ write: !!flags.write,
211
+ append: !!flags.append,
212
+ create: !!flags.create,
213
+ truncate: !!flags.truncate,
214
+ followSymlinks: flags.followSymlinks !== false,
215
+ expectedRevision: flags.expectedRevision,
216
+ };
217
+ }
218
+ function fsError(code, syscall, path) {
219
+ const err = new Error(`${code}: ${syscall} '${path}'`);
220
+ err.code = code;
221
+ err.syscall = syscall;
222
+ err.path = path;
223
+ return err;
224
+ }
@@ -0,0 +1,3 @@
1
+ export declare function parsePort(value: string | undefined, fallback: number): number;
2
+ export declare function createLiveStaticServerCode(root: string): string;
3
+ //# sourceMappingURL=static-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-server.d.ts","sourceRoot":"","sources":["../../src/runtime/static-server.ts"],"names":[],"mappings":"AAIA,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK7E;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6G/D"}
@@ -0,0 +1,121 @@
1
+ function jsString(value) {
2
+ return JSON.stringify(value);
3
+ }
4
+ export function parsePort(value, fallback) {
5
+ if (!value)
6
+ return fallback;
7
+ const n = Number(value);
8
+ if (!Number.isInteger(n) || n <= 0 || n >= 65536)
9
+ return fallback;
10
+ return n;
11
+ }
12
+ export function createLiveStaticServerCode(root) {
13
+ const normalizedRoot = root.replace(/^\/+/, '').replace(/\/+$/, '') || 'home/user';
14
+ return `
15
+ import { WorkerEntrypoint } from "cloudflare:workers";
16
+
17
+ const ROOT = ${jsString(normalizedRoot)};
18
+ const TEXT_TYPES = {
19
+ ".html": "text/html; charset=utf-8",
20
+ ".htm": "text/html; charset=utf-8",
21
+ ".css": "text/css; charset=utf-8",
22
+ ".js": "text/javascript; charset=utf-8",
23
+ ".mjs": "text/javascript; charset=utf-8",
24
+ ".json": "application/json; charset=utf-8",
25
+ ".txt": "text/plain; charset=utf-8",
26
+ ".md": "text/markdown; charset=utf-8",
27
+ ".svg": "image/svg+xml; charset=utf-8",
28
+ ".wasm": "application/wasm",
29
+ ".png": "image/png",
30
+ ".jpg": "image/jpeg",
31
+ ".jpeg": "image/jpeg",
32
+ ".gif": "image/gif",
33
+ ".webp": "image/webp",
34
+ ".ico": "image/x-icon",
35
+ };
36
+
37
+ function cleanPath(pathname) {
38
+ const parts = [];
39
+ for (const raw of pathname.split("/")) {
40
+ if (!raw || raw === ".") continue;
41
+ if (raw === "..") { parts.pop(); continue; }
42
+ parts.push(raw);
43
+ }
44
+ return parts.join("/");
45
+ }
46
+
47
+ function joinRoot(rel) {
48
+ return rel ? ROOT + "/" + rel : ROOT;
49
+ }
50
+
51
+ function contentType(path) {
52
+ const idx = path.lastIndexOf(".");
53
+ const ext = idx >= 0 ? path.slice(idx).toLowerCase() : "";
54
+ return TEXT_TYPES[ext] || "application/octet-stream";
55
+ }
56
+
57
+ function htmlEscape(s) {
58
+ return String(s).replace(/[&<>"]/g, (ch) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[ch]));
59
+ }
60
+
61
+ async function resolveFile(supervisor, rel) {
62
+ const base = joinRoot(rel);
63
+ const stat = await supervisor.stat(base);
64
+ const isDirectory = stat && (stat.type === "directory" || stat.isDir || stat.isDirectory);
65
+ if (stat && !isDirectory) return { path: base, stat };
66
+ if (isDirectory) {
67
+ for (const index of ["index.html", "index.htm"]) {
68
+ const candidate = base.replace(/\\/+$/, "") + "/" + index;
69
+ const s = await supervisor.stat(candidate);
70
+ if (s && !(s.type === "directory" || s.isDir || s.isDirectory)) return { path: candidate, stat: s };
71
+ }
72
+ return { directory: base };
73
+ }
74
+ return null;
75
+ }
76
+
77
+ async function renderDirectory(supervisor, path, rel, url) {
78
+ const entries = await supervisor.readdir(path);
79
+ const rows = entries
80
+ .sort((a, b) => (a.type === b.type ? a.name.localeCompare(b.name) : a.type === "directory" ? -1 : 1))
81
+ .map((entry) => {
82
+ const suffix = entry.type === "directory" ? "/" : "";
83
+ const href = new URL(url);
84
+ href.pathname = href.pathname.replace(/\\/?$/, "/") + encodeURIComponent(entry.name) + suffix;
85
+ return '<li><a href="' + href.pathname + href.search + '">' + htmlEscape(entry.name + suffix) + '</a></li>';
86
+ })
87
+ .join("");
88
+ return new Response(
89
+ '<!doctype html><meta charset="utf-8"><title>Index of /' + htmlEscape(rel) + '</title>' +
90
+ '<h1>Index of /' + htmlEscape(rel) + '</h1><ul>' + rows + '</ul>',
91
+ { headers: { "Content-Type": "text/html; charset=utf-8" } }
92
+ );
93
+ }
94
+
95
+ export default class NimbusStaticServer extends WorkerEntrypoint {
96
+ async fetch(request) {
97
+ return this.handleHttpRequest(request);
98
+ }
99
+
100
+ async handleHttpRequest(request) {
101
+ const supervisor = this.env && this.env.SUPERVISOR;
102
+ if (!supervisor) {
103
+ return new Response("Nimbus static server: SUPERVISOR binding missing", { status: 500 });
104
+ }
105
+ const url = new URL(request.url);
106
+ const rel = cleanPath(decodeURIComponent(url.pathname));
107
+ const resolved = await resolveFile(supervisor, rel);
108
+ if (!resolved) return new Response("Not found", { status: 404 });
109
+ if (resolved.directory) return renderDirectory(supervisor, resolved.directory, rel, url);
110
+ const bytes = await supervisor.readFileBytes(resolved.path);
111
+ if (!bytes) return new Response("Not found", { status: 404 });
112
+ return new Response(bytes, {
113
+ headers: {
114
+ "Content-Type": contentType(resolved.path),
115
+ "Cache-Control": "no-store",
116
+ },
117
+ });
118
+ }
119
+ }
120
+ `;
121
+ }
@@ -0,0 +1,57 @@
1
+ import type { WasiFsDiff, WasiFsSnapshot } from './wasi-instance.js';
2
+ /**
3
+ * Minimal VFS shape runtime bridges need. Kept separate from SqliteVFS's
4
+ * concrete type so runtime helpers do not pull supervisor modules into facet
5
+ * preambles or create import cycles.
6
+ */
7
+ export interface VfsLike {
8
+ exists(path: string): boolean;
9
+ isDirectory(path: string): boolean;
10
+ readFile(path: string): Uint8Array;
11
+ writeFile(path: string, content: Uint8Array | string): void;
12
+ readdir(path: string): {
13
+ name: string;
14
+ type: string;
15
+ }[];
16
+ mkdir(path: string, opts?: {
17
+ recursive?: boolean;
18
+ }): void;
19
+ unlink(path: string): void;
20
+ rmdir(path: string): void;
21
+ }
22
+ export interface VfsSnapshotCaps {
23
+ maxBytes?: number;
24
+ maxFiles?: number;
25
+ skipSubdirs?: Iterable<string>;
26
+ extraRoots?: Iterable<string>;
27
+ }
28
+ export interface VfsSnapshotResult {
29
+ snapshot: WasiFsSnapshot;
30
+ bytes: number;
31
+ files: number;
32
+ }
33
+ export declare function bytesToB64(bytes: Uint8Array): string;
34
+ export declare function b64ToBytes(b64: string): Uint8Array;
35
+ /**
36
+ * Snapshot a VFS subtree into a JSON-serializable WASI-shaped filesystem.
37
+ *
38
+ * The snapshot is intentionally bounded. Runtimes that need incremental or
39
+ * lazy file IO should add a streaming bridge; a single request payload is the
40
+ * right primitive only for normal source trees and small app state.
41
+ */
42
+ export declare function snapshotVfs(vfs: VfsLike, vfsRoot: string, caps?: VfsSnapshotCaps): VfsSnapshotResult | {
43
+ error: string;
44
+ };
45
+ /**
46
+ * Apply a runtime-produced filesystem diff back into the supervisor VFS.
47
+ * Operations are independent so one bad path never loses the rest of a run.
48
+ */
49
+ export declare function flushVfsDiff(vfs: VfsLike, diff: WasiFsDiff): {
50
+ written: number;
51
+ deleted: number;
52
+ mkdirs: number;
53
+ rmdirs: number;
54
+ timesTouched: number;
55
+ symlinks: number;
56
+ };
57
+ //# sourceMappingURL=vfs-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vfs-snapshot.d.ts","sourceRoot":"","sources":["../../src/runtime/vfs-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAErE;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IACnC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAKlD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,eAAoB,GACzB,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAmEvC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,UAAU,GACf;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA4C9G"}