@nimbus-sh/worker 0.6.0 → 0.7.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 (133) hide show
  1. package/README.md +2 -2
  2. package/dist/cirrus-npm-cjs.generated.d.ts +1 -1
  3. package/dist/cirrus-npm-cjs.generated.js +1 -1
  4. package/dist/facets/cirrus-real.d.ts.map +1 -1
  5. package/dist/facets/cirrus-real.js +6 -5
  6. package/dist/facets/compose.d.ts +148 -0
  7. package/dist/facets/compose.d.ts.map +1 -0
  8. package/dist/facets/compose.js +146 -0
  9. package/dist/facets/durable-images.d.ts +9 -5
  10. package/dist/facets/durable-images.d.ts.map +1 -1
  11. package/dist/facets/durable-images.js +17 -7
  12. package/dist/facets/esbuild-bundle-pool.d.ts +49 -0
  13. package/dist/facets/esbuild-bundle-pool.d.ts.map +1 -0
  14. package/dist/facets/esbuild-bundle-pool.js +122 -0
  15. package/dist/facets/exec-telemetry.d.ts +8 -0
  16. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  17. package/dist/facets/manager.d.ts +240 -109
  18. package/dist/facets/manager.d.ts.map +1 -1
  19. package/dist/facets/manager.js +661 -337
  20. package/dist/facets/process.d.ts +20 -16
  21. package/dist/facets/process.d.ts.map +1 -1
  22. package/dist/facets/process.js +59 -28
  23. package/dist/facets/real-vite-fs-shim.js +2 -2
  24. package/dist/facets/vite-dev-server.d.ts +25 -47
  25. package/dist/facets/vite-dev-server.d.ts.map +1 -1
  26. package/dist/facets/vite-dev-server.js +185 -219
  27. package/dist/facets/wasm-image-digest.d.ts +25 -0
  28. package/dist/facets/wasm-image-digest.d.ts.map +1 -0
  29. package/dist/facets/wasm-image-digest.js +25 -0
  30. package/dist/facets/wasm-swap-registry.d.ts +51 -92
  31. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  32. package/dist/facets/wasm-swap-registry.js +68 -227
  33. package/dist/git/network-facet.d.ts.map +1 -1
  34. package/dist/git/network-facet.js +6 -5
  35. package/dist/loaders/child-process/spawn-pool.d.ts +3 -2
  36. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  37. package/dist/loaders/child-process/spawn-pool.js +3 -2
  38. package/dist/loaders/generated-workers.d.ts +2 -2
  39. package/dist/loaders/generated-workers.d.ts.map +1 -1
  40. package/dist/loaders/generated-workers.js +3 -3
  41. package/dist/loaders/npm-resolve-preamble.d.ts +3 -6
  42. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  43. package/dist/loaders/npm-resolve-preamble.js +34 -108
  44. package/dist/node-shims-artifact.generated.js +3 -3
  45. package/dist/npm/install-batch-facet.d.ts +3 -2
  46. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  47. package/dist/npm/install-batch-facet.js +45 -15
  48. package/dist/npm/installer.d.ts +22 -17
  49. package/dist/npm/installer.d.ts.map +1 -1
  50. package/dist/npm/installer.js +209 -193
  51. package/dist/npm/pre-bundle-facet.d.ts +1 -1
  52. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  53. package/dist/npm/pre-bundle-facet.js +1 -1
  54. package/dist/npm/resolve-facet.d.ts +6 -0
  55. package/dist/npm/resolve-facet.d.ts.map +1 -1
  56. package/dist/npm/resolve-one-facet.d.ts +21 -20
  57. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  58. package/dist/npm/resolve-one-facet.js +85 -84
  59. package/dist/npm/semver.d.ts +59 -0
  60. package/dist/npm/semver.d.ts.map +1 -0
  61. package/dist/npm/semver.js +226 -0
  62. package/dist/router/remote-api.js +31 -1
  63. package/dist/runtime/html-entrypoint.d.ts +7 -0
  64. package/dist/runtime/html-entrypoint.d.ts.map +1 -1
  65. package/dist/runtime/html-entrypoint.js +18 -2
  66. package/dist/runtime/node-runner.d.ts +3 -0
  67. package/dist/runtime/node-runner.d.ts.map +1 -1
  68. package/dist/runtime/node-runner.js +7 -0
  69. package/dist/runtime/node-shims.d.ts.map +1 -1
  70. package/dist/runtime/node-shims.js +305 -29
  71. package/dist/runtime/opencode-facet-runner.js +2 -2
  72. package/dist/session/helpers.d.ts +38 -0
  73. package/dist/session/helpers.d.ts.map +1 -1
  74. package/dist/session/helpers.js +76 -0
  75. package/dist/session/init-phases.d.ts +1 -1
  76. package/dist/session/init-phases.d.ts.map +1 -1
  77. package/dist/session/init-phases.js +2 -12
  78. package/dist/session/init.d.ts +15 -1
  79. package/dist/session/init.d.ts.map +1 -1
  80. package/dist/session/init.js +82 -603
  81. package/dist/session/nimbus-session.d.ts +56 -22
  82. package/dist/session/nimbus-session.d.ts.map +1 -1
  83. package/dist/session/nimbus-session.js +130 -101
  84. package/dist/session/npm-install-port.d.ts +16 -0
  85. package/dist/session/npm-install-port.d.ts.map +1 -0
  86. package/dist/session/npm-install-port.js +37 -0
  87. package/dist/session/port-capability.d.ts +44 -0
  88. package/dist/session/port-capability.d.ts.map +1 -1
  89. package/dist/session/port-capability.js +110 -0
  90. package/dist/session/programmatic.d.ts +31 -5
  91. package/dist/session/programmatic.d.ts.map +1 -1
  92. package/dist/session/programmatic.js +94 -68
  93. package/dist/session/routes.d.ts +30 -17
  94. package/dist/session/routes.d.ts.map +1 -1
  95. package/dist/session/routes.js +42 -131
  96. package/dist/session/rpc.d.ts +15 -15
  97. package/dist/session/rpc.d.ts.map +1 -1
  98. package/dist/session/rpc.js +97 -47
  99. package/dist/session/serving-port.d.ts +27 -0
  100. package/dist/session/serving-port.d.ts.map +1 -0
  101. package/dist/session/serving-port.js +27 -0
  102. package/dist/session/start-real-vite.d.ts +12 -0
  103. package/dist/session/start-real-vite.d.ts.map +1 -1
  104. package/dist/session/start-real-vite.js +4 -4
  105. package/dist/session/supervisor-op.d.ts +2 -2
  106. package/dist/session/supervisor-op.d.ts.map +1 -1
  107. package/dist/session/supervisor-op.js +13 -7
  108. package/dist/session/supervisor-rpc.d.ts +7 -7
  109. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  110. package/dist/session/supervisor-rpc.js +4 -0
  111. package/dist/session/vite-command.d.ts +18 -0
  112. package/dist/session/vite-command.d.ts.map +1 -0
  113. package/dist/session/vite-command.js +609 -0
  114. package/dist/session/ws.d.ts +61 -0
  115. package/dist/session/ws.d.ts.map +1 -1
  116. package/dist/session/ws.js +122 -12
  117. package/dist/shell/npm-bin-entrypoints.d.ts +0 -35
  118. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  119. package/dist/shell/npm-bin-entrypoints.js +12 -85
  120. package/package.json +24 -4
  121. package/public/_assets/runtime/{node-shims-9e1380d9ee430fcc.js → node-shims-8f8c64edd2a1f0f5.js} +305 -29
  122. package/public/index.html +1 -1
  123. package/scripts/bundle-facet-workers.mjs +1 -1
  124. package/scripts/bundle-npm-cjs.mjs +2 -2
  125. package/dist/facets/on-demand-bundle-gate.d.ts +0 -65
  126. package/dist/facets/on-demand-bundle-gate.d.ts.map +0 -1
  127. package/dist/facets/on-demand-bundle-gate.js +0 -125
  128. package/dist/npm/install-args.d.ts +0 -21
  129. package/dist/npm/install-args.d.ts.map +0 -1
  130. package/dist/npm/install-args.js +0 -70
  131. package/dist/npm/npm-log.d.ts +0 -31
  132. package/dist/npm/npm-log.d.ts.map +0 -1
  133. package/dist/npm/npm-log.js +0 -51
@@ -0,0 +1,226 @@
1
+ /**
2
+ * npm/semver.ts — the one semver implementation the npm resolver picks
3
+ * versions with.
4
+ *
5
+ * The resolver facet (npm/resolve-one-facet.ts) runs inside a dynamic worker
6
+ * whose only module scope is the preamble string in
7
+ * loaders/npm-resolve-preamble.ts. That preamble embeds THESE functions by
8
+ * `fn.toString()`, so the facet's version pick is this module's by
9
+ * construction — there is no second copy to drift, and
10
+ * tests/unit/npm-semver.mjs asserts the embedded functions answer exactly
11
+ * as the exported ones do.
12
+ *
13
+ * Every function here is self-contained on purpose: no closures over module
14
+ * constants, no imports, only calls to the other functions in this file by
15
+ * name. `toString()` reproduces exactly that, and nothing else.
16
+ *
17
+ * What is implemented is the subset of node-semver that npm dependency
18
+ * ranges use: exact versions, `^`, `~`, comparators, hyphen ranges, `||`,
19
+ * X-ranges (`1`, `1.2`, `1.x`, `*`), and — the part the previous helper
20
+ * lacked — prerelease identifiers. Ignoring them meant every `1.0.0-*`
21
+ * compared equal, so `json-server@1.0.0-beta.15` resolved to whichever
22
+ * `1.0.0-*` the packument listed first (`1.0.0-alpha.1`) and
23
+ * `^1.0.0-next.24` picked `1.0.0-next.0`. Measured against the live registry
24
+ * lists before this rewrite.
25
+ */
26
+ /** Parse `v1.2.3-beta.4+build` → `[1, 2, 3, ['beta', 4]]`; null for a non-version. */
27
+ export function parseSemver(v) {
28
+ const m = String(v).trim().replace(/^[v=]+/, '')
29
+ .match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
30
+ if (!m)
31
+ return null;
32
+ const prerelease = m[4] === undefined
33
+ ? []
34
+ : m[4].split('.').map((id) => (/^\d+$/.test(id) ? Number(id) : id));
35
+ return [Number(m[1]), Number(m[2]), Number(m[3]), prerelease];
36
+ }
37
+ /**
38
+ * Total order. A release sorts above every prerelease of the same triple;
39
+ * prerelease identifiers compare left to right, numeric before alphanumeric,
40
+ * numeric by value, alphanumeric lexically, and a longer list sorts above
41
+ * its prefix (semver.org §11).
42
+ */
43
+ export function compareSemver(a, b) {
44
+ if (a[0] !== b[0])
45
+ return a[0] - b[0];
46
+ if (a[1] !== b[1])
47
+ return a[1] - b[1];
48
+ if (a[2] !== b[2])
49
+ return a[2] - b[2];
50
+ const ap = a[3] ?? [];
51
+ const bp = b[3] ?? [];
52
+ if (ap.length === 0 && bp.length === 0)
53
+ return 0;
54
+ if (ap.length === 0)
55
+ return 1;
56
+ if (bp.length === 0)
57
+ return -1;
58
+ const n = Math.min(ap.length, bp.length);
59
+ for (let i = 0; i < n; i++) {
60
+ const x = ap[i];
61
+ const y = bp[i];
62
+ if (x === y)
63
+ continue;
64
+ if (typeof x === 'number' && typeof y === 'number')
65
+ return x - y;
66
+ if (typeof x === 'number')
67
+ return -1;
68
+ if (typeof y === 'number')
69
+ return 1;
70
+ return x < y ? -1 : 1;
71
+ }
72
+ return ap.length - bp.length;
73
+ }
74
+ /**
75
+ * One comparator set (the space-separated part of a range) as
76
+ * `>=lower <upper` bounds. Every range shape npm uses normalises to at
77
+ * most two bounds, so a set is a list of `[op, version]` pairs.
78
+ */
79
+ export function semverComparators(part) {
80
+ const comp = part.trim();
81
+ if (comp === '' || comp === '*' || comp === 'x' || comp === 'X' || comp === 'latest')
82
+ return [];
83
+ const m = comp.match(/^(\^|~>?|>=|<=|>|<|=)?\s*v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
84
+ if (!m)
85
+ return null;
86
+ const op = m[1] === '~>' ? '~' : (m[1] ?? '');
87
+ const wild = (s) => s === undefined || s === 'x' || s === 'X' || s === '*';
88
+ const majorWild = wild(m[2]);
89
+ const minorWild = wild(m[3]);
90
+ const patchWild = wild(m[4]);
91
+ const major = majorWild ? 0 : Number(m[2]);
92
+ const minor = minorWild ? 0 : Number(m[3]);
93
+ const patch = patchWild ? 0 : Number(m[4]);
94
+ const pre = m[5] === undefined || patchWild
95
+ ? []
96
+ : m[5].split('.').map((id) => (/^\d+$/.test(id) ? Number(id) : id));
97
+ const lower = [major, minor, patch, pre];
98
+ const ge = () => [['>=', lower]];
99
+ const upto = (u) => [['>=', lower], ['<', u]];
100
+ // X-ranges: `*`, `1`, `1.2`, `1.x`, `1.2.x` — an op in front is applied to
101
+ // the lowest version the X-range names (`>=1.2` is `>=1.2.0`, `<1.x` is `<1.0.0`).
102
+ if (majorWild)
103
+ return [];
104
+ if (minorWild) {
105
+ if (op === '' || op === '^' || op === '~' || op === '=')
106
+ return upto([major + 1, 0, 0, []]);
107
+ return op === '<=' ? [['<', [major + 1, 0, 0, []]]] : [[op, lower]];
108
+ }
109
+ if (patchWild) {
110
+ if (op === '' || op === '~' || op === '=')
111
+ return upto([major, minor + 1, 0, []]);
112
+ if (op === '^')
113
+ return upto(major === 0 ? [0, minor + 1, 0, []] : [major + 1, 0, 0, []]);
114
+ return op === '<=' ? [['<', [major, minor + 1, 0, []]]] : [[op, lower]];
115
+ }
116
+ switch (op) {
117
+ case '^':
118
+ if (major > 0)
119
+ return upto([major + 1, 0, 0, []]);
120
+ if (minor > 0)
121
+ return upto([0, minor + 1, 0, []]);
122
+ return upto([0, 0, patch + 1, []]);
123
+ case '~':
124
+ return upto([major, minor + 1, 0, []]);
125
+ case '':
126
+ case '=':
127
+ return [['=', lower]];
128
+ default:
129
+ return [[op, lower]];
130
+ }
131
+ }
132
+ /**
133
+ * node-semver's prerelease rule: a prerelease version satisfies a comparator
134
+ * set only when some comparator in that set names a prerelease of the same
135
+ * `major.minor.patch`. `^1.0.0-next.24` admits `1.0.0-next.29` and `1.0.0`,
136
+ * never `1.1.0-rc.1`; `^1.0.0` admits no prerelease at all.
137
+ */
138
+ export function satisfiesRange(version, range) {
139
+ const v = parseSemver(version);
140
+ if (!v)
141
+ return false;
142
+ const trimmed = String(range).trim();
143
+ if (trimmed === '' || trimmed === '*' || trimmed === 'x' || trimmed === 'latest')
144
+ return v[3].length === 0;
145
+ for (const orPart of trimmed.split(/\s*\|\|\s*/)) {
146
+ let comparators = [];
147
+ const hyphen = orPart.trim().match(/^(\S+)\s+-\s+(\S+)$/);
148
+ if (hyphen) {
149
+ const lo = semverComparators('>=' + hyphen[1]);
150
+ const hi = semverComparators('<=' + hyphen[2]);
151
+ comparators = lo && hi ? [...lo, ...hi] : null;
152
+ }
153
+ else {
154
+ for (const part of orPart.trim().split(/\s+/)) {
155
+ const c = semverComparators(part);
156
+ if (c === null) {
157
+ comparators = null;
158
+ break;
159
+ }
160
+ comparators.push(...c);
161
+ }
162
+ }
163
+ if (comparators === null)
164
+ continue;
165
+ let ok = true;
166
+ for (const [op, r] of comparators) {
167
+ const cmp = compareSemver(v, r);
168
+ if (op === '>=' ? cmp < 0 : op === '>' ? cmp <= 0 : op === '<=' ? cmp > 0 : op === '<' ? cmp >= 0 : cmp !== 0) {
169
+ ok = false;
170
+ break;
171
+ }
172
+ }
173
+ if (!ok)
174
+ continue;
175
+ if (v[3].length > 0) {
176
+ const admitted = comparators.some(([, r]) => r[3].length > 0 && r[0] === v[0] && r[1] === v[1] && r[2] === v[2]);
177
+ if (!admitted)
178
+ continue;
179
+ }
180
+ return true;
181
+ }
182
+ return false;
183
+ }
184
+ /**
185
+ * Whether `range` is semver-shaped at all — `''`, `*`, `latest`, tags,
186
+ * comparators, hyphen ranges, `||` groups. False for git:, github:,
187
+ * URL, file:, and other non-registry specifiers, where a version pin's
188
+ * presence is all a lockfile can answer.
189
+ */
190
+ export function isSemverRange(range) {
191
+ const trimmed = String(range).trim();
192
+ if (trimmed === '' || trimmed === '*' || trimmed === 'x' || trimmed === 'X' || trimmed === 'latest')
193
+ return true;
194
+ for (const orPart of trimmed.split(/\s*\|\|\s*/)) {
195
+ const hyphen = orPart.trim().match(/^(\S+)\s+-\s+(\S+)$/);
196
+ if (hyphen) {
197
+ const lo = semverComparators('>=' + hyphen[1]);
198
+ const hi = semverComparators('<=' + hyphen[2]);
199
+ if (lo === null || hi === null)
200
+ return false;
201
+ continue;
202
+ }
203
+ for (const part of orPart.trim().split(/\s+/)) {
204
+ if (semverComparators(part) === null)
205
+ return false;
206
+ }
207
+ }
208
+ return true;
209
+ }
210
+ /** The highest version satisfying `range`, or null; `latest`/`*` are the caller's dist-tag lookup. */
211
+ export function resolveVersion(versions, range) {
212
+ const trimmed = String(range ?? '').trim();
213
+ if (trimmed === '' || trimmed === '*' || trimmed === 'x' || trimmed === 'X' || trimmed === 'latest')
214
+ return null;
215
+ let best = null;
216
+ for (const v of versions) {
217
+ if (!satisfiesRange(v, trimmed))
218
+ continue;
219
+ const p = parseSemver(v);
220
+ if (!p)
221
+ continue;
222
+ if (best === null || compareSemver(p, best.p) > 0)
223
+ best = { v, p };
224
+ }
225
+ return best === null ? null : best.v;
226
+ }
@@ -163,30 +163,45 @@ async function dispatchRemoteRpc(ctx) {
163
163
  assertRuntimeForLanguage(ctx, language, options.install);
164
164
  return ctx.stub._rpcRunCode(stringArg(args[0], 'code'), options);
165
165
  }
166
+ // The file plane. Each op's trailing argument is the SDK's file options
167
+ // object; `fileOptions` reads it so a `cred` the client put on the wire
168
+ // is refused loudly rather than dropped — the session-user default is
169
+ // the only identity a remote token can act as.
166
170
  case 'readFile':
171
+ fileOptions(args[1]);
167
172
  return ctx.stub._rpcReadFile(stringArg(args[0], 'path'));
168
173
  case 'readFileBytes':
174
+ fileOptions(args[1]);
169
175
  return ctx.stub._rpcReadFileBytes(stringArg(args[0], 'path'));
170
176
  case 'writeFile':
177
+ fileOptions(args[2]);
171
178
  return ctx.stub._rpcWriteFile(stringArg(args[0], 'path'), fileContentArg(args[1]));
172
179
  case 'stat':
180
+ fileOptions(args[1]);
173
181
  return ctx.stub._rpcStat(stringArg(args[0], 'path'));
174
182
  case 'lstat':
183
+ fileOptions(args[1]);
175
184
  return ctx.stub._rpcLstat(stringArg(args[0], 'path'));
176
185
  case 'rename':
186
+ fileOptions(args[2]);
177
187
  return ctx.stub._rpcRename(stringArg(args[0], 'from'), stringArg(args[1], 'to'));
178
188
  case 'chmod':
189
+ fileOptions(args[2]);
179
190
  return ctx.stub._rpcChmod(stringArg(args[0], 'path'), numberArg(args[1], 'mode'));
180
191
  case 'readRange':
192
+ fileOptions(args[3]);
181
193
  return ctx.stub._rpcFsReadRange(stringArg(args[0], 'path'), numberArg(args[1], 'offset'), numberArg(args[2], 'length'));
182
194
  case 'readdir':
195
+ fileOptions(args[1]);
183
196
  return ctx.stub._rpcReaddir(stringArg(args[0], 'path'));
184
197
  case 'exists':
198
+ fileOptions(args[1]);
185
199
  return ctx.stub._rpcExists(stringArg(args[0], 'path'));
186
200
  case 'mkdir':
201
+ fileOptions(args[1]);
187
202
  return ctx.stub._rpcMkdir(stringArg(args[0], 'path'));
188
203
  case 'deleteFile':
189
- return ctx.stub._rpcDeleteFile(stringArg(args[0], 'path'), objectArg(args[1]));
204
+ return ctx.stub._rpcDeleteFile(stringArg(args[0], 'path'), fileOptions(args[1]));
190
205
  case 'installRuntime': {
191
206
  const spec = stringArg(args[0], 'spec');
192
207
  assertRuntimeAllowed(ctx, spec, 'onDemand');
@@ -301,6 +316,21 @@ function execOptions(ctx, value) {
301
316
  cwd: typeof options.cwd === 'string' ? options.cwd : ctx.root,
302
317
  };
303
318
  }
319
+ /**
320
+ * A file op's options object. The same boundary rule as `execOptions`: the
321
+ * remote token authenticates a SESSION, so a caller does not get to name the
322
+ * uid its file operation acts as. `files.as(cred)` puts `cred` on the wire
323
+ * explicitly so this refusal is the answer the caller gets — never a read
324
+ * that silently ran as somebody else. A colocated embedder holding the DO
325
+ * stub is trusted with `cred` the same way it is trusted with kernel writes.
326
+ */
327
+ function fileOptions(value) {
328
+ const options = value === undefined ? {} : objectArg(value);
329
+ if (options.cred !== undefined) {
330
+ throw apiError('cred is not accepted over the remote API', 'E_ARG_SHAPE', 400);
331
+ }
332
+ return options;
333
+ }
304
334
  function processLogOptions(value) {
305
335
  const options = objectArg(value);
306
336
  return {
@@ -3,5 +3,12 @@ export declare function rewriteViteBuildHtml(html: string, options: {
3
3
  jsFilename: string;
4
4
  cssFilename?: string;
5
5
  removeImportMap?: boolean;
6
+ /**
7
+ * Vite injects `<link rel="stylesheet">` for CSS bundled through the
8
+ * entry when index.html declares none (the create-vite template puts
9
+ * all CSS behind `import './index.css'`). Set true to get that
10
+ * behavior; when false, only an existing stylesheet link is rewritten.
11
+ */
12
+ injectCss?: boolean;
6
13
  }): Promise<string>;
7
14
  //# sourceMappingURL=html-entrypoint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-entrypoint.d.ts","sourceRoot":"","sources":["../../src/runtime/html-entrypoint.ts"],"names":[],"mappings":"AAEA,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAcxF;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GACA,OAAO,CAAC,MAAM,CAAC,CA8BjB"}
1
+ {"version":3,"file":"html-entrypoint.d.ts","sourceRoot":"","sources":["../../src/runtime/html-entrypoint.ts"],"names":[],"mappings":"AAEA,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAcxF;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GACA,OAAO,CAAC,MAAM,CAAC,CAkDjB"}
@@ -18,6 +18,7 @@ export async function findHtmlScriptEntrypoint(html) {
18
18
  export async function rewriteViteBuildHtml(html, options) {
19
19
  if (typeof HTMLRewriter !== 'function')
20
20
  return html;
21
+ let sawCssLink = false;
21
22
  const rewriter = new HTMLRewriter()
22
23
  .on('script', {
23
24
  element(element) {
@@ -34,16 +35,31 @@ export async function rewriteViteBuildHtml(html, options) {
34
35
  })
35
36
  .on('link[href]', {
36
37
  element(element) {
37
- if (!options.cssFilename)
38
- return;
39
38
  const href = element.getAttribute('href');
40
39
  if (!href || !isCssAsset(href))
41
40
  return;
41
+ sawCssLink = true;
42
+ if (!options.cssFilename)
43
+ return;
42
44
  element.setAttribute('rel', 'stylesheet');
43
45
  element.setAttribute('crossorigin', '');
44
46
  element.setAttribute('href', `/assets/${options.cssFilename}`);
45
47
  },
46
48
  });
49
+ if (options.injectCss && options.cssFilename) {
50
+ // element.onEndTag fires at </head> — after every `link[href]` child
51
+ // has been seen — so the stylesheet lands exactly when the document
52
+ // declares none, the same condition Vite uses for its emitted <link>.
53
+ rewriter.on('head', {
54
+ element(element) {
55
+ element.onEndTag((end) => {
56
+ if (!sawCssLink) {
57
+ end.before(`<link rel="stylesheet" crossorigin href="/assets/${options.cssFilename}">`, { html: true });
58
+ }
59
+ });
60
+ },
61
+ });
62
+ }
47
63
  return await rewriter.transform(new Response(html)).text();
48
64
  }
49
65
  function isScriptEntrypoint(src) {
@@ -82,6 +82,9 @@ export interface RunFreshOpts {
82
82
  forceLongRunning?: boolean;
83
83
  attachedTty?: boolean;
84
84
  bundleProfile?: FacetBundleProfile;
85
+ /** Shell abort (Ctrl+C): aborting this kills the run through the
86
+ * terminator exec registers on the pid. */
87
+ signal?: AbortSignal;
85
88
  }
86
89
  /** Dispatch a Node-compatible invocation into a fresh or keyed facet. */
87
90
  export declare function runFresh(facetMgr: FacetManager, code: string, opts: RunFreshOpts): Promise<RunFreshResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"node-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/node-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAE1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAO/D;AAoBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;2CAEuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAED,yEAAyE;AACzE,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CA8EzB"}
1
+ {"version":3,"file":"node-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/node-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAE1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAO/D;AAoBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;2CAEuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;gDAC4C;IAC5C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,yEAAyE;AACzE,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CAqFzB"}
@@ -143,6 +143,13 @@ export async function runFresh(facetMgr, code, opts) {
143
143
  longRunning: true,
144
144
  };
145
145
  }
146
+ // A server-shaped program that finished during its boot (`--version`,
147
+ // `--help`, a one-shot run of a CLI that also serves) is an ordinary
148
+ // completed command: its own exit code, no "started" notice.
149
+ const finished = facetMgr.processExitCode?.(spawned.pid) ?? null;
150
+ if (finished !== null) {
151
+ return { exitCode: finished, stdout: '', stderr: '', longRunning: false };
152
+ }
146
153
  const noticeLine = opts.skipSpawn
147
154
  ? ''
148
155
  : `\x1b[2m[started (long-running): pid=${spawned.pid} cmd="${command}"]\x1b[0m\n`;
@@ -1 +1 @@
1
- {"version":3,"file":"node-shims.d.ts","sourceRoot":"","sources":["../../src/runtime/node-shims.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAgDH,wBAAgB,iBAAiB,IAAI,MAAM,CA+vO1C"}
1
+ {"version":3,"file":"node-shims.d.ts","sourceRoot":"","sources":["../../src/runtime/node-shims.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAgDH,wBAAgB,iBAAiB,IAAI,MAAM,CAmhP1C"}