@nimbus-sh/core 0.3.0 → 0.5.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.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/dist/_shared/error-text.d.ts +15 -0
  4. package/dist/_shared/error-text.d.ts.map +1 -0
  5. package/dist/_shared/error-text.js +21 -0
  6. package/dist/_shared/exports-resolver.d.ts +19 -7
  7. package/dist/_shared/exports-resolver.d.ts.map +1 -1
  8. package/dist/_shared/exports-resolver.js +1 -1
  9. package/dist/_shared/retry.d.ts.map +1 -1
  10. package/dist/_shared/retry.js +3 -1
  11. package/dist/_shared/tarball-stream.d.ts +93 -0
  12. package/dist/_shared/tarball-stream.d.ts.map +1 -0
  13. package/dist/_shared/tarball-stream.js +235 -0
  14. package/dist/_shared/tarball.d.ts +17 -0
  15. package/dist/_shared/tarball.d.ts.map +1 -0
  16. package/dist/_shared/tarball.js +39 -0
  17. package/dist/_shared/w7-frame.js +2 -1
  18. package/dist/constants.d.ts.map +1 -1
  19. package/dist/constants.js +30 -16
  20. package/dist/observability/oom-classify.d.ts +1 -1
  21. package/dist/observability/oom-classify.d.ts.map +1 -1
  22. package/dist/observability/oom-classify.js +7 -0
  23. package/dist/observability/oom-discriminator.d.ts +1 -1
  24. package/dist/runtime/clang-runner.d.ts +38 -0
  25. package/dist/runtime/clang-runner.d.ts.map +1 -0
  26. package/dist/runtime/clang-runner.js +866 -0
  27. package/dist/runtime/esbuild-service.d.ts +4 -3
  28. package/dist/runtime/esbuild-service.d.ts.map +1 -1
  29. package/dist/runtime/esbuild-service.js +9 -4
  30. package/dist/runtime/facet-host.d.ts +12 -0
  31. package/dist/runtime/facet-host.d.ts.map +1 -1
  32. package/dist/runtime/installed-runtimes.d.ts +4 -3
  33. package/dist/runtime/installed-runtimes.d.ts.map +1 -1
  34. package/dist/runtime/local-facet-host.d.ts.map +1 -1
  35. package/dist/runtime/local-facet-host.js +29 -9
  36. package/dist/runtime/long-running-handle.d.ts +3 -3
  37. package/dist/runtime/long-running-handle.d.ts.map +1 -1
  38. package/dist/runtime/os-contracts.d.ts +7 -5
  39. package/dist/runtime/os-contracts.d.ts.map +1 -1
  40. package/dist/runtime/port-registry.d.ts +28 -0
  41. package/dist/runtime/port-registry.d.ts.map +1 -1
  42. package/dist/runtime/port-registry.js +79 -9
  43. package/dist/runtime/process-logs.d.ts +9 -1
  44. package/dist/runtime/process-logs.d.ts.map +1 -1
  45. package/dist/runtime/project-detect.d.ts +6 -1
  46. package/dist/runtime/project-detect.d.ts.map +1 -1
  47. package/dist/runtime/require-resolver.d.ts.map +1 -1
  48. package/dist/runtime/require-resolver.js +3 -4
  49. package/dist/runtime/ruby-gems.d.ts +30 -0
  50. package/dist/runtime/ruby-gems.d.ts.map +1 -0
  51. package/dist/runtime/ruby-gems.js +636 -0
  52. package/dist/runtime/ruby-runner.d.ts +127 -0
  53. package/dist/runtime/ruby-runner.d.ts.map +1 -0
  54. package/dist/runtime/ruby-runner.js +1357 -0
  55. package/dist/runtime/runtime-registry.d.ts +4 -3
  56. package/dist/runtime/runtime-registry.d.ts.map +1 -1
  57. package/dist/runtime/runtime-registry.js +2 -1
  58. package/dist/runtime/session-process-supervisor.d.ts +15 -0
  59. package/dist/runtime/session-process-supervisor.d.ts.map +1 -1
  60. package/dist/runtime/session-process-supervisor.js +30 -0
  61. package/dist/runtime/sqlite-runtime-fs-bridge.js +1 -5
  62. package/dist/runtime/virtual-socket-kernel.d.ts.map +1 -1
  63. package/dist/runtime/virtual-socket-kernel.generated.d.ts +1 -1
  64. package/dist/runtime/virtual-socket-kernel.generated.d.ts.map +1 -1
  65. package/dist/runtime/virtual-socket-kernel.generated.js +2 -2
  66. package/dist/runtime/virtual-socket-kernel.js +10 -5
  67. package/dist/runtime/wasm-runner.d.ts.map +1 -1
  68. package/dist/runtime/wasm-runner.js +22 -14
  69. package/dist/shell/features.d.ts.map +1 -1
  70. package/dist/shell/features.js +5 -4
  71. package/dist/shell/unix-commands.d.ts +14 -1
  72. package/dist/shell/unix-commands.d.ts.map +1 -1
  73. package/dist/shell/unix-commands.js +115 -69
  74. package/dist/substrate/lifo/commands/net/ip.d.ts.map +1 -1
  75. package/dist/substrate/lifo/commands/system/ps.d.ts +2 -1
  76. package/dist/substrate/lifo/commands/system/ps.d.ts.map +1 -1
  77. package/dist/substrate/lifo/kernel/ServiceManager.d.ts.map +1 -1
  78. package/dist/substrate/lifo/kernel/ServiceManager.js +0 -2
  79. package/dist/substrate/lifo/kernel/network/NetworkStack.d.ts +22 -11
  80. package/dist/substrate/lifo/kernel/network/NetworkStack.d.ts.map +1 -1
  81. package/dist/substrate/lifo/kernel/network/NetworkStack.js +0 -2
  82. package/dist/substrate/lifo/kernel/network/tunnel/WebSocketTunnel.d.ts +2 -1
  83. package/dist/substrate/lifo/kernel/network/tunnel/WebSocketTunnel.d.ts.map +1 -1
  84. package/dist/substrate/lifo/kernel/network/tunnel/WebSocketTunnel.js +3 -4
  85. package/dist/substrate/lifo/kernel/vfs/VFS.d.ts +17 -0
  86. package/dist/substrate/lifo/kernel/vfs/VFS.d.ts.map +1 -1
  87. package/dist/substrate/lifo/kernel/vfs/VFS.js +33 -0
  88. package/dist/substrate/lifo/node-compat/esbuild.d.ts.map +1 -1
  89. package/dist/substrate/lifo/node-compat/esbuild.js +2 -4
  90. package/dist/substrate/lifo/node-compat/index.d.ts.map +1 -1
  91. package/dist/substrate/lifo/node-compat/index.js +3 -2
  92. package/dist/substrate/lifo/node-compat/loose-equality.d.ts +19 -0
  93. package/dist/substrate/lifo/node-compat/loose-equality.d.ts.map +1 -0
  94. package/dist/substrate/lifo/node-compat/loose-equality.js +91 -0
  95. package/dist/substrate/lifo/node-compat/process.d.ts.map +1 -1
  96. package/dist/substrate/lifo/node-compat/process.js +6 -3
  97. package/dist/substrate/lifo/shell/Shell.d.ts +19 -0
  98. package/dist/substrate/lifo/shell/Shell.d.ts.map +1 -1
  99. package/dist/substrate/lifo/shell/Shell.js +86 -75
  100. package/dist/substrate/lifo/shell/lexer.d.ts +9 -0
  101. package/dist/substrate/lifo/shell/lexer.d.ts.map +1 -1
  102. package/dist/substrate/lifo/shell/lexer.js +40 -0
  103. package/dist/vfs/seed-project.d.ts.map +1 -1
  104. package/dist/vfs/seed-project.js +8 -2
  105. package/dist/vfs/sqlite-vfs.d.ts +61 -1
  106. package/dist/vfs/sqlite-vfs.d.ts.map +1 -1
  107. package/dist/vfs/sqlite-vfs.js +199 -35
  108. package/dist/workspace/nimbus-workspace.d.ts.map +1 -1
  109. package/dist/workspace/nimbus-workspace.js +9 -2
  110. package/package.json +4 -2
  111. package/src/_shared/error-text.ts +21 -0
  112. package/src/_shared/exports-resolver.ts +24 -4
  113. package/src/_shared/retry.ts +4 -2
  114. package/src/_shared/tarball-stream.ts +263 -0
  115. package/src/_shared/tarball.ts +46 -0
  116. package/src/_shared/w7-frame.ts +2 -1
  117. package/src/constants.ts +30 -16
  118. package/src/observability/oom-classify.ts +7 -0
  119. package/src/observability/oom-discriminator.ts +1 -1
  120. package/src/runtime/clang-runner.ts +924 -0
  121. package/src/runtime/esbuild-service.ts +16 -11
  122. package/src/runtime/facet-host.ts +12 -0
  123. package/src/runtime/installed-runtimes.ts +4 -3
  124. package/src/runtime/local-facet-host.ts +28 -8
  125. package/src/runtime/long-running-handle.ts +3 -3
  126. package/src/runtime/os-contracts.ts +7 -5
  127. package/src/runtime/port-registry.ts +97 -9
  128. package/src/runtime/process-logs.ts +12 -3
  129. package/src/runtime/project-detect.ts +7 -1
  130. package/src/runtime/require-resolver.ts +7 -7
  131. package/src/runtime/ruby-gems.ts +682 -0
  132. package/src/runtime/ruby-runner.ts +1484 -0
  133. package/src/runtime/runtime-registry.ts +9 -7
  134. package/src/runtime/session-process-supervisor.ts +27 -0
  135. package/src/runtime/sqlite-runtime-fs-bridge.ts +9 -6
  136. package/src/runtime/virtual-socket-kernel.generated.ts +2 -2
  137. package/src/runtime/virtual-socket-kernel.ts +10 -5
  138. package/src/runtime/wasm-runner.ts +55 -29
  139. package/src/shell/features.ts +5 -4
  140. package/src/shell/unix-commands.ts +273 -128
  141. package/src/substrate/lifo/commands/net/ip.ts +15 -15
  142. package/src/substrate/lifo/commands/system/ps.ts +2 -1
  143. package/src/substrate/lifo/kernel/ServiceManager.ts +0 -2
  144. package/src/substrate/lifo/kernel/network/NetworkStack.ts +24 -17
  145. package/src/substrate/lifo/kernel/network/tunnel/WebSocketTunnel.ts +37 -12
  146. package/src/substrate/lifo/kernel/vfs/VFS.ts +34 -0
  147. package/src/substrate/lifo/node-compat/esbuild.ts +16 -8
  148. package/src/substrate/lifo/node-compat/index.ts +3 -2
  149. package/src/substrate/lifo/node-compat/loose-equality.ts +81 -0
  150. package/src/substrate/lifo/node-compat/process.ts +5 -2
  151. package/src/substrate/lifo/shell/Shell.ts +92 -70
  152. package/src/substrate/lifo/shell/lexer.ts +38 -0
  153. package/src/vfs/seed-project.ts +10 -3
  154. package/src/vfs/sqlite-vfs.ts +209 -36
  155. package/src/workspace/nimbus-workspace.ts +10 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ashish Kumar Singh and Nimbus contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # @nimbus-sh/core
2
+
3
+ > Part of [Nimbus](https://github.com/AshishKumar4/Nimbus), my hobby/research
4
+ > cloud OS. This README is edited and maintained with Claude (AI) and
5
+ > presented as-is.
6
+
7
+ The backend-agnostic half of Nimbus: a durable POSIX-like filesystem, a shell
8
+ with 60+ Unix commands, and the WASI runtime layer — with no Cloudflare
9
+ dependency. You hand it a SQLite and get back `.fs` and `.exec`. On
10
+ Cloudflare that SQLite is `ctx.storage.sql` inside your Durable Object; in bun
11
+ or node it is `bun:sqlite` or `node:sqlite`.
12
+
13
+ I extracted this package because I kept wanting Nimbus *inside* other
14
+ projects — a Durable Object that already does something else but needs a real
15
+ workspace, or a local script that needs the same filesystem semantics the
16
+ hosted product has. The whole of it runs on two narrow ports (`SqlDatabase`
17
+ and `SqlTransactions`), so the same code serves both hosts.
18
+
19
+ ## Quick start
20
+
21
+ ```ts
22
+ import { Database } from 'bun:sqlite';
23
+ import { NimbusWorkspace } from '@nimbus-sh/core/workspace';
24
+
25
+ const db = new Database('workspace.sqlite');
26
+ const sql = {
27
+ exec(q, ...p) {
28
+ const st = db.query(q);
29
+ if (st.columnNames.length === 0) { db.run(q, ...p); return []; }
30
+ return st.all(...p);
31
+ },
32
+ };
33
+ const transactions = { storage: { transactionSync: (cb) => db.transaction(cb)() } };
34
+
35
+ const ws = await NimbusWorkspace.create({ sql, transactions, generation: 1 });
36
+
37
+ await ws.fs.writeFile('/home/user/hello.txt', 'hi\n');
38
+ const out = await ws.exec('cat /home/user/hello.txt | wc -c'); // { stdout: '3\n', exitCode: 0 }
39
+ ```
40
+
41
+ Inside a Cloudflare Durable Object, complete:
42
+
43
+ ```ts
44
+ import { DurableObject } from 'cloudflare:workers';
45
+ import { NimbusWorkspace } from '@nimbus-sh/core/workspace';
46
+
47
+ export class Workspace extends DurableObject {
48
+ private ws?: Promise<NimbusWorkspace>;
49
+
50
+ private workspace(): Promise<NimbusWorkspace> {
51
+ this.ws ??= (async () => {
52
+ // Bump a persisted counter once per instance. Never a constant and
53
+ // never Date.now(): pids derive from the generation, so a repeated
54
+ // one hands a dead process live write authority, and the platform
55
+ // re-instantiates this class far more often than it looks like it
56
+ // does (cold starts, hibernation wakes, resets). Use the bumped
57
+ // value only after the put resolves.
58
+ const generation = ((await this.ctx.storage.get<number>('generation')) ?? 0) + 1;
59
+ await this.ctx.storage.put('generation', generation);
60
+ return NimbusWorkspace.create({
61
+ sql: this.ctx.storage.sql,
62
+ transactions: this.ctx,
63
+ generation,
64
+ });
65
+ })();
66
+ return this.ws;
67
+ }
68
+
69
+ async exec(command: string) {
70
+ return (await this.workspace()).exec(command);
71
+ }
72
+ }
73
+ ```
74
+
75
+ Files written through `.fs` are owned by the session user (uid 1000), not
76
+ root, and the shell enforces the same permission model either way: a
77
+ root-owned `/etc/passwd` refuses a write from `.fs`, and `id` resolves names
78
+ through it.
79
+
80
+ ## Real runtimes, off Cloudflare
81
+
82
+ The wasm runtimes are separate npm packages so nobody downloads a Python
83
+ interpreter to get a filesystem. Install the ones you want and pass them in:
84
+
85
+ ```bash
86
+ npm install @nimbus-sh/runtime-bash @nimbus-sh/runtime-cpython
87
+ ```
88
+
89
+ ```ts
90
+ import bash from '@nimbus-sh/runtime-bash';
91
+ import cpython from '@nimbus-sh/runtime-cpython';
92
+ import { localFacetHost } from '@nimbus-sh/core';
93
+
94
+ const ws = await NimbusWorkspace.create({
95
+ sql, transactions, generation: 1,
96
+ facets: localFacetHost(),
97
+ runtimes: [bash, cpython],
98
+ });
99
+
100
+ await ws.exec('bash -c "echo $((6*7))"'); // 42 — GNU bash 5.2, real BusyBox children
101
+ await ws.exec(`python -c "import sqlite3; print('live')"`); // CPython 3.13, real stdlib
102
+ ```
103
+
104
+ `@nimbus-sh/runtime-ruby` (Ruby 3.3) and `@nimbus-sh/runtime-clang` (clang →
105
+ `wasm32-wasi`, compile and run C in the workspace) work the same way. Every
106
+ package carries the same manifest and the same sha256-verified blobs the
107
+ hosted product serves from R2 — one publisher, two transports.
108
+
109
+ Without `facets` and `runtimes` you still get the full shell and coreutils;
110
+ the wasm runtimes are a dependency you add, not a mode you enable. One caveat:
111
+ `localFacetHost()` covers bun and node only — on workerd the CSP forbids
112
+ request-time `WebAssembly.instantiate`, so wasm has to ride the Worker Loader
113
+ module map, which is the machinery in `@nimbus-sh/worker` and
114
+ `@nimbus-sh/fabric`; the shell, coreutils, and filesystem need none of it.
115
+
116
+ ## Sharing a database with your own app
117
+
118
+ The workspace is designed to be a tenant in a database you own, not the owner
119
+ of it:
120
+
121
+ - It creates and touches only its own tables (`inodes`, `file_chunks`,
122
+ `content_lifecycle`, `vfs_*`).
123
+ - `destroy()` drops exactly those tables. It never calls `deleteAll()`.
124
+ - `transactionSync` must be a real transaction. An implementation that only
125
+ calls the callback turns every atomic write into a torn one.
126
+ - `generation` must never repeat across restarts of your host — pids derive
127
+ from it, and a repeated generation would hand a dead process live write
128
+ authority.
129
+
130
+ ## What needs the Worker package instead
131
+
132
+ Resident processes (long-running servers, attached TUIs), the session
133
+ protocol, port routing to the public internet, and the hosted terminal all
134
+ live in [`@nimbus-sh/worker`](https://www.npmjs.com/package/@nimbus-sh/worker),
135
+ which composes on this package. If you want the full hosted product shape,
136
+ start from `npx create-nimbus-app`.
137
+
138
+ ## License
139
+
140
+ MIT.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * error-text.ts — the text a caught value carries.
3
+ *
4
+ * A `catch` binding is `unknown`: the throw site may have thrown an Error, a
5
+ * string, or a plain object with a `message`, and the shell and runtime paths
6
+ * report all three the same way. This is that report, in one place, so a
7
+ * command's diagnostics do not depend on which of those a facet threw.
8
+ */
9
+ /**
10
+ * The message a thrown value names, or the value itself when it names none.
11
+ * Empty and other falsy messages fall through to the value, so an
12
+ * `new Error('')` still reports as `Error` rather than as nothing.
13
+ */
14
+ export declare function errorText(error: unknown): string;
15
+ //# sourceMappingURL=error-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-text.d.ts","sourceRoot":"","sources":["../../src/_shared/error-text.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMhD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * error-text.ts — the text a caught value carries.
3
+ *
4
+ * A `catch` binding is `unknown`: the throw site may have thrown an Error, a
5
+ * string, or a plain object with a `message`, and the shell and runtime paths
6
+ * report all three the same way. This is that report, in one place, so a
7
+ * command's diagnostics do not depend on which of those a facet threw.
8
+ */
9
+ /**
10
+ * The message a thrown value names, or the value itself when it names none.
11
+ * Empty and other falsy messages fall through to the value, so an
12
+ * `new Error('')` still reports as `Error` rather than as nothing.
13
+ */
14
+ export function errorText(error) {
15
+ if (typeof error === 'object' && error !== null && 'message' in error) {
16
+ const { message } = error;
17
+ if (message)
18
+ return String(message);
19
+ }
20
+ return String(error);
21
+ }
@@ -7,7 +7,7 @@
7
7
  * 1. Install-time supervisor (TS) — `src/npm-resolver.ts` re-exports the
8
8
  * typed functions for tree resolution.
9
9
  *
10
- * 2. NimbusLoaderPool isolates (JS string) — `src/loaders/pre-bundle-preamble.ts`
10
+ * 2. LoaderPool isolates (JS string) — `src/loaders/pre-bundle-preamble.ts`
11
11
  * embeds `getExportsResolverJS()` as part of the pool preamble so the
12
12
  * pre-bundle facet uses identical resolution semantics to the supervisor.
13
13
  *
@@ -34,6 +34,22 @@
34
34
  export declare const DEFAULT_ESM_CONDITIONS: string[];
35
35
  /** Default conditions for CJS runtime resolution (user-shell node). */
36
36
  export declare const DEFAULT_CJS_CONDITIONS: string[];
37
+ /**
38
+ * A `package.json#exports` / `#imports` value: a target path, an ordered list
39
+ * of fallbacks to try in turn, or a map keyed by subpath (`"./client"`) or by
40
+ * condition (`"import"`) whose values are the same shape again. `null` is the
41
+ * spec's "this subpath is not exported" marker, and blocks fallback.
42
+ */
43
+ export type ExportsField = string | null | ExportsField[] | {
44
+ [key: string]: ExportsField;
45
+ };
46
+ /** The package.json fields entry-point resolution reads. */
47
+ export interface ResolvablePackageJson {
48
+ exports?: ExportsField;
49
+ imports?: ExportsField;
50
+ main?: string;
51
+ module?: string;
52
+ }
37
53
  /**
38
54
  * Resolve `package.json#exports` (or `#imports`) per Node spec.
39
55
  *
@@ -42,18 +58,14 @@ export declare const DEFAULT_CJS_CONDITIONS: string[];
42
58
  * @param conditions Active conditions, in priority order
43
59
  * @returns Relative path target string, or null if not found / forbidden
44
60
  */
45
- export declare function resolveExports(exportsField: any, subpath?: string, conditions?: string[]): string | null;
61
+ export declare function resolveExports(exportsField: ExportsField | undefined, subpath?: string, conditions?: string[]): string | null;
46
62
  /**
47
63
  * Resolve a package's entry-point file relative to its directory.
48
64
  * Priority: exports → module → main → null.
49
65
  * For non-root subpaths without an `exports` field, returns the subpath
50
66
  * itself (caller probes filesystem with extension-list).
51
67
  */
52
- export declare function resolvePackageEntry(pkg: {
53
- exports?: any;
54
- module?: string;
55
- main?: string;
56
- }, subpath?: string, conditions?: string[]): string | null;
68
+ export declare function resolvePackageEntry(pkg: ResolvablePackageJson, subpath?: string, conditions?: string[]): string | null;
57
69
  /**
58
70
  * Returns the resolver source as plain JavaScript (no TypeScript syntax),
59
71
  * suitable for embedding into a generated worker preamble or shim string.
@@ -1 +1 @@
1
- {"version":3,"file":"exports-resolver.d.ts","sourceRoot":"","sources":["../../src/_shared/exports-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,6DAA6D;AAC7D,eAAO,MAAM,sBAAsB,UAA6C,CAAC;AAEjF,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,UAAiC,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,GAAG,EACjB,OAAO,GAAE,MAAY,EACrB,UAAU,GAAE,MAAM,EAA2B,GAC5C,MAAM,GAAG,IAAI,CAkEf;AAwCD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACtD,OAAO,GAAE,MAAY,EACrB,UAAU,GAAE,MAAM,EAA2B,GAC5C,MAAM,GAAG,IAAI,CAsBf;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAkG7C"}
1
+ {"version":3,"file":"exports-resolver.d.ts","sourceRoot":"","sources":["../../src/_shared/exports-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,6DAA6D;AAC7D,eAAO,MAAM,sBAAsB,UAA6C,CAAC;AAEjF,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,UAAiC,CAAC;AAErE;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,IAAI,GACJ,YAAY,EAAE,GACd;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAEpC,4DAA4D;AAC5D,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,YAAY,GAAG,SAAS,EACtC,OAAO,GAAE,MAAY,EACrB,UAAU,GAAE,MAAM,EAA2B,GAC5C,MAAM,GAAG,IAAI,CAkEf;AAwCD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,qBAAqB,EAC1B,OAAO,GAAE,MAAY,EACrB,UAAU,GAAE,MAAM,EAA2B,GAC5C,MAAM,GAAG,IAAI,CAsBf;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAkG7C"}
@@ -7,7 +7,7 @@
7
7
  * 1. Install-time supervisor (TS) — `src/npm-resolver.ts` re-exports the
8
8
  * typed functions for tree resolution.
9
9
  *
10
- * 2. NimbusLoaderPool isolates (JS string) — `src/loaders/pre-bundle-preamble.ts`
10
+ * 2. LoaderPool isolates (JS string) — `src/loaders/pre-bundle-preamble.ts`
11
11
  * embeds `getExportsResolverJS()` as part of the pool preamble so the
12
12
  * pre-bundle facet uses identical resolution semantics to the supervisor.
13
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/_shared/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,gFAAgF;AAChF,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC,oEAAoE;AACpE,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAAsB,CAAC;AAE/D,4DAA4D;AAC5D,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOzD;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEnF,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,EAClB,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAqFnB"}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/_shared/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,gFAAgF;AAChF,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC,oEAAoE;AACpE,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAAsB,CAAC;AAE/D,4DAA4D;AAC5D,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOzD;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEnF,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,EAClB,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAsFnB"}
@@ -23,6 +23,7 @@
23
23
  * equivalent retry loops inside their isolated function bodies.
24
24
  */
25
25
  import { disposeRpcResource } from './rpc-dispose.js';
26
+ import { errorText } from './error-text.js';
26
27
  /** Default retry count AFTER the first attempt (3 = up to 4 total attempts). */
27
28
  export const DEFAULT_RETRIES = 3;
28
29
  /** Base backoff delays in ms. Index = retry attempt (0-indexed). */
@@ -142,7 +143,8 @@ export async function retryableFetch(url, init, opts) {
142
143
  throw e;
143
144
  }
144
145
  const delayMs = jittered(BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)]);
145
- const reason = e?.name === 'AbortError' ? 'timeout' : (e?.message || String(e));
146
+ const isAbort = typeof e === 'object' && e !== null && 'name' in e && e.name === 'AbortError';
147
+ const reason = isAbort ? 'timeout' : errorText(e);
146
148
  opts?.onRetry?.(attempt + 1, totalRetries, delayMs, reason);
147
149
  await new Promise((r) => setTimeout(r, delayMs));
148
150
  }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * tarball-stream.ts — pure streaming tar primitives.
3
+ *
4
+ * A leaf with no imports at all, deliberately: `bundle-facet-workers.mjs`
5
+ * esbuilds this file into a string constant the loader pool injects into
6
+ * dynamic workers, and a facet isolate resolves no specifier. Anything this
7
+ * file imported would have to travel with it.
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tarball-stream.d.ts","sourceRoot":"","sources":["../../src/_shared/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"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * tarball-stream.ts — pure streaming tar primitives.
3
+ *
4
+ * A leaf with no imports at all, deliberately: `bundle-facet-workers.mjs`
5
+ * esbuilds this file into a string constant the loader pool injects into
6
+ * dynamic workers, and a facet isolate resolves no specifier. Anything this
7
+ * file imported would have to travel with it.
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 const MAX_FILE_BYTES = 20_000_000;
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 function canonicalTarName(name) {
36
+ const out = [];
37
+ for (const seg of name.split('/')) {
38
+ if (seg === '..') {
39
+ if (out.length === 0)
40
+ return '';
41
+ out.pop();
42
+ }
43
+ else if (seg !== '' && seg !== '.') {
44
+ out.push(seg);
45
+ }
46
+ }
47
+ return out.join('/');
48
+ }
49
+ export function parseTarHeader(block) {
50
+ if (block[0] === 0)
51
+ return null;
52
+ let name = '';
53
+ for (let i = 0; i < 100 && block[i] !== 0; i++) {
54
+ name += String.fromCharCode(block[i]);
55
+ }
56
+ let prefix = '';
57
+ for (let i = 345; i < 500 && block[i] !== 0; i++) {
58
+ prefix += String.fromCharCode(block[i]);
59
+ }
60
+ if (prefix)
61
+ name = prefix + '/' + name;
62
+ // Strip the npm `package/` convention.
63
+ name = name.replace(/^package\//, '');
64
+ // Canonicalize the entry-relative path. npm tarballs legitimately carry
65
+ // entries like "./dist/index.js" (agent-base, http-proxy-agent,
66
+ // protobufjs, ...); left as-is the "./" survives into the VFS write path
67
+ // and the w7-frame writer rejects the noncanonical path, failing the
68
+ // whole shared install wave and dropping shard-mates' completion markers.
69
+ // Collapsing here (the one place entry names are assembled) keeps every
70
+ // downstream join canonical. An entry that escapes its package root via
71
+ // ".." is dropped to '' → skipped as a no-name entry.
72
+ name = canonicalTarName(name);
73
+ let sizeStr = '';
74
+ for (let i = 124; i < 136 && block[i] !== 0; i++) {
75
+ sizeStr += String.fromCharCode(block[i]);
76
+ }
77
+ const size = parseInt(sizeStr.trim(), 8) || 0;
78
+ const typeFlag = block[156];
79
+ return { name, size, typeFlag };
80
+ }
81
+ /**
82
+ * Wrap a `ReadableStream<Uint8Array>` as an async iterable. Workerd and
83
+ * Node both support `Symbol.asyncIterator` on ReadableStream, but we
84
+ * spell the reader loop out so we don't depend on ambient lib typings.
85
+ */
86
+ export async function* readableStreamToAsyncIterable(rs) {
87
+ const reader = rs.getReader();
88
+ try {
89
+ while (true) {
90
+ const { value, done } = await reader.read();
91
+ if (done)
92
+ return;
93
+ if (value && value.length > 0)
94
+ yield value;
95
+ }
96
+ }
97
+ finally {
98
+ try {
99
+ reader.releaseLock();
100
+ }
101
+ catch { /* ignore */ }
102
+ }
103
+ }
104
+ /**
105
+ * Streaming tar extractor.
106
+ *
107
+ * Consumes an async iterable of Uint8Array chunks (the decompressed tar
108
+ * byte stream) and yields one `{ name, data }` entry per regular file,
109
+ * as each file completes.
110
+ *
111
+ * Memory invariant: holds at most one pending file's bytes (≤ MAX_FILE_BYTES)
112
+ * plus a small carry buffer for the tar header being assembled.
113
+ *
114
+ * Skips: symlinks, directories, hardlinks, long-name extensions (PaxHeader),
115
+ * and any file whose declared size exceeds MAX_FILE_BYTES.
116
+ *
117
+ * If `onSkip` is provided, it is invoked for each skipped entry with the
118
+ * name, declared size, and reason code. Callers that need to surface
119
+ * dropped-file warnings to users should pass one; legacy callers that
120
+ * omit the arg still behave exactly as before (silent skip).
121
+ */
122
+ export async function* streamTarEntries(source, onSkip) {
123
+ let carry = new Uint8Array(0);
124
+ let state = { kind: 'header' };
125
+ function concat(a, b) {
126
+ if (a.length === 0)
127
+ return b;
128
+ if (b.length === 0)
129
+ return a;
130
+ const out = new Uint8Array(a.length + b.length);
131
+ out.set(a, 0);
132
+ out.set(b, a.length);
133
+ return out;
134
+ }
135
+ for await (const chunkRaw of source) {
136
+ let buf = concat(carry, chunkRaw);
137
+ let cursor = 0;
138
+ while (true) {
139
+ if (state.kind === 'header') {
140
+ if (buf.length - cursor < 512)
141
+ break;
142
+ const header = buf.subarray(cursor, cursor + 512);
143
+ const parsed = parseTarHeader(header);
144
+ cursor += 512;
145
+ if (!parsed)
146
+ return; // end-of-archive
147
+ const { name, size, typeFlag } = parsed;
148
+ const pad = size === 0 ? 0 : (512 - (size % 512)) % 512;
149
+ const isRegularFile = (typeFlag === 48 /* '0' */ || typeFlag === 0);
150
+ if (size === 0) {
151
+ if (isRegularFile && name) {
152
+ yield { name, data: new Uint8Array(0) };
153
+ }
154
+ state = { kind: 'header' };
155
+ continue;
156
+ }
157
+ if (!isRegularFile || !name || size > MAX_FILE_BYTES) {
158
+ if (onSkip) {
159
+ // Classify before entering the skip state so the reason is
160
+ // exact. Precedence matches the condition order above:
161
+ // non-regular first (directories/symlinks/PaxHeaders are
162
+ // skipped regardless of size), then no-name, then too-large.
163
+ const reason = !isRegularFile
164
+ ? 'non-regular'
165
+ : !name
166
+ ? 'no-name'
167
+ : 'too-large';
168
+ try {
169
+ onSkip(name, size, reason);
170
+ }
171
+ catch { /* best-effort */ }
172
+ }
173
+ state = { kind: 'skip', remaining: size + pad };
174
+ continue;
175
+ }
176
+ state = {
177
+ kind: 'file',
178
+ name,
179
+ remaining: size,
180
+ fileBuf: new Uint8Array(size),
181
+ fileOffset: 0,
182
+ pad,
183
+ skip: false,
184
+ };
185
+ continue;
186
+ }
187
+ if (state.kind === 'file') {
188
+ const avail = buf.length - cursor;
189
+ if (avail === 0)
190
+ break;
191
+ if (state.remaining > 0) {
192
+ const take = Math.min(state.remaining, avail);
193
+ state.fileBuf.set(buf.subarray(cursor, cursor + take), state.fileOffset);
194
+ state.fileOffset += take;
195
+ state.remaining -= take;
196
+ cursor += take;
197
+ if (state.remaining > 0)
198
+ break;
199
+ }
200
+ if (state.pad > 0) {
201
+ const avail2 = buf.length - cursor;
202
+ if (avail2 === 0)
203
+ break;
204
+ const take = Math.min(state.pad, avail2);
205
+ state.pad -= take;
206
+ cursor += take;
207
+ if (state.pad > 0)
208
+ break;
209
+ }
210
+ yield { name: state.name, data: state.fileBuf };
211
+ state = { kind: 'header' };
212
+ continue;
213
+ }
214
+ // state.kind === 'skip'
215
+ const avail = buf.length - cursor;
216
+ if (avail === 0)
217
+ break;
218
+ const take = Math.min(state.remaining, avail);
219
+ cursor += take;
220
+ state.remaining -= take;
221
+ if (state.remaining > 0)
222
+ break;
223
+ state = { kind: 'header' };
224
+ }
225
+ if (cursor >= buf.length) {
226
+ carry = new Uint8Array(0);
227
+ }
228
+ else if (cursor === 0) {
229
+ carry = buf;
230
+ }
231
+ else {
232
+ carry = buf.slice(cursor);
233
+ }
234
+ }
235
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * tarball.ts — a whole tarball, in memory, as a path→bytes map.
3
+ *
4
+ * The streaming primitives it walks with (`parseTarHeader`, `streamTarEntries`,
5
+ * `readableStreamToAsyncIterable`) live in `./tarball-stream.ts` — a
6
+ * dependency-free leaf, because `bundle-facet-workers.mjs` esbuilds that file
7
+ * into a string the loader pool injects into dynamic workers, where an import
8
+ * would not resolve.
9
+ *
10
+ * This half is for a caller that already holds the bytes: `gem install`, which
11
+ * fetches a `.gem` (a tar holding a gzipped tar) and needs both layers open at
12
+ * once. An installer streaming a tarball it is still downloading should drive
13
+ * `streamTarEntries` itself and never hold the whole thing.
14
+ */
15
+ /** Extract every regular file. Gzipped input is decompressed first. */
16
+ export declare function extractTarball(tarball: ArrayBuffer): Promise<Map<string, Uint8Array>>;
17
+ //# sourceMappingURL=tarball.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tarball.d.ts","sourceRoot":"","sources":["../../src/_shared/tarball.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,uEAAuE;AACvE,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAsBlC"}