@cosmicdrift/kumiko-server-runtime 0.252.0 → 0.253.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-server-runtime",
3
- "version": "0.252.0",
3
+ "version": "0.253.0",
4
4
  "description": "Production server-boot runtime for Kumiko apps: connections, schema-drift-gate, seeds, lifecycle, graceful shutdown. Symmetric to kumiko-dev-server's runDevApp, without dev/scaffold/codegen tooling.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -80,8 +80,8 @@
80
80
  }
81
81
  },
82
82
  "dependencies": {
83
- "@cosmicdrift/kumiko-bundled-features": "0.252.0",
84
- "@cosmicdrift/kumiko-framework": "0.252.0",
83
+ "@cosmicdrift/kumiko-bundled-features": "0.253.0",
84
+ "@cosmicdrift/kumiko-framework": "0.253.0",
85
85
  "temporal-polyfill": "^0.3.2"
86
86
  },
87
87
  "publishConfig": {
@@ -895,6 +895,11 @@ describe("runProdApp: lokaler Event-Dispatcher (MSP-Anwendung im Single-Containe
895
895
  // multiStreamProjection blieb in Prod unangewendet, kumiko_event_consumers
896
896
  // blieb leer. Der Test schreibt über den ECHTEN Boot-Pfad und pollt auf
897
897
  // die async projizierte Row.
898
+ // Both polls normally settle in well under a second; this only sizes the
899
+ // harness limit to the two 8s poll budgets so a slow retry is not cut short
900
+ // by bun's 5s default before pollFor can give up on its own terms.
901
+ const BOOT_AND_POLL_TIMEOUT_MS = 20_000;
902
+
898
903
  async function pollFor<T>(probe: () => Promise<T | undefined>, timeoutMs = 8000): Promise<T> {
899
904
  const deadline = Date.now() + timeoutMs;
900
905
  for (;;) {
@@ -905,51 +910,60 @@ describe("runProdApp: lokaler Event-Dispatcher (MSP-Anwendung im Single-Containe
905
910
  }
906
911
  }
907
912
 
908
- test("Write → appendEvent → MSP wendet async an; Consumer-Cursor wandert", async () => {
909
- let dispatchSystemWrite: import("../extra-routes-deps").ExtraRoutesSystemDeps["dispatchSystemWrite"];
910
- const handle = await boot(undefined, {
911
- eventDispatcher: { pollIntervalMs: 50 },
912
- extraRoutes: (_app, deps) => {
913
- dispatchSystemWrite = deps.dispatchSystemWrite;
914
- },
915
- });
916
-
917
- // Default-Boot baut den lokalen Dispatcher und start() hat ihn gestartet.
918
- expect(handle.entrypoint.eventDispatcher).toBeDefined();
913
+ test(
914
+ "Write appendEvent → MSP wendet async an; Consumer-Cursor wandert",
915
+ async () => {
916
+ let dispatchSystemWrite: import("../extra-routes-deps").ExtraRoutesSystemDeps["dispatchSystemWrite"];
917
+ const handle = await boot(undefined, {
918
+ eventDispatcher: { pollIntervalMs: 50 },
919
+ extraRoutes: (_app, deps) => {
920
+ dispatchSystemWrite = deps.dispatchSystemWrite;
921
+ },
922
+ });
919
923
 
920
- const aggregateId = crypto.randomUUID();
921
- const result = await dispatchSystemWrite!({
922
- handlerQn: "prod-probe:write:probe-append",
923
- payload: { aggregateId, note: "dispatched" },
924
- tenantId: TENANT_ID as import("@cosmicdrift/kumiko-framework/engine").TenantId,
925
- });
926
- expect(result.isSuccess).toBe(true);
924
+ // Default-Boot baut den lokalen Dispatcher und start() hat ihn gestartet.
925
+ expect(handle.entrypoint.eventDispatcher).toBeDefined();
927
926
 
928
- const url = ADMIN_URL.replace(/\/[^/]+$/, `/${TEST_DB}`);
929
- const { db, close } = createDbConnection(url);
930
- try {
931
- const row = await pollFor(async () => {
932
- const rows = (await asRawClient(db).unsafe(
933
- `SELECT note FROM prod_probe_pings WHERE aggregate_id = $1`,
934
- [aggregateId],
935
- )) as Array<{ note: string }>;
936
- return rows[0];
927
+ const aggregateId = crypto.randomUUID();
928
+ const result = await dispatchSystemWrite!({
929
+ handlerQn: "prod-probe:write:probe-append",
930
+ payload: { aggregateId, note: "dispatched" },
931
+ tenantId: TENANT_ID as import("@cosmicdrift/kumiko-framework/engine").TenantId,
937
932
  });
938
- expect(row.note).toBe("dispatched");
939
-
940
- // Consumer-Registrierung + Cursor-Fortschritt — in Prod war diese
941
- // Tabelle komplett leer, DER Beweis dass nie ein Dispatcher lief.
942
- const consumers = (await asRawClient(db).unsafe(
943
- `SELECT name, last_processed_event_id FROM kumiko_event_consumers
944
- WHERE name = 'prod-probe:projection:probe-ping-projection'
945
- OR name LIKE '%probe-ping-projection%'`,
946
- )) as Array<{ name: string; last_processed_event_id: string | number }>;
947
- expect(consumers.length).toBeGreaterThan(0);
948
- expect(Number(consumers[0]?.last_processed_event_id)).toBeGreaterThan(0);
949
- } finally {
950
- await close();
951
- }
952
- });
933
+ expect(result.isSuccess).toBe(true);
934
+
935
+ const url = ADMIN_URL.replace(/\/[^/]+$/, `/${TEST_DB}`);
936
+ const { db, close } = createDbConnection(url);
937
+ try {
938
+ const row = await pollFor(async () => {
939
+ const rows = (await asRawClient(db).unsafe(
940
+ `SELECT note FROM prod_probe_pings WHERE aggregate_id = $1`,
941
+ [aggregateId],
942
+ )) as Array<{ note: string }>;
943
+ return rows[0];
944
+ });
945
+ expect(row.note).toBe("dispatched");
946
+
947
+ // Consumer-Registrierung + Cursor-Fortschritt — in Prod war diese
948
+ // Tabelle komplett leer, DER Beweis dass nie ein Dispatcher lief.
949
+ // The cursor is committed after the projection row, so poll on the
950
+ // cursor value itself — a registered consumer still reads 0 for a moment.
951
+ const consumers = await pollFor(async () => {
952
+ const rows = (await asRawClient(db).unsafe(
953
+ `SELECT name, last_processed_event_id FROM kumiko_event_consumers
954
+ WHERE name = 'prod-probe:projection:probe-ping-projection'
955
+ OR name LIKE '%probe-ping-projection%'`,
956
+ )) as Array<{ name: string; last_processed_event_id: string | number }>;
957
+ return Number(rows[0]?.last_processed_event_id) > 0 ? rows : undefined;
958
+ });
959
+ expect(consumers.length).toBeGreaterThan(0);
960
+ expect(Number(consumers[0]?.last_processed_event_id)).toBeGreaterThan(0);
961
+ } finally {
962
+ await close();
963
+ }
964
+ },
965
+ BOOT_AND_POLL_TIMEOUT_MS,
966
+ );
953
967
 
954
968
  test("eventDispatcher.disabled: kein lokaler Dispatcher gebaut", async () => {
955
969
  const handle = await boot(undefined, {