@nimbus-sh/worker 0.2.0 → 0.2.2

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 (83) hide show
  1. package/dist/facets/manager.d.ts +47 -2
  2. package/dist/facets/manager.d.ts.map +1 -1
  3. package/dist/facets/manager.js +139 -15
  4. package/dist/loaders/generated-workers.d.ts +2 -2
  5. package/dist/loaders/generated-workers.d.ts.map +1 -1
  6. package/dist/loaders/generated-workers.js +3 -3
  7. package/dist/runtime/bash-repl.d.ts +1 -1
  8. package/dist/runtime/bash-repl.d.ts.map +1 -1
  9. package/dist/runtime/bash-repl.js +3 -2
  10. package/dist/runtime/cpython-resident.d.ts +27 -0
  11. package/dist/runtime/cpython-resident.d.ts.map +1 -0
  12. package/dist/runtime/cpython-resident.js +133 -0
  13. package/dist/runtime/facet-loader-host.d.ts +16 -1
  14. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  15. package/dist/runtime/facet-loader-host.js +42 -0
  16. package/dist/runtime/package-manager.d.ts +3 -58
  17. package/dist/runtime/package-manager.d.ts.map +1 -1
  18. package/dist/runtime/package-manager.js +6 -143
  19. package/dist/runtime/python-repl.d.ts +1 -1
  20. package/dist/runtime/python-repl.d.ts.map +1 -1
  21. package/dist/runtime/python-repl.js +2 -2
  22. package/dist/runtime/ruby-repl.js +1 -1
  23. package/dist/runtime/ruby-resident.d.ts +20 -0
  24. package/dist/runtime/ruby-resident.d.ts.map +1 -0
  25. package/dist/runtime/ruby-resident.js +278 -0
  26. package/dist/runtime/runtime-catalog.d.ts +4 -80
  27. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  28. package/dist/runtime/runtime-catalog.js +4 -67
  29. package/dist/session/init.d.ts +16 -7
  30. package/dist/session/init.d.ts.map +1 -1
  31. package/dist/session/init.js +210 -249
  32. package/dist/session/keys.d.ts +13 -0
  33. package/dist/session/keys.d.ts.map +1 -1
  34. package/dist/session/keys.js +13 -0
  35. package/dist/session/nimbus-session.d.ts +30 -2
  36. package/dist/session/nimbus-session.d.ts.map +1 -1
  37. package/dist/session/nimbus-session.js +49 -58
  38. package/dist/session/programmatic.d.ts +3 -3
  39. package/dist/session/programmatic.d.ts.map +1 -1
  40. package/dist/session/programmatic.js +3 -2
  41. package/dist/session/routes.js +1 -1
  42. package/dist/session/supervisor-rpc.d.ts +6 -13
  43. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  44. package/dist/session/supervisor-rpc.js +7 -17
  45. package/package.json +2 -2
  46. package/scripts/bundle-facet-workers.mjs +9 -8
  47. package/scripts/bundle-runtime.mjs +276 -44
  48. package/dist/npm/tarball-stream.d.ts +0 -93
  49. package/dist/npm/tarball-stream.d.ts.map +0 -1
  50. package/dist/npm/tarball-stream.js +0 -235
  51. package/dist/npm/tarball.d.ts +0 -34
  52. package/dist/npm/tarball.d.ts.map +0 -1
  53. package/dist/npm/tarball.js +0 -97
  54. package/dist/runtime/bash-runner.d.ts +0 -63
  55. package/dist/runtime/bash-runner.d.ts.map +0 -1
  56. package/dist/runtime/bash-runner.generated.d.ts +0 -14
  57. package/dist/runtime/bash-runner.generated.d.ts.map +0 -1
  58. package/dist/runtime/bash-runner.generated.js +0 -13
  59. package/dist/runtime/bash-runner.js +0 -291
  60. package/dist/runtime/clang-runner.d.ts +0 -37
  61. package/dist/runtime/clang-runner.d.ts.map +0 -1
  62. package/dist/runtime/clang-runner.js +0 -865
  63. package/dist/runtime/cpython-runner.d.ts +0 -71
  64. package/dist/runtime/cpython-runner.d.ts.map +0 -1
  65. package/dist/runtime/cpython-runner.js +0 -535
  66. package/dist/runtime/python-pip.d.ts +0 -38
  67. package/dist/runtime/python-pip.d.ts.map +0 -1
  68. package/dist/runtime/python-pip.js +0 -1063
  69. package/dist/runtime/ruby-gems.d.ts +0 -30
  70. package/dist/runtime/ruby-gems.d.ts.map +0 -1
  71. package/dist/runtime/ruby-gems.js +0 -636
  72. package/dist/runtime/ruby-runner.d.ts +0 -75
  73. package/dist/runtime/ruby-runner.d.ts.map +0 -1
  74. package/dist/runtime/ruby-runner.js +0 -1577
  75. package/dist/runtime/runtime-registry.d.ts +0 -162
  76. package/dist/runtime/runtime-registry.d.ts.map +0 -1
  77. package/dist/runtime/runtime-registry.js +0 -364
  78. package/dist/runtime/virtual-socket-kernel.generated.d.ts +0 -14
  79. package/dist/runtime/virtual-socket-kernel.generated.d.ts.map +0 -1
  80. package/dist/runtime/virtual-socket-kernel.generated.js +0 -13
  81. package/dist/runtime/wasm-runner.d.ts +0 -70
  82. package/dist/runtime/wasm-runner.d.ts.map +0 -1
  83. package/dist/runtime/wasm-runner.js +0 -664
@@ -7,6 +7,13 @@
7
7
  * node scripts/bundle-runtime.mjs clang binji-2020 [--bucket nimbus-runtime-cache]
8
8
  * node scripts/bundle-runtime.mjs python 0.29.4 [--bucket nimbus-runtime-cache]
9
9
  * node scripts/bundle-runtime.mjs --pin-catalog (read-only; publishes nothing)
10
+ * node scripts/bundle-runtime.mjs bash 5.2.37 --npm-package <dir> (local; no R2)
11
+ *
12
+ * `--npm-package` is the SECOND publisher for the same artifacts: it stages
13
+ * exactly what the R2 path stages, composes the same manifest bytes, and lays
14
+ * the blobs out under the same content-addressed keys — into a directory that
15
+ * `npm publish` takes, for the embedders who have npm and no bucket. It reads
16
+ * nothing from Cloudflare and writes nothing to it. See §--npm-package below.
10
17
  *
11
18
  * Per `2026-05-10-true-os/plan.md` §2.4:
12
19
  * - Blobs are content-addressed under `blobs/<name>-<version>/<sha256>/<file>`.
@@ -45,10 +52,6 @@ import { tmpdir } from 'node:os';
45
52
  import { basename, dirname, join } from 'node:path';
46
53
 
47
54
  const ACCOUNT = process.env.CLOUDFLARE_ACCOUNT_ID;
48
- if (!ACCOUNT) {
49
- console.error('ERROR: CLOUDFLARE_ACCOUNT_ID env var required');
50
- process.exit(1);
51
- }
52
55
  // Resolve the wrangler bin from either the package-local or the
53
56
  // repo-root node_modules (this script runs from packages/worker but
54
57
  // the bin is hoisted to the workspace root).
@@ -62,6 +65,7 @@ const PYODIDE_WORKERD_ADAPTER = JSON.parse(
62
65
 
63
66
  const USAGE =
64
67
  'usage: bundle-runtime.mjs <name> <version> [--bucket <bucket>]\n' +
68
+ ' bundle-runtime.mjs <name> <version> --npm-package <dir>\n' +
65
69
  ' bundle-runtime.mjs --pin-catalog [--bucket <bucket>]';
66
70
 
67
71
  /** The bucket the deployed Worker's NIMBUS_RUNTIME_CACHE binding points at.
@@ -74,12 +78,25 @@ const rawArgs = process.argv.slice(2);
74
78
  const positionalArgs = [];
75
79
  let BUCKET = process.env.NIMBUS_RUNTIME_BUCKET || PRODUCTION_BUCKET;
76
80
  let PIN_ONLY = false;
81
+ let NPM_OUT_DIR = null;
77
82
  for (let i = 0; i < rawArgs.length; i++) {
78
83
  const arg = rawArgs[i];
79
84
  if (arg === '--pin-catalog') {
80
85
  PIN_ONLY = true;
81
86
  continue;
82
87
  }
88
+ if (arg === '--npm-package') {
89
+ NPM_OUT_DIR = rawArgs[++i];
90
+ if (!NPM_OUT_DIR) {
91
+ console.error(USAGE);
92
+ process.exit(2);
93
+ }
94
+ continue;
95
+ }
96
+ if (arg.startsWith('--npm-package=')) {
97
+ NPM_OUT_DIR = arg.slice('--npm-package='.length);
98
+ continue;
99
+ }
83
100
  if (arg === '--bucket') {
84
101
  const value = rawArgs[++i];
85
102
  if (!value) {
@@ -96,6 +113,12 @@ for (let i = 0; i < rawArgs.length; i++) {
96
113
  positionalArgs.push(arg);
97
114
  }
98
115
 
116
+ // Every mode but `--npm-package` reads or writes R2 through wrangler.
117
+ if (!NPM_OUT_DIR && !ACCOUNT) {
118
+ console.error('ERROR: CLOUDFLARE_ACCOUNT_ID env var required');
119
+ process.exit(1);
120
+ }
121
+
99
122
  // `--pin-catalog` regenerates the build-time root of trust from the catalog
100
123
  // already in R2. Read-only: it publishes nothing, so it is safe to run at any
101
124
  // time, including while another ingest is in flight against a different bucket.
@@ -127,6 +150,15 @@ const SPECS = {
127
150
  license: 'Apache-2.0-with-LLVM-exception',
128
151
  wasi_namespace: 'wasi_unstable',
129
152
  upstream_base: 'https://raw.githubusercontent.com/binji/wasm-clang/master',
153
+ npm: {
154
+ name: '@nimbus-sh/runtime-clang',
155
+ summary: 'clang 8.0.1 and wasm-ld for wasm32-wasi, with a wasi-libc sysroot',
156
+ // npm demands semver and this runtime's Nimbus version is a channel
157
+ // name, so the compiler's own version is what the package carries. The
158
+ // two namespaces stay separate: the manifest still says `binji-2020`,
159
+ // and that is what the install root under ~/.nimbus/runtimes is named.
160
+ version: '8.0.1',
161
+ },
130
162
  files: [
131
163
  { src: 'clang', vfs: 'bin/clang', mode: 'exec', runner: 'clang-runner', binName: 'clang' },
132
164
  { src: 'lld', vfs: 'bin/wasm-ld', mode: 'exec', runner: 'clang-runner', binName: 'wasm-ld', kind: 'linker' },
@@ -154,6 +186,10 @@ const SPECS = {
154
186
  license: 'Ruby+BSD-2-Clause',
155
187
  wasi_namespace: 'wasi_snapshot_preview1',
156
188
  upstream_base: 'https://registry.npmjs.org/@ruby/3.3-wasm-wasi/-/3.3-wasm-wasi-2.9.3-2.9.4.tgz',
189
+ npm: {
190
+ name: '@nimbus-sh/runtime-ruby',
191
+ summary: 'Ruby 3.3.4 (ruby.wasm) for wasm32-wasi, with its stdlib packed in',
192
+ },
157
193
  tarball_extract: 'package/dist', // strip this prefix from src paths inside the tarball
158
194
  files: [
159
195
  // The Ruby wasm — includes Ruby 3.3.x interpreter + stdlib packed
@@ -194,6 +230,10 @@ const SPECS = {
194
230
  license: 'GPL-3.0-or-later AND GPL-2.0-only',
195
231
  wasi_namespace: 'wasi_snapshot_preview1',
196
232
  local_base: '../wasm/bash',
233
+ npm: {
234
+ name: '@nimbus-sh/runtime-bash',
235
+ summary: 'GNU bash 5.2.37 and BusyBox 1.37.0, cross-compiled to wasm32-wasi',
236
+ },
197
237
  files: [
198
238
  { src: 'bash.async.wasm', vfs: 'share/bash/bash.async.wasm' },
199
239
  { src: 'coreutils/busybox.wasm', vfs: 'share/bash/coreutils/busybox.wasm' },
@@ -271,6 +311,10 @@ const SPECS = {
271
311
  license: 'PSF-2.0',
272
312
  wasi_namespace: 'wasi_snapshot_preview1',
273
313
  local_base: '../wasm/python',
314
+ npm: {
315
+ name: '@nimbus-sh/runtime-cpython',
316
+ summary: 'CPython 3.13.14, cross-compiled to wasm32-wasi, with its stdlib',
317
+ },
274
318
  files: [
275
319
  { src: 'python.wasm', vfs: 'share/cpython/python.wasm' },
276
320
  // The same interpreter with numpy and markupsafe's C speedups linked in,
@@ -383,6 +427,19 @@ if (!spec) {
383
427
  console.error(`known: ${Object.keys(SPECS).join(', ')}`);
384
428
  process.exit(2);
385
429
  }
430
+ // Checked before anything is staged: which runtimes we publish to npm is a
431
+ // decision, and a spec that has not made it should cost nothing to find out.
432
+ if (NPM_OUT_DIR) {
433
+ if (!spec.npm) {
434
+ console.error(`ERROR: ${key} declares no npm package in its spec.`);
435
+ console.error(' Add an `npm: { name, summary }` entry to publish it that way.');
436
+ process.exit(2);
437
+ }
438
+ if (spec.ingest_only) {
439
+ console.error(`ERROR: ${key} is ingest_only — it has no manifest to publish.`);
440
+ process.exit(2);
441
+ }
442
+ }
386
443
 
387
444
  const workDir = join(tmpdir(), `bundle-runtime-${RUNTIME}-${VERSION}`);
388
445
  rmSync(workDir, { recursive: true, force: true });
@@ -390,8 +447,12 @@ mkdirSync(workDir, { recursive: true });
390
447
 
391
448
  console.log(`[bundle-runtime] ${RUNTIME} ${VERSION}`);
392
449
  console.log(`[bundle-runtime] work dir: ${workDir}`);
393
- console.log(`[bundle-runtime] bucket: ${BUCKET}`);
394
- console.log(`[bundle-runtime] account: ${ACCOUNT}`);
450
+ if (NPM_OUT_DIR) {
451
+ console.log(`[bundle-runtime] target: ${NPM_OUT_DIR} (npm package; R2 is not read or written)`);
452
+ } else {
453
+ console.log(`[bundle-runtime] bucket: ${BUCKET}`);
454
+ console.log(`[bundle-runtime] account: ${ACCOUNT}`);
455
+ }
395
456
 
396
457
  // ── 0. Optional repackage step (sysroot-prep wave) ──────────────────
397
458
  // Runs BEFORE the fetch loop. Produces one or more local files inside
@@ -480,6 +541,19 @@ if (!spec.ingest_only) {
480
541
  console.log(`[bundle-runtime] LICENSE → ${licenseBytes.length} bytes sha256=${licenseSha256.slice(0, 16)}…`);
481
542
  }
482
543
 
544
+ const totalMb = (downloaded.reduce((a, f) => a + f.size, 0) / 1024 / 1024).toFixed(2);
545
+
546
+ // ── --npm-package: the same artifacts, published through npm ────────
547
+ // Everything above this line is the staging the R2 path performs, and
548
+ // everything below it is Cloudflare. A runtime package is the staged blobs
549
+ // under their content-addressed keys plus the manifest that names them, which
550
+ // is the R2 bucket's shape for one runtime, in a directory `npm publish`
551
+ // takes. Nothing here reads or writes R2.
552
+ if (NPM_OUT_DIR) {
553
+ writeNpmPackage(NPM_OUT_DIR, composeManifest(downloaded, packageRuntimeArtifacts), downloaded);
554
+ process.exit(0);
555
+ }
556
+
483
557
  // ── 2. Upload each file as a content-addressed blob (deduped) ──────
484
558
  // Content path: blobs/<name>-<version>/<sha256>/<src-name>. Multiple
485
559
  // manifest entries pointing at identical content share one R2 upload.
@@ -497,8 +571,6 @@ for (const f of downloaded) {
497
571
  // ── 3 + 4. Manifest + catalog. Skipped in ingest_only mode (the swap
498
572
  // wave composes those at manifest-compose time; this prep pass only
499
573
  // stages the upstream blobs).
500
- const totalMb = (downloaded.reduce((a, f) => a + f.size, 0) / 1024 / 1024).toFixed(2);
501
-
502
574
  if (spec.ingest_only) {
503
575
  console.log(`\n[bundle-runtime] DONE (ingest_only)`);
504
576
  console.log(`[bundle-runtime] uploaded ${downloaded.length} file(s) (${totalMb} MiB) for ${RUNTIME}@${VERSION}`);
@@ -507,43 +579,8 @@ if (spec.ingest_only) {
507
579
  console.log(`[bundle-runtime] catalog: UNCHANGED (swap wave will flip default)`);
508
580
  } else {
509
581
  // ── 3. Write the per-version manifest ────────────────────────────
510
- const runtimeArtifacts = downloaded
511
- .filter((f) => f.transformMetadata)
512
- .map((f) => ({
513
- path: f.vfs,
514
- kind: f.transformMetadata.kind,
515
- id: f.transformMetadata.id,
516
- source_sha256: f.transformMetadata.source_sha256,
517
- sha256: f.sha256,
518
- }));
519
- runtimeArtifacts.push(...packageRuntimeArtifacts);
520
-
521
- const manifest = {
522
- name: RUNTIME,
523
- version: VERSION,
524
- license: spec.license,
525
- wasi_namespace: spec.wasi_namespace || null,
526
- files: downloaded.map((f) => ({
527
- path: f.vfs,
528
- content: f.r2Key,
529
- sha256: f.sha256,
530
- size: f.size,
531
- ...(f.mode ? { mode: f.mode } : {}),
532
- })),
533
- entrypoints: spec.files
534
- .filter((f) => f.runner)
535
- .map((f) => ({
536
- binName: f.binName,
537
- runner: f.runner,
538
- args: [],
539
- ...(f.kind ? { kind: f.kind } : {}),
540
- })),
541
- ...(runtimeArtifacts.length ? { runtime_artifacts: runtimeArtifacts } : {}),
542
- };
543
-
544
582
  const manifestLocal = join(workDir, 'manifest.json');
545
- const manifestText = JSON.stringify(manifest, null, 2);
546
- writeFileSync(manifestLocal, manifestText);
583
+ writeFileSync(manifestLocal, manifestText(composeManifest(downloaded, packageRuntimeArtifacts)));
547
584
  // Digest of the exact bytes uploaded below. The catalog carries it so the
548
585
  // supervisor can verify a manifest the same way a manifest lets it verify
549
586
  // a blob — see the trust-model note in src/runtime/runtime-catalog.ts.
@@ -788,6 +825,201 @@ function pinCatalogFromR2() {
788
825
  }
789
826
  }
790
827
 
828
+ // ── The manifest ─────────────────────────────────────────────────────
829
+ //
830
+ // What a runtime IS: the files it is made of, the digest of each, and the
831
+ // commands they answer. Both publishers compose it here so an embedder who
832
+ // installed the npm package and a session that ran `nimbus install` are
833
+ // holding the same description of the same runtime, byte for byte.
834
+
835
+ function composeManifest(downloaded, packageRuntimeArtifacts) {
836
+ const runtimeArtifacts = downloaded
837
+ .filter((f) => f.transformMetadata)
838
+ .map((f) => ({
839
+ path: f.vfs,
840
+ kind: f.transformMetadata.kind,
841
+ id: f.transformMetadata.id,
842
+ source_sha256: f.transformMetadata.source_sha256,
843
+ sha256: f.sha256,
844
+ }));
845
+ runtimeArtifacts.push(...packageRuntimeArtifacts);
846
+
847
+ return {
848
+ name: RUNTIME,
849
+ version: VERSION,
850
+ license: spec.license,
851
+ wasi_namespace: spec.wasi_namespace || null,
852
+ files: downloaded.map((f) => ({
853
+ path: f.vfs,
854
+ content: f.r2Key,
855
+ sha256: f.sha256,
856
+ size: f.size,
857
+ ...(f.mode ? { mode: f.mode } : {}),
858
+ })),
859
+ entrypoints: spec.files
860
+ .filter((f) => f.runner)
861
+ .map((f) => ({
862
+ binName: f.binName,
863
+ runner: f.runner,
864
+ args: [],
865
+ ...(f.kind ? { kind: f.kind } : {}),
866
+ })),
867
+ ...(runtimeArtifacts.length ? { runtime_artifacts: runtimeArtifacts } : {}),
868
+ };
869
+ }
870
+
871
+ function manifestText(manifest) {
872
+ return JSON.stringify(manifest, null, 2);
873
+ }
874
+
875
+ // ── --npm-package ────────────────────────────────────────────────────
876
+
877
+ /**
878
+ * Write the runtime as a directory `npm publish` accepts.
879
+ *
880
+ * The blobs keep the keys the manifest already names — `blobs/<name>-<version>/
881
+ * <sha256>/<file>`, the R2 object keys — so the manifest needs no npm-specific
882
+ * rewrite and comes out byte-identical to the one in the bucket. That is the
883
+ * point rather than a coincidence: `content` is documented as the publisher's
884
+ * key for a blob, and for this publisher a path inside its own tarball IS that
885
+ * key. There is one manifest format and one layout, and `readBlob` below is
886
+ * the whole of what distinguishes the two publishers.
887
+ */
888
+ function writeNpmPackage(outDir, manifest, downloaded) {
889
+ rmSync(outDir, { recursive: true, force: true });
890
+ mkdirSync(outDir, { recursive: true });
891
+
892
+ const written = new Set();
893
+ let unpackedBytes = 0;
894
+ for (const f of downloaded) {
895
+ if (written.has(f.r2Key)) continue;
896
+ written.add(f.r2Key);
897
+ unpackedBytes += f.size;
898
+ const dest = join(outDir, f.r2Key);
899
+ mkdirSync(dirname(dest), { recursive: true });
900
+ writeFileSync(dest, f.bytes);
901
+ }
902
+
903
+ writeFileSync(join(outDir, 'manifest.json'), manifestText(manifest));
904
+ writeFileSync(join(outDir, 'LICENSE'), spec.license_text);
905
+ writeFileSync(join(outDir, 'index.js'), runtimePackageEntry());
906
+ writeFileSync(join(outDir, 'index.d.ts'), runtimePackageTypes());
907
+ writeFileSync(join(outDir, 'README.md'), runtimePackageReadme());
908
+ const npmVersion = spec.npm.version ?? VERSION;
909
+ writeFileSync(join(outDir, 'package.json'), `${JSON.stringify({
910
+ name: spec.npm.name,
911
+ version: npmVersion,
912
+ description: `${spec.npm.summary}, as a Nimbus runtime package.`,
913
+ keywords: ['nimbus', 'wasm', 'wasi', 'runtime', RUNTIME],
914
+ homepage: 'https://github.com/AshishKumar4/Nimbus',
915
+ // No `directory`: the package is built from the runtime spec and the wasm
916
+ // build tree, and has no source directory of its own to point at.
917
+ repository: { type: 'git', url: 'git+https://github.com/AshishKumar4/Nimbus.git' },
918
+ bugs: 'https://github.com/AshishKumar4/Nimbus/issues',
919
+ license: spec.license,
920
+ type: 'module',
921
+ main: './index.js',
922
+ types: './index.d.ts',
923
+ exports: {
924
+ '.': { types: './index.d.ts', import: './index.js' },
925
+ './manifest.json': './manifest.json',
926
+ './package.json': './package.json',
927
+ },
928
+ files: ['index.js', 'index.d.ts', 'manifest.json', 'blobs', 'LICENSE', 'README.md'],
929
+ // The runtime is inert without the half that installs and runs it, and
930
+ // `index.d.ts` types itself against that package's exports.
931
+ peerDependencies: { '@nimbus-sh/core': '>=0.2.0' },
932
+ publishConfig: { access: 'public' },
933
+ }, null, 2)}\n`);
934
+
935
+ console.log(`\n[bundle-runtime] DONE (npm package)`);
936
+ console.log(`[bundle-runtime] ${spec.npm.name}@${npmVersion} → ${outDir}`);
937
+ console.log(`[bundle-runtime] ${written.size} blobs, ${(unpackedBytes / 1024 / 1024).toFixed(2)} MiB unpacked`);
938
+ console.log(`[bundle-runtime] publish with: npm publish ${outDir}`);
939
+ console.log(`[bundle-runtime] R2: UNTOUCHED (nothing was read from or written to Cloudflare)`);
940
+ }
941
+
942
+ /**
943
+ * The package entry point, identical in every runtime package.
944
+ *
945
+ * It is the `RuntimePackage` port from `@nimbus-sh/core`: a manifest, and the
946
+ * bytes it names. Core verifies every blob against the manifest before it
947
+ * reaches a filesystem, so this side neither hashes nor validates — it reads.
948
+ */
949
+ function runtimePackageEntry() {
950
+ return `/**
951
+ * A Nimbus runtime package: a manifest, and the content-addressed blobs it
952
+ * names. Pass the default export to \`NimbusWorkspace.create({ runtimes })\`
953
+ * and the runtime installs into the workspace filesystem, digest-verified,
954
+ * at the same path \`nimbus install\` uses on Cloudflare.
955
+ *
956
+ * Generated by packages/worker/scripts/bundle-runtime.mjs. Do not edit.
957
+ */
958
+
959
+ import { readFileSync } from 'node:fs';
960
+
961
+ const root = new URL('./', import.meta.url);
962
+
963
+ export const manifest = JSON.parse(readFileSync(new URL('manifest.json', root), 'utf8'));
964
+
965
+ /** The bytes of one manifest file entry, by the publisher key it carries. */
966
+ export function readBlob(file) {
967
+ // Copied rather than handed over: readFileSync returns a pooled Buffer for
968
+ // small files, whose backing ArrayBuffer holds other files' bytes too.
969
+ return new Uint8Array(readFileSync(new URL(file.content, root)));
970
+ }
971
+
972
+ export default { manifest, readBlob };
973
+ `;
974
+ }
975
+
976
+ function runtimePackageTypes() {
977
+ return `import type { ManifestFile, RuntimeManifest, RuntimePackage } from '@nimbus-sh/core';
978
+
979
+ export declare const manifest: RuntimeManifest;
980
+ export declare function readBlob(file: ManifestFile): Uint8Array;
981
+
982
+ declare const runtimePackage: RuntimePackage;
983
+ export default runtimePackage;
984
+ `;
985
+ }
986
+
987
+ function runtimePackageReadme() {
988
+ return `# ${spec.npm.name}
989
+
990
+ ${spec.npm.summary}, packaged for [Nimbus](https://github.com/AshishKumar4/Nimbus).
991
+
992
+ This package is data: the runtime's wasm and support files, content-addressed,
993
+ plus the manifest that describes them. It does nothing on its own —
994
+ [\`@nimbus-sh/core\`](https://www.npmjs.com/package/@nimbus-sh/core) installs it
995
+ into a workspace filesystem and runs it.
996
+
997
+ \`\`\`bash
998
+ npm install @nimbus-sh/core ${spec.npm.name}
999
+ \`\`\`
1000
+
1001
+ \`\`\`js
1002
+ import { NimbusWorkspace, localFacetHost } from '@nimbus-sh/core';
1003
+ import ${RUNTIME} from '${spec.npm.name}';
1004
+
1005
+ const workspace = await NimbusWorkspace.create({
1006
+ sql, // your SQLite, through the SqlDatabase port
1007
+ facets: localFacetHost(),
1008
+ runtimes: [${RUNTIME}],
1009
+ });
1010
+ \`\`\`
1011
+
1012
+ Every file is verified against the manifest's SHA-256 before it reaches the
1013
+ filesystem. The same bytes are served to Cloudflare deployments from R2 by
1014
+ \`nimbus install ${RUNTIME}\`, under the same manifest.
1015
+
1016
+ ## Licence
1017
+
1018
+ ${spec.license}. See the bundled \`LICENSE\` for the notice and where to find
1019
+ the full text and corresponding source.
1020
+ `;
1021
+ }
1022
+
791
1023
  // ── Runtime transforms ───────────────────────────────────────────────
792
1024
 
793
1025
  function runtimeBlobKey(src, sha256) {
@@ -1,93 +0,0 @@
1
- /**
2
- * npm-tarball-stream.ts — pure streaming tar primitives.
3
- *
4
- * Extracted from npm-tarball.ts so these helpers can be esbuild-bundled
5
- * WITHOUT dragging in NpmCache / NpmResolver / SqliteVFS. Consumed by
6
- * scripts/bundle-facet-workers.mjs which emits a string constant the
7
- * NimbusLoaderPool uses to inject the tar parser into dynamic workers.
8
- *
9
- * Zero dependencies. Works identically on the supervisor and inside a
10
- * facet isolate. Never buffers the full decompressed tarball — peak
11
- * transient heap is one file's bytes plus a 512-byte carry.
12
- */
13
- /**
14
- * Maximum size of a single file inside a tarball. Larger entries are skipped.
15
- *
16
- * History: 5 MB was too low — it silently dropped `esbuild-wasm/esbuild.wasm`
17
- * (11.35 MB on v0.24.2), which made Nimbus-in-Nimbus `npm run dev` fail with
18
- * `No such module "esbuild-wasm/esbuild.wasm"` since the missing file caused
19
- * esbuild's VFS plugin to mark the import `external`, and workerd's LOADER
20
- * has no entry for that specifier. 20 MB covers esbuild-wasm with headroom
21
- * while keeping per-facet peak heap bounded for the streaming extractor.
22
- */
23
- export declare const MAX_FILE_BYTES = 20000000;
24
- /**
25
- * Read one tar header (USTAR) out of `block`. Returns parsed fields or
26
- * `null` for an end-of-archive block (all zeros).
27
- */
28
- /**
29
- * Collapse "."/".." segments in a tar entry's package-relative path.
30
- * Returns the canonical relative path, or '' when the entry escapes its
31
- * package root (a leading ".." that pops above the root) — the caller
32
- * treats '' as a no-name entry and skips it. Mirrors the segment logic in
33
- * w7-frame's canonicalPath so joined write paths are always accepted.
34
- */
35
- export declare function canonicalTarName(name: string): string;
36
- export declare function parseTarHeader(block: Uint8Array): {
37
- name: string;
38
- size: number;
39
- typeFlag: number;
40
- } | null;
41
- /**
42
- * Wrap a `ReadableStream<Uint8Array>` as an async iterable. Workerd and
43
- * Node both support `Symbol.asyncIterator` on ReadableStream, but we
44
- * spell the reader loop out so we don't depend on ambient lib typings.
45
- */
46
- export declare function readableStreamToAsyncIterable(rs: ReadableStream<Uint8Array>): AsyncGenerator<Uint8Array, void, undefined>;
47
- /**
48
- * Reason a tar entry was skipped and never yielded. Surfaced to callers
49
- * via the optional `onSkip` callback on `streamTarEntries`.
50
- *
51
- * - 'too-large': size > MAX_FILE_BYTES. The most common reason Nimbus
52
- * cares about — it's what caused esbuild-wasm/esbuild.wasm to vanish
53
- * silently in Nimbus-in-Nimbus before the cap was raised.
54
- * - 'non-regular': typeFlag indicates a symlink / hardlink / directory /
55
- * PaxHeader / GNU LongName etc. These aren't files we stage.
56
- * - 'no-name': header parsed but name was empty (malformed or a PaxHeader
57
- * that our parser didn't recognize as non-regular).
58
- */
59
- export type TarSkipReason = 'too-large' | 'non-regular' | 'no-name';
60
- /**
61
- * Optional skip-observer passed to `streamTarEntries`. Called ONCE per
62
- * skipped entry, with the declared name (may be empty for 'no-name'
63
- * skips) and the declared size in bytes.
64
- *
65
- * Consumers typically push these into a per-package warnings array so
66
- * users see what wasn't installed. The callback is synchronous and
67
- * must not throw — thrown errors are swallowed to keep the extractor
68
- * best-effort.
69
- */
70
- export type TarSkipCallback = (name: string, size: number, reason: TarSkipReason) => void;
71
- /**
72
- * Streaming tar extractor.
73
- *
74
- * Consumes an async iterable of Uint8Array chunks (the decompressed tar
75
- * byte stream) and yields one `{ name, data }` entry per regular file,
76
- * as each file completes.
77
- *
78
- * Memory invariant: holds at most one pending file's bytes (≤ MAX_FILE_BYTES)
79
- * plus a small carry buffer for the tar header being assembled.
80
- *
81
- * Skips: symlinks, directories, hardlinks, long-name extensions (PaxHeader),
82
- * and any file whose declared size exceeds MAX_FILE_BYTES.
83
- *
84
- * If `onSkip` is provided, it is invoked for each skipped entry with the
85
- * name, declared size, and reason code. Callers that need to surface
86
- * dropped-file warnings to users should pass one; legacy callers that
87
- * omit the arg still behave exactly as before (silent skip).
88
- */
89
- export declare function streamTarEntries(source: AsyncIterable<Uint8Array>, onSkip?: TarSkipCallback): AsyncGenerator<{
90
- name: string;
91
- data: Uint8Array;
92
- }, void, undefined>;
93
- //# sourceMappingURL=tarball-stream.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tarball-stream.d.ts","sourceRoot":"","sources":["../../src/npm/tarball-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,WAAa,CAAC;AAEzC;;;GAGG;AACH;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWrD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+BzG;AAED;;;;GAIG;AACH,wBAAuB,6BAA6B,CAClD,EAAE,EAAE,cAAc,CAAC,UAAU,CAAC,GAC7B,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,CAW7C;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAEpE;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,KAClB,IAAI,CAAC;AAEV;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAuB,gBAAgB,CACrC,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,EACjC,MAAM,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CA6GrE"}