@cosmicdrift/kumiko-dev-server 0.252.0 → 0.252.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.252.0",
3
+ "version": "0.252.1",
4
4
  "description": "Dev-tooling for Kumiko apps: local dev-server bootstrap (runDevApp), scaffolding, codegen. Its compose-stacks/env-schema subpaths are consumed at prod boot too — see @cosmicdrift/kumiko-server-runtime for the prod runner itself.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -59,9 +59,9 @@
59
59
  "kumiko-upgrade": "./bin/kumiko-upgrade.ts"
60
60
  },
61
61
  "dependencies": {
62
- "@cosmicdrift/kumiko-bundled-features": "0.252.0",
63
- "@cosmicdrift/kumiko-framework": "0.252.0",
64
- "@cosmicdrift/kumiko-server-runtime": "0.252.0",
62
+ "@cosmicdrift/kumiko-bundled-features": "0.252.1",
63
+ "@cosmicdrift/kumiko-framework": "0.252.1",
64
+ "@cosmicdrift/kumiko-server-runtime": "0.252.1",
65
65
  "ts-morph": "^28.0.0"
66
66
  },
67
67
  "publishConfig": {
@@ -25,6 +25,10 @@ const __filename = fileURLToPath(import.meta.url);
25
25
  const __dirname = dirname(__filename);
26
26
  const KUMIKO_BUILD_BIN = resolve(__dirname, "../../bin/kumiko-build.ts");
27
27
 
28
+ // Each of these tests spawns kumiko-build, which runs the real Bun.build +
29
+ // tailwind pipeline; bun's 5s default kills it mid-build on a loaded CI runner.
30
+ const FULL_PIPELINE_TIMEOUT_MS = 60_000;
31
+
28
32
  function bunAvailable(): boolean {
29
33
  try {
30
34
  execFileSync("bun", ["--version"], { stdio: "ignore" });
@@ -155,111 +159,124 @@ describe.skipIf(!bunAvailable())("kumiko-build CLI (full pipeline with bun)", ()
155
159
  await rm(tmp, { recursive: true, force: true });
156
160
  });
157
161
 
158
- test("client.ts → hashed bundle, manifest, html mit injected script-tag", async () => {
159
- // Minimal client ohne externe Deps Bun.build resolvt nichts.
160
- await mkdir(join(tmp, "src"), { recursive: true });
161
- await writeFile(
162
- join(tmp, "src/client.ts"),
163
- `const root = document.getElementById("root"); if (root) root.textContent = "hi";`,
164
- );
165
- await mkdir(join(tmp, "public"), { recursive: true });
166
- await writeFile(
167
- join(tmp, "public/index.html"),
168
- `<!doctype html><html><head></head><body><div id="root"></div><script type="module" src="/client.js"></script></body></html>`,
169
- );
170
- // package.json mit stylesheet:false äquivalent — wir setzen kein
171
- // src/styles.css und sind außerhalb des monorepos, sodass der
172
- // renderer-web-Fallback fehlschlägt und gracefully undefined liefert.
173
- await writeFile(join(tmp, "package.json"), `{"name":"build-it-fixture","private":true}`);
174
-
175
- execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
176
-
177
- const manifest = JSON.parse(await readFile(join(tmp, "dist/manifest.json"), "utf8")) as Record<
178
- string,
179
- string
180
- >;
181
- expect(manifest["client.js"]).toMatch(/^\/assets\/client-[a-z0-9]+\.js$/);
182
-
183
- const html = await readFile(join(tmp, "dist/index.html"), "utf8");
184
- expect(html).toContain(`src="${manifest["client.js"]}"`);
185
- expect(html).toContain('id="root"');
186
-
187
- // Hashed asset existiert im dist/
188
- const assetPath = join(tmp, "dist", manifest["client.js"] ?? "");
189
- expect(existsSync(assetPath)).toBe(true);
190
-
191
- // Bundle enthält den User-Code (minified — also Identifier-Namen
192
- // mangled, aber der String-Literal "hi" überlebt).
193
- expect(await readFile(assetPath, "utf8")).toContain('"hi"');
194
- });
195
-
196
- test("client.ts ohne index.html → klarer Error mit Template-Vorschlag", async () => {
197
- await mkdir(join(tmp, "src"), { recursive: true });
198
- await writeFile(join(tmp, "src/client.ts"), `console.log("hi");`);
199
- await writeFile(join(tmp, "package.json"), `{"name":"no-html","private":true}`);
200
-
201
- let stderr = "";
202
- expect(() => {
203
- try {
204
- execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
205
- } catch (err) {
206
- const e = err as { stderr?: Buffer };
207
- stderr = e.stderr?.toString() ?? "";
208
- throw err;
209
- }
210
- }).toThrow();
211
-
212
- expect(stderr).toContain("kein index.html gefunden");
213
- expect(stderr).toContain(`<script type="module" src="/client.js"></script>`);
214
- });
215
-
216
- test("client.ts + index.html ohne /client.js Placeholder → klarer Error", async () => {
217
- await mkdir(join(tmp, "src"), { recursive: true });
218
- await writeFile(join(tmp, "src/client.ts"), `console.log("hi");`);
219
- await mkdir(join(tmp, "public"), { recursive: true });
220
- await writeFile(
221
- join(tmp, "public/index.html"),
222
- `<!doctype html><html><body>no script</body></html>`,
223
- );
224
- await writeFile(join(tmp, "package.json"), `{"name":"no-placeholder","private":true}`);
225
-
226
- let stderr = "";
227
- expect(() => {
228
- try {
229
- execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
230
- } catch (err) {
231
- const e = err as { stderr?: Buffer };
232
- stderr = e.stderr?.toString() ?? "";
233
- throw err;
234
- }
235
- }).toThrow();
236
-
237
- expect(stderr).toContain("keinen Entry-Tag für /client.js");
238
- expect(stderr).toContain(`<script type="module" src="/client.js"></script>`);
239
- });
240
-
241
- test("Re-Build mit unverändertem Source produziert identischen Hash (reproducibility)", async () => {
242
- await mkdir(join(tmp, "src"), { recursive: true });
243
- await writeFile(join(tmp, "src/client.ts"), `console.log("stable");`);
244
- await mkdir(join(tmp, "public"), { recursive: true });
245
- await writeFile(
246
- join(tmp, "public/index.html"),
247
- `<!doctype html><html><body><script type="module" src="/client.js"></script></body></html>`,
248
- );
249
- await writeFile(join(tmp, "package.json"), `{"name":"hash-stability","private":true}`);
250
-
251
- execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
252
- const manifest1 = JSON.parse(await readFile(join(tmp, "dist/manifest.json"), "utf8")) as Record<
253
- string,
254
- string
255
- >;
256
-
257
- execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
258
- const manifest2 = JSON.parse(await readFile(join(tmp, "dist/manifest.json"), "utf8")) as Record<
259
- string,
260
- string
261
- >;
262
-
263
- expect(manifest2["client.js"]).toBe(manifest1["client.js"]);
264
- });
162
+ test(
163
+ "client.ts hashed bundle, manifest, html mit injected script-tag",
164
+ async () => {
165
+ // Minimal client ohne externe Deps — Bun.build resolvt nichts.
166
+ await mkdir(join(tmp, "src"), { recursive: true });
167
+ await writeFile(
168
+ join(tmp, "src/client.ts"),
169
+ `const root = document.getElementById("root"); if (root) root.textContent = "hi";`,
170
+ );
171
+ await mkdir(join(tmp, "public"), { recursive: true });
172
+ await writeFile(
173
+ join(tmp, "public/index.html"),
174
+ `<!doctype html><html><head></head><body><div id="root"></div><script type="module" src="/client.js"></script></body></html>`,
175
+ );
176
+ // package.json mit stylesheet:false äquivalent wir setzen kein
177
+ // src/styles.css und sind außerhalb des monorepos, sodass der
178
+ // renderer-web-Fallback fehlschlägt und gracefully undefined liefert.
179
+ await writeFile(join(tmp, "package.json"), `{"name":"build-it-fixture","private":true}`);
180
+
181
+ execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
182
+
183
+ const manifest = JSON.parse(
184
+ await readFile(join(tmp, "dist/manifest.json"), "utf8"),
185
+ ) as Record<string, string>;
186
+ expect(manifest["client.js"]).toMatch(/^\/assets\/client-[a-z0-9]+\.js$/);
187
+
188
+ const html = await readFile(join(tmp, "dist/index.html"), "utf8");
189
+ expect(html).toContain(`src="${manifest["client.js"]}"`);
190
+ expect(html).toContain('id="root"');
191
+
192
+ // Hashed asset existiert im dist/
193
+ const assetPath = join(tmp, "dist", manifest["client.js"] ?? "");
194
+ expect(existsSync(assetPath)).toBe(true);
195
+
196
+ // Bundle enthält den User-Code (minified — also Identifier-Namen
197
+ // mangled, aber der String-Literal "hi" überlebt).
198
+ expect(await readFile(assetPath, "utf8")).toContain('"hi"');
199
+ },
200
+ FULL_PIPELINE_TIMEOUT_MS,
201
+ );
202
+
203
+ test(
204
+ "client.ts ohne index.html → klarer Error mit Template-Vorschlag",
205
+ async () => {
206
+ await mkdir(join(tmp, "src"), { recursive: true });
207
+ await writeFile(join(tmp, "src/client.ts"), `console.log("hi");`);
208
+ await writeFile(join(tmp, "package.json"), `{"name":"no-html","private":true}`);
209
+
210
+ let stderr = "";
211
+ expect(() => {
212
+ try {
213
+ execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
214
+ } catch (err) {
215
+ const e = err as { stderr?: Buffer };
216
+ stderr = e.stderr?.toString() ?? "";
217
+ throw err;
218
+ }
219
+ }).toThrow();
220
+
221
+ expect(stderr).toContain("kein index.html gefunden");
222
+ expect(stderr).toContain(`<script type="module" src="/client.js"></script>`);
223
+ },
224
+ FULL_PIPELINE_TIMEOUT_MS,
225
+ );
226
+
227
+ test(
228
+ "client.ts + index.html ohne /client.js Placeholder → klarer Error",
229
+ async () => {
230
+ await mkdir(join(tmp, "src"), { recursive: true });
231
+ await writeFile(join(tmp, "src/client.ts"), `console.log("hi");`);
232
+ await mkdir(join(tmp, "public"), { recursive: true });
233
+ await writeFile(
234
+ join(tmp, "public/index.html"),
235
+ `<!doctype html><html><body>no script</body></html>`,
236
+ );
237
+ await writeFile(join(tmp, "package.json"), `{"name":"no-placeholder","private":true}`);
238
+
239
+ let stderr = "";
240
+ expect(() => {
241
+ try {
242
+ execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
243
+ } catch (err) {
244
+ const e = err as { stderr?: Buffer };
245
+ stderr = e.stderr?.toString() ?? "";
246
+ throw err;
247
+ }
248
+ }).toThrow();
249
+
250
+ expect(stderr).toContain("keinen Entry-Tag für /client.js");
251
+ expect(stderr).toContain(`<script type="module" src="/client.js"></script>`);
252
+ },
253
+ FULL_PIPELINE_TIMEOUT_MS,
254
+ );
255
+
256
+ test(
257
+ "Re-Build mit unverändertem Source produziert identischen Hash (reproducibility)",
258
+ async () => {
259
+ await mkdir(join(tmp, "src"), { recursive: true });
260
+ await writeFile(join(tmp, "src/client.ts"), `console.log("stable");`);
261
+ await mkdir(join(tmp, "public"), { recursive: true });
262
+ await writeFile(
263
+ join(tmp, "public/index.html"),
264
+ `<!doctype html><html><body><script type="module" src="/client.js"></script></body></html>`,
265
+ );
266
+ await writeFile(join(tmp, "package.json"), `{"name":"hash-stability","private":true}`);
267
+
268
+ execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
269
+ const manifest1 = JSON.parse(
270
+ await readFile(join(tmp, "dist/manifest.json"), "utf8"),
271
+ ) as Record<string, string>;
272
+
273
+ execFileSync("bun", [KUMIKO_BUILD_BIN, tmp], { stdio: "pipe" });
274
+ const manifest2 = JSON.parse(
275
+ await readFile(join(tmp, "dist/manifest.json"), "utf8"),
276
+ ) as Record<string, string>;
277
+
278
+ expect(manifest2["client.js"]).toBe(manifest1["client.js"]);
279
+ },
280
+ FULL_PIPELINE_TIMEOUT_MS,
281
+ );
265
282
  });