@nimbus-sh/worker 0.1.4 → 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 (141) 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/loaders/loader-pool.d.ts +7 -0
  24. package/dist/loaders/loader-pool.d.ts.map +1 -1
  25. package/dist/loaders/loader-pool.js +3 -1
  26. package/dist/npm/installer.d.ts.map +1 -1
  27. package/dist/npm/installer.js +47 -27
  28. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  29. package/dist/npm/pre-bundle-facet.js +2 -1
  30. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  31. package/dist/npm/resolve-one-facet.js +41 -13
  32. package/dist/npm/resolver.d.ts.map +1 -1
  33. package/dist/npm/resolver.js +70 -35
  34. package/dist/router/index.d.ts.map +1 -1
  35. package/dist/router/index.js +45 -21
  36. package/dist/router/remote-api.d.ts.map +1 -1
  37. package/dist/router/remote-api.js +29 -8
  38. package/dist/runtime/barrel-synthesizer.d.ts +7 -0
  39. package/dist/runtime/barrel-synthesizer.d.ts.map +1 -1
  40. package/dist/runtime/barrel-synthesizer.js +11 -0
  41. package/dist/runtime/clang-runner.d.ts +2 -2
  42. package/dist/runtime/clang-runner.d.ts.map +1 -1
  43. package/dist/runtime/clang-runner.js +64 -47
  44. package/dist/runtime/esbuild-service.d.ts +12 -5
  45. package/dist/runtime/esbuild-service.d.ts.map +1 -1
  46. package/dist/runtime/esbuild-service.js +28 -14
  47. package/dist/runtime/node-runner.d.ts +2 -0
  48. package/dist/runtime/node-runner.d.ts.map +1 -1
  49. package/dist/runtime/node-shims.d.ts +4 -2
  50. package/dist/runtime/node-shims.d.ts.map +1 -1
  51. package/dist/runtime/node-shims.js +404 -55
  52. package/dist/runtime/os-contracts.d.ts +128 -0
  53. package/dist/runtime/os-contracts.d.ts.map +1 -0
  54. package/dist/runtime/os-contracts.js +1 -0
  55. package/dist/runtime/package-manager.d.ts +31 -0
  56. package/dist/runtime/package-manager.d.ts.map +1 -1
  57. package/dist/runtime/package-manager.js +162 -15
  58. package/dist/runtime/port-registry.d.ts +5 -0
  59. package/dist/runtime/port-registry.d.ts.map +1 -1
  60. package/dist/runtime/port-registry.js +22 -1
  61. package/dist/runtime/pyodide-runtime-assets.d.ts +19 -0
  62. package/dist/runtime/pyodide-runtime-assets.d.ts.map +1 -0
  63. package/dist/runtime/pyodide-runtime-assets.js +44 -0
  64. package/dist/runtime/python-repl.d.ts +3 -0
  65. package/dist/runtime/python-repl.d.ts.map +1 -1
  66. package/dist/runtime/python-repl.js +18 -32
  67. package/dist/runtime/python-runner.d.ts +8 -9
  68. package/dist/runtime/python-runner.d.ts.map +1 -1
  69. package/dist/runtime/python-runner.js +958 -118
  70. package/dist/runtime/python-socket-shim.d.ts +11 -0
  71. package/dist/runtime/python-socket-shim.d.ts.map +1 -0
  72. package/dist/runtime/python-socket-shim.js +526 -0
  73. package/dist/runtime/require-resolver.d.ts.map +1 -1
  74. package/dist/runtime/require-resolver.js +2 -11
  75. package/dist/runtime/ruby-gems.d.ts +25 -0
  76. package/dist/runtime/ruby-gems.d.ts.map +1 -0
  77. package/dist/runtime/ruby-gems.js +582 -0
  78. package/dist/runtime/ruby-runner.d.ts +2 -4
  79. package/dist/runtime/ruby-runner.d.ts.map +1 -1
  80. package/dist/runtime/ruby-runner.js +335 -34
  81. package/dist/runtime/runtime-catalog.d.ts +16 -4
  82. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  83. package/dist/runtime/runtime-catalog.js +21 -10
  84. package/dist/runtime/runtime-registry.d.ts +3 -0
  85. package/dist/runtime/runtime-registry.d.ts.map +1 -1
  86. package/dist/runtime/runtime-registry.js +4 -0
  87. package/dist/runtime/sqlite-runtime-fs-bridge.d.ts +43 -0
  88. package/dist/runtime/sqlite-runtime-fs-bridge.d.ts.map +1 -0
  89. package/dist/runtime/sqlite-runtime-fs-bridge.js +224 -0
  90. package/dist/runtime/static-server.d.ts +3 -0
  91. package/dist/runtime/static-server.d.ts.map +1 -0
  92. package/dist/runtime/static-server.js +121 -0
  93. package/dist/runtime/vfs-snapshot.d.ts +57 -0
  94. package/dist/runtime/vfs-snapshot.d.ts.map +1 -0
  95. package/dist/runtime/vfs-snapshot.js +141 -0
  96. package/dist/runtime/virtual-socket-kernel.d.ts +16 -0
  97. package/dist/runtime/virtual-socket-kernel.d.ts.map +1 -0
  98. package/dist/runtime/virtual-socket-kernel.js +360 -0
  99. package/dist/runtime/wasi-instance.d.ts +6 -3
  100. package/dist/runtime/wasi-instance.d.ts.map +1 -1
  101. package/dist/runtime/wasm-runner.d.ts +1 -25
  102. package/dist/runtime/wasm-runner.d.ts.map +1 -1
  103. package/dist/runtime/wasm-runner.js +1 -160
  104. package/dist/session/agent.d.ts +43 -0
  105. package/dist/session/agent.d.ts.map +1 -0
  106. package/dist/session/agent.js +1252 -0
  107. package/dist/session/init.d.ts.map +1 -1
  108. package/dist/session/init.js +64 -19
  109. package/dist/session/nimbus-session.d.ts +14 -2
  110. package/dist/session/nimbus-session.d.ts.map +1 -1
  111. package/dist/session/nimbus-session.js +104 -30
  112. package/dist/session/programmatic.d.ts +10 -0
  113. package/dist/session/programmatic.d.ts.map +1 -1
  114. package/dist/session/programmatic.js +121 -0
  115. package/dist/session/routes.d.ts.map +1 -1
  116. package/dist/session/routes.js +19 -1
  117. package/dist/session/rpc.d.ts +11 -0
  118. package/dist/session/rpc.d.ts.map +1 -1
  119. package/dist/session/rpc.js +56 -43
  120. package/dist/session/supervisor-rpc.d.ts +15 -0
  121. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  122. package/dist/session/supervisor-rpc.js +32 -0
  123. package/dist/session/ws.d.ts +4 -3
  124. package/dist/session/ws.d.ts.map +1 -1
  125. package/dist/session/ws.js +11 -1
  126. package/dist/shell/unix-commands.d.ts.map +1 -1
  127. package/dist/shell/unix-commands.js +52 -51
  128. package/dist/vfs/path.d.ts +8 -4
  129. package/dist/vfs/path.d.ts.map +1 -1
  130. package/dist/vfs/path.js +16 -4
  131. package/dist/vfs/sqlite-vfs.d.ts +2 -0
  132. package/dist/vfs/sqlite-vfs.d.ts.map +1 -1
  133. package/dist/vfs/sqlite-vfs.js +11 -0
  134. package/dist/vfs/symlink-registry.d.ts +7 -1
  135. package/dist/vfs/symlink-registry.d.ts.map +1 -1
  136. package/dist/vfs/symlink-registry.js +16 -11
  137. package/package.json +4 -1
  138. package/public/index.html +240 -0
  139. package/public/s/index.html +1316 -128
  140. package/runtime-contracts/pyodide-workerd-adapter.json +18 -0
  141. package/scripts/bundle-runtime.mjs +99 -24
@@ -0,0 +1,18 @@
1
+ {
2
+ "id": "pyodide-0.29.4-workerd-adapter-v1",
3
+ "pyodideVersion": "0.29.4",
4
+ "artifactPath": "share/pyodide/pyodide.asm.js",
5
+ "sentinel": "/* Nimbus Pyodide workerd adapter: pyodide-0.29.4-workerd-adapter-v1 */",
6
+ "patches": [
7
+ {
8
+ "name": "workerd-runtime-environment-fallback",
9
+ "find": "else throw new Error(\"Cannot determine runtime environment\")",
10
+ "replace": "else {/* Nimbus workerd adapter: browser-like runtime fallback */}"
11
+ },
12
+ {
13
+ "name": "workerd-main-thread-loader",
14
+ "find": "if(d.IN_BROWSER_MAIN_THREAD)",
15
+ "replace": "if(true||d.IN_BROWSER_MAIN_THREAD)"
16
+ }
17
+ ]
18
+ }
@@ -8,7 +8,7 @@
8
8
  * node scripts/bundle-runtime.mjs python 0.29.4 [--bucket nimbus-runtime-cache]
9
9
  *
10
10
  * Per `2026-05-10-true-os/plan.md` §2.4:
11
- * - Blobs are content-addressed under `blobs/<name>-<version>/<file>`.
11
+ * - Blobs are content-addressed under `blobs/<name>-<version>/<sha256>/<file>`.
12
12
  * - Per-version manifest at `manifests/<name>-<version>.json` lists
13
13
  * the files (path-in-VFS, content R2 key, sha256, size, mode).
14
14
  * - Top-level `catalog/v1.json` lists known runtimes.
@@ -31,7 +31,7 @@
31
31
  */
32
32
 
33
33
  import { createHash } from 'node:crypto';
34
- import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
34
+ import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from 'node:fs';
35
35
  import { execSync } from 'node:child_process';
36
36
  import { tmpdir } from 'node:os';
37
37
  import { basename, join } from 'node:path';
@@ -42,6 +42,9 @@ if (!ACCOUNT) {
42
42
  process.exit(1);
43
43
  }
44
44
  const WRANGLER = './node_modules/.bin/wrangler';
45
+ const PYODIDE_WORKERD_ADAPTER = JSON.parse(
46
+ readFileSync(new URL('../runtime-contracts/pyodide-workerd-adapter.json', import.meta.url), 'utf8'),
47
+ );
45
48
 
46
49
  const rawArgs = process.argv.slice(2);
47
50
  const positionalArgs = [];
@@ -152,10 +155,11 @@ const SPECS = {
152
155
  // user-VFS layout matches binji-clang's convention (bin/ for
153
156
  // exec entry, share/<name>/ for runtime-private blobs).
154
157
  { src: 'pyodide.asm.wasm', vfs: 'share/pyodide/pyodide.asm.wasm' },
155
- // The Emscripten JS half. python-runner injects this verbatim
156
- // as a LOADER module-source entry so workerd compiles it at
157
- // module-load time (CSP-blocked at request time).
158
- { src: 'pyodide.asm.js', vfs: 'share/pyodide/pyodide.asm.js' },
158
+ // The Emscripten JS half. Runtime sync adapts it once for
159
+ // workerd and records that contract in manifest metadata; the
160
+ // Python runner consumes the resulting artifact without patching
161
+ // it during session boot.
162
+ { src: 'pyodide.asm.js', vfs: 'share/pyodide/pyodide.asm.js', transform: 'pyodide-workerd-adapter' },
159
163
  // Python 3.13 stdlib. Pyodide writes this into its Emscripten
160
164
  // MEMFS at /lib/python313.zip and CPython imports from there
161
165
  // via the ZipImporter on sys.path.
@@ -255,6 +259,7 @@ if (!spec) {
255
259
  }
256
260
 
257
261
  const workDir = join(tmpdir(), `bundle-runtime-${RUNTIME}-${VERSION}`);
262
+ rmSync(workDir, { recursive: true, force: true });
258
263
  mkdirSync(workDir, { recursive: true });
259
264
 
260
265
  console.log(`[bundle-runtime] ${RUNTIME} ${VERSION}`);
@@ -308,9 +313,16 @@ for (const f of spec.files) {
308
313
  execSync(`curl -sS -L -o "${local}" "${url}"`, { stdio: 'inherit' });
309
314
  }
310
315
  }
311
- const bytes = readFileSync(local);
316
+ const sourceBytes = readFileSync(local);
317
+ const transformed = applyRuntimeTransform(f, sourceBytes);
318
+ if (transformed.bytes !== sourceBytes) {
319
+ writeFileSync(local, transformed.bytes);
320
+ console.log(`[bundle-runtime] transform ${f.src}: ${transformed.metadata.id}`);
321
+ }
322
+ const bytes = transformed.bytes;
312
323
  const sha256 = createHash('sha256').update(bytes).digest('hex');
313
- downloaded.push({ ...f, local, bytes, sha256, size: bytes.length });
324
+ const r2Key = runtimeBlobKey(f.src, sha256);
325
+ downloaded.push({ ...f, local, bytes, sha256, size: bytes.length, r2Key, transformMetadata: transformed.metadata });
314
326
  console.log(`[bundle-runtime] ${f.vfs} (← ${f.src}) → ${(bytes.length / 1024 / 1024).toFixed(2)} MiB sha256=${sha256.slice(0, 16)}…`);
315
327
  }
316
328
 
@@ -323,22 +335,21 @@ if (!spec.ingest_only) {
323
335
  const licenseSha256 = createHash('sha256').update(licenseBytes).digest('hex');
324
336
  downloaded.push({
325
337
  src: 'LICENSE', vfs: 'LICENSE', local: licenseLocal, bytes: licenseBytes,
326
- sha256: licenseSha256, size: licenseBytes.length,
338
+ sha256: licenseSha256, size: licenseBytes.length, r2Key: runtimeBlobKey('LICENSE', licenseSha256),
327
339
  });
328
340
  console.log(`[bundle-runtime] LICENSE → ${licenseBytes.length} bytes sha256=${licenseSha256.slice(0, 16)}…`);
329
341
  }
330
342
 
331
343
  // ── 2. Upload each file as a content-addressed blob (deduped) ──────
332
- // Content path: blobs/<name>-<version>/<src-name>. Multiple manifest
333
- // entries pointing at the same src share one R2 upload.
334
- const uploadedSrc = new Set();
344
+ // Content path: blobs/<name>-<version>/<sha256>/<src-name>. Multiple
345
+ // manifest entries pointing at identical content share one R2 upload.
346
+ const uploadedBlobKeys = new Set();
335
347
  for (const f of downloaded) {
336
- if (uploadedSrc.has(f.src)) continue;
337
- uploadedSrc.add(f.src);
338
- const r2Key = `blobs/${RUNTIME}-${VERSION}/${f.src}`;
339
- console.log(`[bundle-runtime] put r2://${BUCKET}/${r2Key}`);
348
+ if (uploadedBlobKeys.has(f.r2Key)) continue;
349
+ uploadedBlobKeys.add(f.r2Key);
350
+ console.log(`[bundle-runtime] put r2://${BUCKET}/${f.r2Key}`);
340
351
  execSync(
341
- `CLOUDFLARE_ACCOUNT_ID=${ACCOUNT} ${WRANGLER} r2 object put ${BUCKET}/${r2Key} --file "${f.local}" --remote`,
352
+ `CLOUDFLARE_ACCOUNT_ID=${ACCOUNT} ${WRANGLER} r2 object put ${BUCKET}/${f.r2Key} --file "${f.local}" --remote`,
342
353
  { stdio: 'inherit' },
343
354
  );
344
355
  }
@@ -356,6 +367,16 @@ if (spec.ingest_only) {
356
367
  console.log(`[bundle-runtime] catalog: UNCHANGED (swap wave will flip default)`);
357
368
  } else {
358
369
  // ── 3. Write the per-version manifest ────────────────────────────
370
+ const runtimeArtifacts = downloaded
371
+ .filter((f) => f.transformMetadata)
372
+ .map((f) => ({
373
+ path: f.vfs,
374
+ kind: f.transformMetadata.kind,
375
+ id: f.transformMetadata.id,
376
+ source_sha256: f.transformMetadata.source_sha256,
377
+ sha256: f.sha256,
378
+ }));
379
+
359
380
  const manifest = {
360
381
  name: RUNTIME,
361
382
  version: VERSION,
@@ -364,7 +385,7 @@ if (spec.ingest_only) {
364
385
  memfs_companion: spec.memfs_companion || null,
365
386
  files: downloaded.map((f) => ({
366
387
  path: f.vfs,
367
- content: `blobs/${RUNTIME}-${VERSION}/${f.src}`,
388
+ content: f.r2Key,
368
389
  sha256: f.sha256,
369
390
  size: f.size,
370
391
  ...(f.mode ? { mode: f.mode } : {}),
@@ -377,6 +398,7 @@ if (spec.ingest_only) {
377
398
  args: [],
378
399
  ...(f.kind ? { kind: f.kind } : {}),
379
400
  })),
401
+ ...(runtimeArtifacts.length ? { runtime_artifacts: runtimeArtifacts } : {}),
380
402
  };
381
403
 
382
404
  const manifestLocal = join(workDir, 'manifest.json');
@@ -403,16 +425,14 @@ if (spec.ingest_only) {
403
425
  }
404
426
 
405
427
  if (!catalog.runtimes[RUNTIME]) catalog.runtimes[RUNTIME] = { default: VERSION, versions: {} };
406
- // Catalog size_bytes counts unique blob content (not duplicated
407
- // manifest entries pointing at the same src). Preserved from
408
- // Pyodide P1 (05c4ce6), where `python` and `python3` share one
409
- // BIN_MARKER blob.
428
+ // Catalog size_bytes counts unique blob content, not duplicate
429
+ // manifest entries.
410
430
  const catalogSize = (() => {
411
431
  const seen = new Set();
412
432
  let total = 0;
413
433
  for (const f of downloaded) {
414
- if (seen.has(f.src)) continue;
415
- seen.add(f.src);
434
+ if (seen.has(f.r2Key)) continue;
435
+ seen.add(f.r2Key);
416
436
  total += f.size;
417
437
  }
418
438
  return total;
@@ -440,6 +460,61 @@ if (spec.ingest_only) {
440
460
  console.log(`[bundle-runtime] catalog: r2://${BUCKET}/${catalogR2Key}`);
441
461
  }
442
462
 
463
+ // ── Runtime transforms ───────────────────────────────────────────────
464
+
465
+ function runtimeBlobKey(src, sha256) {
466
+ return `blobs/${RUNTIME}-${VERSION}/${sha256}/${src}`;
467
+ }
468
+
469
+ function applyRuntimeTransform(fileSpec, sourceBytes) {
470
+ if (!fileSpec.transform) return { bytes: sourceBytes, metadata: null };
471
+ if (fileSpec.transform !== 'pyodide-workerd-adapter') {
472
+ throw new Error(`unknown transform '${fileSpec.transform}' for ${fileSpec.src}`);
473
+ }
474
+ const sourceSha256 = createHash('sha256').update(sourceBytes).digest('hex');
475
+ const sourceText = sourceBytes.toString('utf8');
476
+ const transformedText = applyPyodideWorkerdAdapter(sourceText, fileSpec.src);
477
+ const bytes = Buffer.from(transformedText, 'utf8');
478
+ return {
479
+ bytes,
480
+ metadata: {
481
+ kind: 'workerd-adapter',
482
+ id: PYODIDE_WORKERD_ADAPTER.id,
483
+ source_sha256: sourceSha256,
484
+ },
485
+ };
486
+ }
487
+
488
+ function applyPyodideWorkerdAdapter(sourceText, label) {
489
+ if (sourceText.startsWith(PYODIDE_WORKERD_ADAPTER.sentinel)) {
490
+ throw new Error(`${label} already contains ${PYODIDE_WORKERD_ADAPTER.id}; expected pristine upstream source`);
491
+ }
492
+ let out = sourceText;
493
+ for (const patch of PYODIDE_WORKERD_ADAPTER.patches) {
494
+ const matches = countOccurrences(out, patch.find);
495
+ if (matches !== 1) {
496
+ throw new Error(
497
+ `${label}: adapter ${PYODIDE_WORKERD_ADAPTER.id} expected exactly one ` +
498
+ `'${patch.name}' target, found ${matches}`,
499
+ );
500
+ }
501
+ out = out.replace(patch.find, patch.replace);
502
+ }
503
+ return `${PYODIDE_WORKERD_ADAPTER.sentinel}\n${out}`;
504
+ }
505
+
506
+ function countOccurrences(haystack, needle) {
507
+ if (!needle) return 0;
508
+ let count = 0;
509
+ let offset = 0;
510
+ while (true) {
511
+ const idx = haystack.indexOf(needle, offset);
512
+ if (idx < 0) return count;
513
+ count++;
514
+ offset = idx + needle.length;
515
+ }
516
+ }
517
+
443
518
  // ── Repackage step (sysroot-prep wave) ──────────────────────────────
444
519
  //
445
520
  // Downloads an upstream `.tar.gz`, extracts it, and re-tars a subset of