@cosmicdrift/kumiko-types 0.163.3 → 0.165.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.163.3",
3
+ "version": "0.165.0",
4
4
  "description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types, ohne Runtime-Code. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
package/src/config.ts CHANGED
@@ -202,8 +202,8 @@ export type ConfigStoredRow = {
202
202
  readonly userId: string | null;
203
203
  };
204
204
 
205
- // Extended row returned by ConfigResolver.getAllWithSource includes the
206
- // resolution source so the UI can display where each value came from.
205
+ // Extended row with resolution source so the UI can display where each
206
+ // value came from.
207
207
  export type ConfigStoredRowWithSource = ConfigStoredRow & {
208
208
  readonly source: ConfigValueSource;
209
209
  };
@@ -280,16 +280,6 @@ export type ConfigResolver = {
280
280
  db: DbConnection | TenantDb,
281
281
  ): Promise<ReadonlyMap<string, ConfigStoredRow>>;
282
282
 
283
- // Like getAll() but also reports the resolution source for each key.
284
- // Use when the caller needs to display the cascade origin (e.g. the
285
- // values.query handler serves the UI's hierarchy badge). Hot-path
286
- // callers should prefer getAll() for the narrower return type.
287
- getAllWithSource(
288
- tenantId: TenantId,
289
- userId: string,
290
- db: DbConnection | TenantDb,
291
- ): Promise<ReadonlyMap<string, ConfigStoredRowWithSource>>;
292
-
293
283
  // Returns ALL cascade levels for a single key — not just the winner.
294
284
  // Each level shows its value (or undefined if not set) and whether it
295
285
  // is the active/winning level. Levels are ordered by specificity
@@ -354,6 +344,15 @@ export type JobTrigger =
354
344
  // maintenance.start) statt N r.job-Calls mit demselben Handler-Body.
355
345
  // Im Handler-payload landet `_triggerName: string` damit der Code
356
346
  // weiß, welcher Trigger gefeuert hat.
347
+ //
348
+ // Two delivery semantics depending on what `on` resolves to (kumiko-
349
+ // framework#1505): a write/query-handler QN dispatches synchronously
350
+ // from dispatch-write.ts's afterCommitHooks — effectively once. An
351
+ // r.defineEvent QN (e.g. one an r.multiStreamProjection appends via
352
+ // ctx.unsafeAppendEvent) dispatches async via the job-trigger
353
+ // event-consumer (createJobTriggerEventConsumer, pipeline/system-
354
+ // hooks.ts) — cursor delivery, at-least-once. Handlers triggered on an
355
+ // r.defineEvent QN must be idempotent.
357
356
  | { readonly on: import("./handlers").NameOrRef | readonly import("./handlers").NameOrRef[] }
358
357
  | { readonly cron: string }
359
358
  | { readonly manual: true };
@@ -15,6 +15,25 @@ export class VersionConflictError extends Error {
15
15
  }
16
16
  }
17
17
 
18
+ // Thrown when append() collides on the partial unique index over
19
+ // metadata.idempotencyKey (tenant-scoped). Distinct from VersionConflictError:
20
+ // a version conflict means two writers raced the same predecessor; this
21
+ // means the same idempotency key was used twice, which is a caller-side
22
+ // retry that must have already appended once. Callers that set
23
+ // idempotencyKey should treat this as "already applied" rather than retry.
24
+ export class IdempotentAppendConflictError extends Error {
25
+ public readonly tenantId: string;
26
+ public readonly idempotencyKey: string;
27
+ constructor(tenantId: string, idempotencyKey: string) {
28
+ super(
29
+ `Idempotency conflict on tenant ${tenantId}: an event with idempotencyKey "${idempotencyKey}" was already appended.`,
30
+ );
31
+ this.name = "IdempotentAppendConflictError";
32
+ this.tenantId = tenantId;
33
+ this.idempotencyKey = idempotencyKey;
34
+ }
35
+ }
36
+
18
37
  // Thrown when ctx.appendEvent targets an archived stream. Archived aggregates
19
38
  // are read-only — restoreStream() makes them writable again. The archive
20
39
  // state is not carried on the events themselves; it lives on the sparse
@@ -12,6 +12,14 @@ export type EventMetadata = {
12
12
  // set to event.id when an MSP-apply runs ctx.appendEvent. Together with
13
13
  // correlationId forms a causation DAG across aggregate streams.
14
14
  readonly causationId?: string;
15
+ // Opt-in second line of defense against duplicate appends when the
16
+ // Redis-backed HTTP idempotency guard (pipeline/idempotency.ts) misses a
17
+ // retry window (Redis unreachable, TTL race). Callers that want a hard
18
+ // per-event uniqueness guarantee set a stable key derived from the
19
+ // triggering request; the event-store enforces it via a tenant-scoped
20
+ // partial unique index and throws IdempotentAppendConflictError on a
21
+ // repeat. Unset by default — no uniqueness constraint applies.
22
+ readonly idempotencyKey?: string;
15
23
  // Marten-conform free key/value space for app-specific metadata that
16
24
  // doesn't deserve its own EventMetadata field. Examples: A/B-test bucket,
17
25
  // feature-flag snapshot, geo-region, client SDK version. Persisted into
@@ -1,5 +1,4 @@
1
- // Barrel for observability types. Split into span/metric/provider files so
2
- // each module stays focused; consumers still import from "./types".
1
+ // Barrel for observability types. Split into span/metric/provider so each module stays focused.
3
2
 
4
3
  export type {
5
4
  Counter,
package/src/tz-context.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  import type { GeoAddress, GeoCoordinates, GeoTzProvider } from "./geo-tz";
8
8
 
9
9
  // JSON form for wall-clock + TZ — see createLocatedTimestampField() in
10
- // engine/factories.ts. Two fields, foolproof.
10
+ // @cosmicdrift/kumiko-framework, engine/factories.ts. Two fields, foolproof.
11
11
  export type LocatedTimestampJson = {
12
12
  /** Wall-clock ISO without offset, e.g. "2026-04-03T10:00:00" */
13
13
  readonly at: string;