@cosmicdrift/kumiko-framework 0.21.1 → 0.23.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.
@@ -6,7 +6,7 @@ describe("runEventStoreSeed", () => {
6
6
  let updateCalls = 0;
7
7
  let createCalls = 0;
8
8
 
9
- const result = await runEventStoreSeed({
9
+ const result = await runEventStoreSeed<string>({
10
10
  existing: { id: "agg-1", version: 3 },
11
11
  create: async () => {
12
12
  createCalls++;
@@ -26,7 +26,7 @@ describe("runEventStoreSeed", () => {
26
26
  test('ifExists="update" calls update when row exists', async () => {
27
27
  let updateCalls = 0;
28
28
 
29
- const result = await runEventStoreSeed({
29
+ const result = await runEventStoreSeed<string>({
30
30
  existing: { id: "agg-2", version: 1 },
31
31
  ifExists: "update",
32
32
  create: async () => ({ id: "new" }),
@@ -44,7 +44,7 @@ describe("runEventStoreSeed", () => {
44
44
  test("missing row calls create", async () => {
45
45
  let createCalls = 0;
46
46
 
47
- const result = await runEventStoreSeed({
47
+ const result = await runEventStoreSeed<string>({
48
48
  existing: null,
49
49
  create: async () => {
50
50
  createCalls++;
@@ -56,4 +56,15 @@ describe("runEventStoreSeed", () => {
56
56
  expect(result.id).toBe("created");
57
57
  expect(createCalls).toBe(1);
58
58
  });
59
+
60
+ test("supports numeric id type via explicit generic", async () => {
61
+ const result = await runEventStoreSeed<number>({
62
+ existing: { id: 42, version: 1 },
63
+ ifExists: "update",
64
+ create: async () => ({ id: 99 }),
65
+ update: async (row) => ({ id: row.id }),
66
+ });
67
+
68
+ expect(result.id).toBe(42);
69
+ });
59
70
  });
@@ -1,21 +1,25 @@
1
1
  import { DEFAULT_SEED_IF_EXISTS, type SeedIfExists } from "./types";
2
2
 
3
- export type EventStoreSeedExisting = {
4
- readonly id: string | number;
3
+ export type EventStoreSeedExisting<TId extends string | number = string> = {
4
+ readonly id: TId;
5
5
  readonly version: number;
6
6
  };
7
7
 
8
- export type RunEventStoreSeedOptions<TExisting extends EventStoreSeedExisting> = {
8
+ export type RunEventStoreSeedOptions<
9
+ TId extends string | number = string,
10
+ TExisting extends EventStoreSeedExisting<TId> = EventStoreSeedExisting<TId>,
11
+ > = {
9
12
  readonly existing: TExisting | null | undefined;
10
13
  readonly ifExists?: SeedIfExists;
11
- readonly create: () => Promise<{ id: string | number }>;
12
- readonly update: (existing: TExisting) => Promise<{ id: string | number }>;
14
+ readonly create: () => Promise<{ id: TId }>;
15
+ readonly update: (existing: TExisting) => Promise<{ id: TId }>;
13
16
  };
14
17
 
15
18
  /** Shared create-or-skip/update path for event-store boot-seed helpers. */
16
- export async function runEventStoreSeed<TExisting extends EventStoreSeedExisting>(
17
- opts: RunEventStoreSeedOptions<TExisting>,
18
- ): Promise<{ id: string | number }> {
19
+ export async function runEventStoreSeed<
20
+ TId extends string | number = string,
21
+ TExisting extends EventStoreSeedExisting<TId> = EventStoreSeedExisting<TId>,
22
+ >(opts: RunEventStoreSeedOptions<TId, TExisting>): Promise<{ id: TId }> {
19
23
  const ifExists = opts.ifExists ?? DEFAULT_SEED_IF_EXISTS;
20
24
  if (opts.existing != null) {
21
25
  if (ifExists === "skip") {
@@ -30,6 +30,7 @@ import {
30
30
  type EntityEditScreenDefinition,
31
31
  type EntityListScreenDefinition,
32
32
  type FieldDefinition,
33
+ isExtensionEditSection,
33
34
  normalizeEditField,
34
35
  normalizeListColumn,
35
36
  parseQn,
@@ -234,6 +235,7 @@ function collectRequiredEditFields(
234
235
  ): string[] {
235
236
  const out: string[] = [];
236
237
  for (const section of screen.layout.sections) {
238
+ if (isExtensionEditSection(section)) continue;
237
239
  for (const rawField of section.fields) {
238
240
  const { field } = normalizeEditField(rawField);
239
241
  const def = entity.fields[field];
@@ -271,6 +273,7 @@ function buildEditFillOps(
271
273
  // form; Felder ohne Fixture-Wert (file/image/…) werden übersprungen.
272
274
  const ops: EditFillOp[] = [];
273
275
  for (const section of screen.layout.sections) {
276
+ if (isExtensionEditSection(section)) continue;
274
277
  for (const raw of section.fields) {
275
278
  const { field } = normalizeEditField(raw);
276
279
  const def = entity.fields[field];
@@ -317,6 +320,7 @@ function pickIdentifyingForEdit(
317
320
  : undefined;
318
321
 
319
322
  for (const section of editScreen.layout.sections) {
323
+ if (isExtensionEditSection(section)) continue;
320
324
  for (const rawField of section.fields) {
321
325
  const { field } = normalizeEditField(rawField);
322
326
  if (entity.fields[field]?.type !== "text") continue;
@@ -46,7 +46,9 @@ export type {
46
46
  ConfigEditScreenDefinition,
47
47
  CustomScreenDefinition,
48
48
  CustomScreenRoute,
49
+ EditExtensionSection,
49
50
  EditFieldSpec,
51
+ EditFieldsSection,
50
52
  EditLayout,
51
53
  EditSectionSpec,
52
54
  EntityEditScreenDefinition,
@@ -64,6 +66,10 @@ export type {
64
66
  ScreenSlots,
65
67
  ToolbarAction,
66
68
  } from "../engine/types/screen";
67
- export { normalizeEditField, normalizeListColumn } from "../engine/types/screen";
69
+ export {
70
+ isExtensionEditSection,
71
+ normalizeEditField,
72
+ normalizeListColumn,
73
+ } from "../engine/types/screen";
68
74
  export type { WorkspaceDefinition } from "../engine/types/workspace";
69
75
  export type { AppSchema, FeatureSchema, WorkspaceSchema } from "./app-schema";