@cosmicdrift/kumiko-framework 0.59.1 → 0.60.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-framework",
3
- "version": "0.59.1",
3
+ "version": "0.60.0",
4
4
  "description": "Framework core — engine, pipeline, API, DB, and every other bit that makes Kumiko go.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -21,6 +21,7 @@ import {
21
21
  type ProjectionDefinition,
22
22
  } from "../../engine";
23
23
  import { createEventsTable } from "../../event-store";
24
+ import type { JobRunner } from "../../jobs/job-runner";
24
25
  import { createProjectionStateTable } from "../../pipeline";
25
26
  import {
26
27
  createTestDb,
@@ -34,6 +35,7 @@ import {
34
35
  enqueueProjectionRebuild,
35
36
  listPendingRebuildRows,
36
37
  listPendingRebuilds,
38
+ PROJECTION_REBUILD_JOB,
37
39
  queueRebuildsFromMarkers,
38
40
  runPendingRebuilds,
39
41
  } from "../pending-rebuilds";
@@ -280,3 +282,42 @@ describe("enqueueProjectionRebuild — inline fallback (no jobs feature)", () =>
280
282
  expect(await getCount()).toBe(2);
281
283
  });
282
284
  });
285
+
286
+ // #391/2: jobRunner present but the projection-rebuild job not registered (a
287
+ // caller that wired a jobRunner yet forgot to compose createJobsFeature()). The
288
+ // getJob-capability guard must still fall to the inline rebuild — NOT dispatch
289
+ // onto a runner whose queue has no handler for the job (silent no-op forever).
290
+ describe("enqueueProjectionRebuild — inline fallback (jobRunner without the job)", () => {
291
+ test("jobRunner present but job unregistered → inline, dispatch never called", async () => {
292
+ await executor.create({ groupId: GROUP, name: "a" }, admin, tdb);
293
+ await executor.create({ groupId: GROUP, name: "b" }, admin, tdb);
294
+ await executor.create({ groupId: GROUP, name: "c" }, admin, tdb);
295
+
296
+ // Sanity: this registry has no projection-rebuild job (no jobs feature).
297
+ expect(registry.getJob(PROJECTION_REBUILD_JOB)).toBeUndefined();
298
+
299
+ let dispatchCalls = 0;
300
+ const stubJobRunner: JobRunner = {
301
+ start: async () => {},
302
+ stop: async () => {},
303
+ handleEvent: async () => {},
304
+ dispatch: async () => {
305
+ dispatchCalls++;
306
+ return "should-not-happen";
307
+ },
308
+ };
309
+
310
+ const outcome = await enqueueProjectionRebuild("pendingtest:projection:pending-counts", {
311
+ db: testDb.db,
312
+ registry,
313
+ jobRunner: stubJobRunner,
314
+ });
315
+
316
+ expect(outcome.mode).toBe("inline");
317
+ if (outcome.mode === "inline") {
318
+ expect(outcome.result.eventsProcessed).toBe(3);
319
+ }
320
+ expect(dispatchCalls).toBe(0); // routed to inline, not to a handler-less queue
321
+ expect(await getCount()).toBe(3);
322
+ });
323
+ });