@cosmicdrift/kumiko-types 0.167.1 → 0.170.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-types",
3
- "version": "0.167.1",
3
+ "version": "0.170.0",
4
4
  "description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt keine identitaets-sensitiven Runtime-Werte mehr (Error-Klassen leben seit #1629 in kumiko-framework, Brand-Symbole nutzen Symbol.for) und ist deshalb eine plain dependency, keine peerDependency.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -18,6 +18,8 @@ export type RegisterEntityCrudOptions = {
18
18
  readonly write?: EntityHandlerOptions;
19
19
  readonly read?: EntityQueryHandlerOptions;
20
20
  readonly verbs?: Partial<Record<EntityCrudVerb, boolean>>;
21
+ /** Per-verb access override — falls back to `write.access`/`read.access` when unset for a verb. */
22
+ readonly verbAccess?: Partial<Record<EntityCrudVerb, AccessRule>>;
21
23
  /** Default true. Set false when the entity was already registered (e.g. before r.relation). */
22
24
  readonly registerEntity?: boolean;
23
25
  };
@@ -5,18 +5,29 @@ import type { EntityId } from "./identifiers";
5
5
  import type { SearchAdapter } from "./search-adapter";
6
6
  import type { TenantDb } from "./tenant-db-types";
7
7
 
8
+ // Runs the caller's preSave hooks against changes not yet persisted, for
9
+ // the executor's create()/update() only — restore/delete/forget have no
10
+ // `changes` to shape. See HandlerContext.runPreSave for how this gets bound
11
+ // to a specific handler name + AppContext.
12
+ export type PreSaveRunner = (
13
+ changes: Record<string, unknown>,
14
+ previous: Readonly<Record<string, unknown>>,
15
+ isNew: boolean,
16
+ ) => Promise<Record<string, unknown>>;
17
+
8
18
  export type EventStoreExecutor = {
9
19
  create: (
10
20
  payload: Record<string, unknown>,
11
21
  user: SessionUser,
12
22
  db: TenantDb,
23
+ options?: { preSave?: PreSaveRunner },
13
24
  ) => Promise<WriteResult<SaveContext>>;
14
25
 
15
26
  update: (
16
27
  payload: { id: EntityId; version?: number | undefined; changes: Record<string, unknown> },
17
28
  user: SessionUser,
18
29
  db: TenantDb,
19
- options?: { skipOptimisticLock?: boolean; skipUnchanged?: boolean },
30
+ options?: { skipOptimisticLock?: boolean; skipUnchanged?: boolean; preSave?: PreSaveRunner },
20
31
  ) => Promise<WriteResult<SaveContext>>;
21
32
 
22
33
  delete: (
package/src/handlers.ts CHANGED
@@ -354,6 +354,21 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
354
354
  // still apply, so this never widens what a user may see beyond the live list.
355
355
  readonly includeDeleted?: boolean;
356
356
 
357
+ // Wired by the write dispatcher whenever a lifecycle pipeline is active;
358
+ // runs the registered `preSave` hooks (+ system preSave hooks) for
359
+ // `handlerName`, returning the hook-transformed `changes`. Entity CRUD
360
+ // handlers (create/update) forward this to the executor so preSave hooks
361
+ // actually run before persistence (kumiko-framework#1672). A custom
362
+ // `r.writeHandler` handler that doesn't go through the executor must call
363
+ // this itself to get preSave semantics — undefined when no lifecycle
364
+ // pipeline is wired (e.g. bare HandlerContext stubs in unit tests).
365
+ readonly runPreSave?: (
366
+ handlerName: string,
367
+ changes: Record<string, unknown>,
368
+ previous: Readonly<Record<string, unknown>>,
369
+ isNew: boolean,
370
+ ) => Promise<Record<string, unknown>>;
371
+
357
372
  readonly query: (qn: string, payload: unknown) => Promise<unknown>;
358
373
  readonly queryAs: (user: SessionUser, qn: string, payload: unknown) => Promise<unknown>;
359
374
  readonly write: (qn: string, payload: unknown) => Promise<WriteResult>;