@cosmicdrift/kumiko-dev-server 0.28.0 → 0.31.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-dev-server",
3
- "version": "0.28.0",
3
+ "version": "0.31.0",
4
4
  "description": "Development server bootstrap for Kumiko apps. Bundles the client, mints dev-JWTs, injects the resolved AppSchema, and seeds an admin. Not for production.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -313,6 +313,38 @@ describe("runProdApp", () => {
313
313
  expect(await res.text()).toContain("SPA shell");
314
314
  });
315
315
 
316
+ test("static-fallback: non-GET ohne Hono-Match → 404, nicht SPA-Shell (#259)", async () => {
317
+ // Prod-Szenario: POST auf einen falsch konfigurierten Webhook-Pfad
318
+ // (Route nicht gemountet). 200 index.html würde dem Provider
319
+ // "delivered" signalisieren — Events gingen still verloren.
320
+ const tmpStaticDir = await createTempStaticDir({
321
+ "index.html": "<html>SPA shell</html>",
322
+ "robots.txt": "User-agent: *\nAllow: /",
323
+ });
324
+
325
+ const handle = await boot(undefined, { staticDir: tmpStaticDir });
326
+
327
+ const unmatched = await handle.fetch(
328
+ new Request("http://test/webhooks/subscription/stripe", { method: "POST" }),
329
+ );
330
+ expect(unmatched.status).toBe(404);
331
+
332
+ // Disk-Files werden ebenfalls nicht auf non-GET serviert.
333
+ const diskFile = await handle.fetch(new Request("http://test/robots.txt", { method: "POST" }));
334
+ expect(diskFile.status).toBe(404);
335
+ });
336
+
337
+ test("static-fallback: HEAD auf SPA-Route bleibt 200 (spiegelt GET)", async () => {
338
+ const tmpStaticDir = await createTempStaticDir({
339
+ "index.html": "<html>SPA shell</html>",
340
+ });
341
+
342
+ const handle = await boot(undefined, { staticDir: tmpStaticDir });
343
+
344
+ const res = await handle.fetch(new Request("http://test/some/spa/route", { method: "HEAD" }));
345
+ expect(res.status).toBe(200);
346
+ });
347
+
316
348
  test("hostDispatch: per-host html-Datei + Schema-Gating", async () => {
317
349
  // Multi-App-Deployment: zwei HTML-Dateien für unterschiedliche
318
350
  // Hosts. Schema wird NUR für admin-Host injected — Public-Host
@@ -1070,6 +1070,14 @@ function buildStaticFallback(
1070
1070
  }
1071
1071
  const honoRes = honoTry.response;
1072
1072
 
1073
+ // Disk-/SPA-Fallback ist GET/HEAD-only. Ein non-GET ohne Hono-Match
1074
+ // (z.B. POST auf einen falsch konfigurierten Webhook-Pfad) muss den
1075
+ // Hono-404 durchreichen — 200 index.html würde dem Provider
1076
+ // "delivered" signalisieren und Events gingen still verloren (#259).
1077
+ if (req.method !== "GET" && req.method !== "HEAD") {
1078
+ return honoRes;
1079
+ }
1080
+
1073
1081
  // Disk-Datei (Asset oder konkrete File). Asset-Pfade laufen
1074
1082
  // host-unabhängig — die Bundles in /assets/* werden vom client
1075
1083
  // aktiv geladen, kein Server-side Routing nötig.