@venizia/ignis-kernel 0.2.0-10 → 0.2.0-11

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.
Files changed (29) hide show
  1. package/dist/cjs/base/events/common/constants.d.ts +32 -0
  2. package/dist/cjs/base/events/common/constants.d.ts.map +1 -1
  3. package/dist/cjs/base/events/common/constants.js +34 -1
  4. package/dist/cjs/base/events/common/constants.js.map +1 -1
  5. package/dist/cjs/base/events/common/types.d.ts +41 -3
  6. package/dist/cjs/base/events/common/types.d.ts.map +1 -1
  7. package/dist/cjs/base/events/event-bus.d.ts +45 -8
  8. package/dist/cjs/base/events/event-bus.d.ts.map +1 -1
  9. package/dist/cjs/base/events/event-bus.js +144 -24
  10. package/dist/cjs/base/events/event-bus.js.map +1 -1
  11. package/dist/cjs/base/models/common/types.d.ts +20 -0
  12. package/dist/cjs/base/models/common/types.d.ts.map +1 -1
  13. package/dist/cjs/base/models/common/types.js +9 -1
  14. package/dist/cjs/base/models/common/types.js.map +1 -1
  15. package/dist/esm/base/events/common/constants.d.ts +32 -0
  16. package/dist/esm/base/events/common/constants.d.ts.map +1 -1
  17. package/dist/esm/base/events/common/constants.js +32 -0
  18. package/dist/esm/base/events/common/constants.js.map +1 -1
  19. package/dist/esm/base/events/common/types.d.ts +41 -3
  20. package/dist/esm/base/events/common/types.d.ts.map +1 -1
  21. package/dist/esm/base/events/event-bus.d.ts +45 -8
  22. package/dist/esm/base/events/event-bus.d.ts.map +1 -1
  23. package/dist/esm/base/events/event-bus.js +145 -25
  24. package/dist/esm/base/events/event-bus.js.map +1 -1
  25. package/dist/esm/base/models/common/types.d.ts +20 -0
  26. package/dist/esm/base/models/common/types.d.ts.map +1 -1
  27. package/dist/esm/base/models/common/types.js +7 -0
  28. package/dist/esm/base/models/common/types.js.map +1 -1
  29. package/package.json +1 -1
@@ -1,5 +1,37 @@
1
+ import type { TConstValue } from '@venizia/ignis-helpers/common';
1
2
  export declare class EventDispatchRetry {
2
3
  static readonly MAX_ATTEMPTS = 3;
3
4
  static readonly BASE_DELAY_MS = 100;
5
+ /**
6
+ * Ceiling on `register`'s `retry.maxAttempts`. Dispatch is fire-and-forget - nobody awaits it - so
7
+ * an attempt count high enough to matter is already high enough to hammer a struggling downstream
8
+ * resource attempt after attempt. Twice the highest count any known consumer has asked for (5)
9
+ * leaves room to tune without permitting an attempt storm.
10
+ */
11
+ static readonly MAX_ATTEMPTS_CEILING = 10;
12
+ /**
13
+ * Ceiling, in ms, on the total backoff window `register`'s `retry` can produce (the sum of every
14
+ * inter-attempt delay, computed without jitter since jitter only shrinks it). Matches
15
+ * `RetryHelper`'s own default cap on a SINGLE delay: a dispatch holds a handler's resources - e.g.
16
+ * a database connection - for its entire retry window, so the sum across every attempt gets the
17
+ * same "unreasonable beyond this" line the framework already draws for one attempt.
18
+ */
19
+ static readonly MAX_TOTAL_WINDOW_MS = 30000;
4
20
  }
21
+ /**
22
+ * Tag for `EventBus.register`'s `handler` union (`TEventHandlerReference`). The tag makes the
23
+ * caller's choice explicit at the call site instead of implicit in whichever field is present, so a
24
+ * mismatched `type`/field pair (`BINDING_KEY` with `fn`, or `FUNCTION` with `key`) is a compile
25
+ * error there rather than a runtime surprise later, inside a `queueMicrotask` where nobody is
26
+ * watching.
27
+ */
28
+ export declare class EventHandlerTypes {
29
+ /** `handler.key` is resolved from the container on every retry attempt - a rebind reaches an attempt already in flight. */
30
+ static readonly BINDING_KEY = "binding-key";
31
+ /** `handler.fn` is invoked directly as a captured closure - there is nothing to rebind, so every attempt in a retry window calls the exact function registered here. */
32
+ static readonly FUNCTION = "function";
33
+ static readonly SCHEME_SET: Set<string>;
34
+ static isValid(value: string): value is TEventHandlerType;
35
+ }
36
+ export type TEventHandlerType = TConstValue<typeof EventHandlerTypes>;
5
37
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,aAAa,OAAO;CACrC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,aAAa,OAAO;IAEpC;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,oBAAoB,MAAM;IAE1C;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,mBAAmB,SAAU;CAC9C;AAED;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC5B,2HAA2H;IAC3H,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;IAE5C,wKAAwK;IACxK,MAAM,CAAC,QAAQ,CAAC,QAAQ,cAAc;IAEtC,MAAM,CAAC,QAAQ,CAAC,UAAU,cAAsD;IAEhF,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,iBAAiB;CAG1D;AAED,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
@@ -1,9 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EventDispatchRetry = void 0;
3
+ exports.EventHandlerTypes = exports.EventDispatchRetry = void 0;
4
4
  class EventDispatchRetry {
5
5
  static { this.MAX_ATTEMPTS = 3; }
6
6
  static { this.BASE_DELAY_MS = 100; }
7
+ /**
8
+ * Ceiling on `register`'s `retry.maxAttempts`. Dispatch is fire-and-forget - nobody awaits it - so
9
+ * an attempt count high enough to matter is already high enough to hammer a struggling downstream
10
+ * resource attempt after attempt. Twice the highest count any known consumer has asked for (5)
11
+ * leaves room to tune without permitting an attempt storm.
12
+ */
13
+ static { this.MAX_ATTEMPTS_CEILING = 10; }
14
+ /**
15
+ * Ceiling, in ms, on the total backoff window `register`'s `retry` can produce (the sum of every
16
+ * inter-attempt delay, computed without jitter since jitter only shrinks it). Matches
17
+ * `RetryHelper`'s own default cap on a SINGLE delay: a dispatch holds a handler's resources - e.g.
18
+ * a database connection - for its entire retry window, so the sum across every attempt gets the
19
+ * same "unreasonable beyond this" line the framework already draws for one attempt.
20
+ */
21
+ static { this.MAX_TOTAL_WINDOW_MS = 30_000; }
7
22
  }
8
23
  exports.EventDispatchRetry = EventDispatchRetry;
24
+ /**
25
+ * Tag for `EventBus.register`'s `handler` union (`TEventHandlerReference`). The tag makes the
26
+ * caller's choice explicit at the call site instead of implicit in whichever field is present, so a
27
+ * mismatched `type`/field pair (`BINDING_KEY` with `fn`, or `FUNCTION` with `key`) is a compile
28
+ * error there rather than a runtime surprise later, inside a `queueMicrotask` where nobody is
29
+ * watching.
30
+ */
31
+ class EventHandlerTypes {
32
+ /** `handler.key` is resolved from the container on every retry attempt - a rebind reaches an attempt already in flight. */
33
+ static { this.BINDING_KEY = 'binding-key'; }
34
+ /** `handler.fn` is invoked directly as a captured closure - there is nothing to rebind, so every attempt in a retry window calls the exact function registered here. */
35
+ static { this.FUNCTION = 'function'; }
36
+ static { this.SCHEME_SET = new Set([this.BINDING_KEY, this.FUNCTION]); }
37
+ static isValid(value) {
38
+ return this.SCHEME_SET.has(value);
39
+ }
40
+ }
41
+ exports.EventHandlerTypes = EventHandlerTypes;
9
42
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":";;;AAAA,MAAa,kBAAkB;aACb,iBAAY,GAAG,CAAC,CAAC;aACjB,kBAAa,GAAG,GAAG,CAAC;;AAFtC,gDAGC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":";;;AAEA,MAAa,kBAAkB;aACb,iBAAY,GAAG,CAAC,CAAC;aACjB,kBAAa,GAAG,GAAG,CAAC;IAEpC;;;;;OAKG;aACa,yBAAoB,GAAG,EAAE,CAAC;IAE1C;;;;;;OAMG;aACa,wBAAmB,GAAG,MAAM,CAAC;;AAnB/C,gDAoBC;AAED;;;;;;GAMG;AACH,MAAa,iBAAiB;IAC5B,2HAA2H;aAC3G,gBAAW,GAAG,aAAa,CAAC;IAE5C,wKAAwK;aACxJ,aAAQ,GAAG,UAAU,CAAC;aAEtB,eAAU,GAAG,IAAI,GAAG,CAAS,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEhF,MAAM,CAAC,OAAO,CAAC,KAAa;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;;AAXH,8CAYC"}
@@ -1,3 +1,5 @@
1
+ import type { ValueOrPromise } from '@venizia/ignis-helpers/common';
2
+ import { EventHandlerTypes } from './constants';
1
3
  /** One occurrence of a named domain event, decoupled from whatever publishes or handles it. */
2
4
  export interface IDomainEvent<TPayload = unknown> {
3
5
  name: string;
@@ -6,7 +8,41 @@ export interface IDomainEvent<TPayload = unknown> {
6
8
  traceId?: string;
7
9
  }
8
10
  /**
9
- * Handles one `IDomainEvent`.
11
+ * Per-registration retry override for `EventBus.register`. Both fields must be positive integers,
12
+ * and are bounded by `EventDispatchRetry.MAX_ATTEMPTS_CEILING` / `MAX_TOTAL_WINDOW_MS` - a value
13
+ * outside either throws at `register()`, never clamps.
14
+ */
15
+ export interface IEventHandlerRetryOptions {
16
+ /** Default `EventDispatchRetry.MAX_ATTEMPTS`. */
17
+ maxAttempts?: number;
18
+ /** First backoff delay in ms; exponential growth is computed from it. Default `EventDispatchRetry.BASE_DELAY_MS`. */
19
+ baseDelayMs?: number;
20
+ }
21
+ /** A handler callback - synchronous or asynchronous, `EventBus` awaits either the same way. */
22
+ export type TEventHandlerFunction<TPayload = unknown> = (opts: {
23
+ event: IDomainEvent<TPayload>;
24
+ }) => ValueOrPromise<void>;
25
+ /** `register`'s binding-key handler shape: resolved from the container by `key` on every retry attempt. */
26
+ export interface IEventHandlerBindingKeyReference {
27
+ type: typeof EventHandlerTypes.BINDING_KEY;
28
+ key: string;
29
+ }
30
+ /** `register`'s function handler shape: `fn` is invoked directly, captured as a closure - see `TEventHandlerReference`. */
31
+ export interface IEventHandlerFunctionReference<TPayload = unknown> {
32
+ type: typeof EventHandlerTypes.FUNCTION;
33
+ fn: TEventHandlerFunction<TPayload>;
34
+ }
35
+ /**
36
+ * The two shapes `EventBus.register`'s `handler` accepts, tagged by `type` so the caller states
37
+ * which rather than the bus inferring it from whichever field is present. Only `BINDING_KEY` shares
38
+ * `IEventHandler`'s rebind property; see its doc.
39
+ */
40
+ export type TEventHandlerReference<TPayload = unknown> = IEventHandlerBindingKeyReference | IEventHandlerFunctionReference<TPayload>;
41
+ /**
42
+ * Handles one `IDomainEvent`. Implemented by whatever is bound into the container under
43
+ * `register`'s `{ type: EventHandlerTypes.BINDING_KEY, key }` form - see `TEventHandlerReference`
44
+ * for the `FUNCTION` form, which does not implement this interface and does not share its rebind
45
+ * property.
10
46
  *
11
47
  * MUST be idempotent. The bus retries a failed handler, so delivery is at-least-once: one that
12
48
  * half-succeeds then throws runs again from the top, re-applying whatever already landed. Three
@@ -16,11 +52,13 @@ export interface IDomainEvent<TPayload = unknown> {
16
52
  * audit row, which simply gains a duplicate - corrupting the record used to diagnose the retry.
17
53
  *
18
54
  * Resolved from the container by binding key at dispatch time, never captured as a direct reference,
19
- * so rebinding the key takes effect on the next attempt - including one already in flight.
55
+ * so rebinding the key takes effect on the next attempt - including one already in flight. A
56
+ * `FUNCTION`-form handler does NOT have this property: `fn` is a captured closure, so every attempt
57
+ * in a long retry window calls the exact function registered at startup.
20
58
  */
21
59
  export interface IEventHandler<TEvent extends IDomainEvent = IDomainEvent> {
22
60
  handle(opts: {
23
61
  event: TEvent;
24
- }): Promise<void>;
62
+ }): ValueOrPromise<void>;
25
63
  }
26
64
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/types.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,WAAW,YAAY,CAAC,QAAQ,GAAG,OAAO;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,YAAY,GAAG,YAAY;IACvE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,+FAA+F;AAC/F,MAAM,WAAW,YAAY,CAAC,QAAQ,GAAG,OAAO;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,qHAAqH;IACrH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+FAA+F;AAC/F,MAAM,MAAM,qBAAqB,CAAC,QAAQ,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE;IAC7D,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;CAC/B,KAAK,cAAc,CAAC,IAAI,CAAC,CAAC;AAE3B,2GAA2G;AAC3G,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,OAAO,iBAAiB,CAAC,WAAW,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2HAA2H;AAC3H,MAAM,WAAW,8BAA8B,CAAC,QAAQ,GAAG,OAAO;IAChE,IAAI,EAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC;IACxC,EAAE,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;CACrC;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,CAAC,QAAQ,GAAG,OAAO,IACnD,gCAAgC,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,YAAY,GAAG,YAAY;IACvE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;CACvD"}
@@ -1,21 +1,52 @@
1
1
  import type { Container } from '../../helpers/inversion/container';
2
2
  import { BaseHelper } from '@venizia/ignis-helpers/core';
3
+ import type { IEventHandlerRetryOptions, TEventHandlerReference } from './common/types';
3
4
  /** In-process, fire-and-forget domain event bus. `TPayloadMap` keys the event names, so a wrong name
4
- * or payload shape is a compile error. Delivery is always async and retry is fixed - there is no
5
- * knob for either, so "published" guarantees the same thing at every call site. Retry makes delivery
6
- * at-least-once: handlers must be idempotent, see `IEventHandler`. */
5
+ * or payload shape is a compile error. Delivery is always async. Retry timing is a property of the
6
+ * handler's own failure mode, not of the event, so `register` may tune it per registration. But
7
+ * nobody awaits a fire-and-forget dispatch, so an unbounded window would let one event hold a
8
+ * handler - and whatever it holds open, e.g. a database connection - for an unbounded time with no
9
+ * one to report it. What the bus guarantees instead: a bounded MAXIMUM time a single dispatch can
10
+ * occupy, enforced as a hard ceiling at `register()` - see `EventDispatchRetry`. Retry makes
11
+ * delivery at-least-once: handlers must be idempotent, see `IEventHandler`. */
7
12
  export declare class EventBus<TPayloadMap extends object> extends BaseHelper {
8
13
  private readonly container;
9
14
  /** `register` appends, never replaces - two handlers may share an event name, and replacing would
10
15
  * drop the first with no way for the caller to notice. */
11
- private readonly handlerBindingKeysByName;
16
+ private readonly registrationsByName;
12
17
  constructor(opts: {
13
18
  scope?: string;
14
19
  container: Container;
15
20
  });
21
+ /** The pre-jitter total of every inter-attempt delay `maxAttempts`/`baseDelayMs` would produce -
22
+ * jitter (always on, see `dispatch`) only ever shrinks a delay, so this is a true upper bound. */
23
+ private static computeTotalWindowMs;
24
+ /** Loud rejection, never a silent clamp: a caller who believes a number the bus does not honour is
25
+ * worse off than one who sees the ceiling at boot. */
26
+ private static assertValidRetry;
27
+ /**
28
+ * Turns `handler` into a uniform invoker plus a description for the exhaustion log line.
29
+ * `BINDING_KEY` resolves through the container INSIDE the returned closure, so every call re-reads
30
+ * the current binding; `FUNCTION` calls `fn` directly, so the closure IS the resolution - there is
31
+ * nothing left to re-read on a later attempt. The tag (`handler.type`) is what this switches on,
32
+ * not which field happens to be present - see `EventHandlerTypes`' doc.
33
+ */
34
+ private static buildHandlerInvoker;
35
+ /**
36
+ * `retry` is optional and per REGISTRATION, not per publish: the right window belongs to the
37
+ * handler's own failure mode, and two handlers on the same event name may each pick their own.
38
+ * Omitting it reproduces today's `EventDispatchRetry` defaults exactly. Both `maxAttempts` and the
39
+ * total backoff window it implies are bounded - see `EventDispatchRetry` - and exceeding either
40
+ * throws here, at boot where a human sees it, rather than being silently clamped at dispatch time.
41
+ */
16
42
  register<K extends keyof TPayloadMap & string>(opts: {
17
43
  name: K;
18
- handlerBindingKey: string;
44
+ /** A `BINDING_KEY` reference re-resolves through the container on every retry attempt, so a
45
+ * rebind reaches a dispatch already in flight. A `FUNCTION` reference is captured as-is: a
46
+ * rebind has nothing to reach, and every attempt in a long retry window calls the exact `fn`
47
+ * registered here. */
48
+ handler: TEventHandlerReference<TPayloadMap[K]>;
49
+ retry?: IEventHandlerRetryOptions;
19
50
  }): void;
20
51
  /**
21
52
  * Never blocks and never throws back to the caller: dispatch runs outside this call's flow via
@@ -28,9 +59,15 @@ export declare class EventBus<TPayloadMap extends object> extends BaseHelper {
28
59
  traceId?: string;
29
60
  }): void;
30
61
  /**
31
- * Fixed 3 attempts / ~100ms exponential backoff, no jitter - see `EventDispatchRetry`. The
32
- * handler is resolved fresh from the container on every attempt rather than once up front, so a
33
- * rebind takes effect on the very next attempt of a dispatch already in flight.
62
+ * Attempts/backoff come from the registration (`EventDispatchRetry`'s defaults when omitted),
63
+ * always with full jitter - `RetryJitterModes.FULL` decorrelates a shared-resource pile-up hardest,
64
+ * so many handlers retrying the same lock do not collide on the same instant a second and third
65
+ * time. `invokeHandler` already encodes whether that re-resolves (`BINDING_KEY`) or was captured
66
+ * once (`FUNCTION`) - see `buildHandlerInvoker` - so this method calls it uniformly. A handler that
67
+ * throws synchronously is caught exactly like one that returns a rejected promise: `execution`
68
+ * here is itself `async`, and JS converts a synchronous throw inside an async function body into a
69
+ * rejection of that function's own promise - `RetryHelper.executeWithRetry`'s attempt loop never
70
+ * sees the difference.
34
71
  *
35
72
  * `RetryHelper.executeWithRetry` is used without its own `logger` - its internal per-attempt/exhaustion
36
73
  * logging knows nothing about the event name or `traceId`, so it cannot be the trace anyone
@@ -1 +1 @@
1
- {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EACL,UAAU,EAKX,MAAM,6BAA6B,CAAC;AAKrC;;;sEAGsE;AACtE,qBAAa,QAAQ,CAAC,WAAW,SAAS,MAAM,CAAE,SAAQ,UAAU;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC;8DAC0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAwB;gBAErD,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE;IAM1D,QAAQ,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QACnD,IAAI,EAAE,CAAC,CAAC;QACR,iBAAiB,EAAE,MAAM,CAAC;KAC3B,GAAG,IAAI;IAkBR;;;;OAIG;IACH,OAAO,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QAClD,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI;IAiCR;;;;;;;;OAQG;YACW,QAAQ;CAmCvB"}
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,EACL,UAAU,EAKX,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAGV,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,gBAAgB,CAAC;AAexB;;;;;;;+EAO+E;AAC/E,qBAAa,QAAQ,CAAC,WAAW,SAAS,MAAM,CAAE,SAAQ,UAAU;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC;8DAC0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA4C;gBAEpE,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE;IAM1D;sGACkG;IAClG,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAkBnC;0DACsD;IACtD,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiC/B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAkDlC;;;;;;OAMG;IACH,QAAQ,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QACnD,IAAI,EAAE,CAAC,CAAC;QACR;;;8BAGsB;QACtB,OAAO,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,KAAK,CAAC,EAAE,yBAAyB,CAAC;KACnC,GAAG,IAAI;IAmCR;;;;OAIG;IACH,OAAO,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QAClD,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI;IAiCR;;;;;;;;;;;;;;OAcG;YACW,QAAQ;CAmCvB"}
@@ -8,28 +8,142 @@ const core_1 = require("@venizia/ignis-helpers/core");
8
8
  const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
9
9
  const constants_1 = require("./common/constants");
10
10
  /** In-process, fire-and-forget domain event bus. `TPayloadMap` keys the event names, so a wrong name
11
- * or payload shape is a compile error. Delivery is always async and retry is fixed - there is no
12
- * knob for either, so "published" guarantees the same thing at every call site. Retry makes delivery
13
- * at-least-once: handlers must be idempotent, see `IEventHandler`. */
11
+ * or payload shape is a compile error. Delivery is always async. Retry timing is a property of the
12
+ * handler's own failure mode, not of the event, so `register` may tune it per registration. But
13
+ * nobody awaits a fire-and-forget dispatch, so an unbounded window would let one event hold a
14
+ * handler - and whatever it holds open, e.g. a database connection - for an unbounded time with no
15
+ * one to report it. What the bus guarantees instead: a bounded MAXIMUM time a single dispatch can
16
+ * occupy, enforced as a hard ceiling at `register()` - see `EventDispatchRetry`. Retry makes
17
+ * delivery at-least-once: handlers must be idempotent, see `IEventHandler`. */
14
18
  class EventBus extends core_1.BaseHelper {
15
19
  constructor(opts) {
16
20
  super({ scope: opts.scope ?? EventBus.name });
17
21
  this.container = opts.container;
18
- this.handlerBindingKeysByName = new Map();
22
+ this.registrationsByName = new Map();
19
23
  }
24
+ /** The pre-jitter total of every inter-attempt delay `maxAttempts`/`baseDelayMs` would produce -
25
+ * jitter (always on, see `dispatch`) only ever shrinks a delay, so this is a true upper bound. */
26
+ static computeTotalWindowMs(opts) {
27
+ const { maxAttempts, baseDelayMs } = opts;
28
+ let totalWindowMs = 0;
29
+ for (let attempt = 1; attempt < maxAttempts; attempt++) {
30
+ totalWindowMs += core_1.RetryHelper.computeBackoffDelayMs({
31
+ attempt,
32
+ backoff: {
33
+ strategy: core_1.RetryBackoffStrategies.EXPONENTIAL,
34
+ initialDelayMs: baseDelayMs,
35
+ jitter: core_1.RetryJitterModes.NONE,
36
+ },
37
+ });
38
+ }
39
+ return totalWindowMs;
40
+ }
41
+ /** Loud rejection, never a silent clamp: a caller who believes a number the bus does not honour is
42
+ * worse off than one who sees the ceiling at boot. */
43
+ static assertValidRetry(opts) {
44
+ const { name, maxAttempts, baseDelayMs } = opts;
45
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
46
+ throw (0, core_1.getError)({
47
+ message: `[EventBus][register] retry.maxAttempts must be a positive integer | name: ${name} | Got: ${maxAttempts}`,
48
+ });
49
+ }
50
+ if (!Number.isInteger(baseDelayMs) || baseDelayMs < 1) {
51
+ throw (0, core_1.getError)({
52
+ message: `[EventBus][register] retry.baseDelayMs must be a positive integer | name: ${name} | Got: ${baseDelayMs}`,
53
+ });
54
+ }
55
+ if (maxAttempts > constants_1.EventDispatchRetry.MAX_ATTEMPTS_CEILING) {
56
+ throw (0, core_1.getError)({
57
+ message: `[EventBus][register] retry.maxAttempts exceeds the ceiling | name: ${name} | Got: ${maxAttempts} | Ceiling: ${constants_1.EventDispatchRetry.MAX_ATTEMPTS_CEILING} | Lower retry.maxAttempts`,
58
+ });
59
+ }
60
+ const totalWindowMs = EventBus.computeTotalWindowMs({ maxAttempts, baseDelayMs });
61
+ if (totalWindowMs > constants_1.EventDispatchRetry.MAX_TOTAL_WINDOW_MS) {
62
+ throw (0, core_1.getError)({
63
+ message: `[EventBus][register] retry window exceeds the ceiling | name: ${name} | Got: ${totalWindowMs}ms | Ceiling: ${constants_1.EventDispatchRetry.MAX_TOTAL_WINDOW_MS}ms | Lower retry.maxAttempts or retry.baseDelayMs`,
64
+ });
65
+ }
66
+ }
67
+ /**
68
+ * Turns `handler` into a uniform invoker plus a description for the exhaustion log line.
69
+ * `BINDING_KEY` resolves through the container INSIDE the returned closure, so every call re-reads
70
+ * the current binding; `FUNCTION` calls `fn` directly, so the closure IS the resolution - there is
71
+ * nothing left to re-read on a later attempt. The tag (`handler.type`) is what this switches on,
72
+ * not which field happens to be present - see `EventHandlerTypes`' doc.
73
+ */
74
+ static buildHandlerInvoker(opts) {
75
+ const { container, handler, name } = opts;
76
+ if ((0, isEmpty_1.default)(handler)) {
77
+ throw (0, core_1.getError)({
78
+ message: `[EventBus][register] Invalid handler | name: ${name} | Got: ${handler}`,
79
+ });
80
+ }
81
+ switch (handler.type) {
82
+ case constants_1.EventHandlerTypes.BINDING_KEY: {
83
+ const { key } = handler;
84
+ if ((0, isEmpty_1.default)(key)) {
85
+ throw (0, core_1.getError)({
86
+ message: `[EventBus][register] Invalid handler.key | name: ${name} | Got: ${key}`,
87
+ });
88
+ }
89
+ return {
90
+ invokeHandler: ({ event }) => container.get({ key }).handle({ event }),
91
+ description: `binding-key:${key}`,
92
+ };
93
+ }
94
+ case constants_1.EventHandlerTypes.FUNCTION: {
95
+ const { fn } = handler;
96
+ if (typeof fn !== 'function') {
97
+ throw (0, core_1.getError)({
98
+ message: `[EventBus][register] Invalid handler.fn | name: ${name} | Expected a function | Got: ${typeof fn}`,
99
+ });
100
+ }
101
+ return {
102
+ invokeHandler: ({ event }) => fn({ event }),
103
+ description: `function:${fn.name || 'anonymous'}`,
104
+ };
105
+ }
106
+ default: {
107
+ throw (0, core_1.getError)({
108
+ message: `[EventBus][register] Unknown handler.type | name: ${name} | Expected one of: ${[...constants_1.EventHandlerTypes.SCHEME_SET].join(', ')} | Got: ${handler.type}`,
109
+ });
110
+ }
111
+ }
112
+ }
113
+ /**
114
+ * `retry` is optional and per REGISTRATION, not per publish: the right window belongs to the
115
+ * handler's own failure mode, and two handlers on the same event name may each pick their own.
116
+ * Omitting it reproduces today's `EventDispatchRetry` defaults exactly. Both `maxAttempts` and the
117
+ * total backoff window it implies are bounded - see `EventDispatchRetry` - and exceeding either
118
+ * throws here, at boot where a human sees it, rather than being silently clamped at dispatch time.
119
+ */
20
120
  register(opts) {
21
- const { name, handlerBindingKey } = opts;
22
- if ((0, isEmpty_1.default)(name) || (0, isEmpty_1.default)(handlerBindingKey)) {
121
+ const { name, handler, retry } = opts;
122
+ if ((0, isEmpty_1.default)(name)) {
23
123
  throw (0, core_1.getError)({
24
- message: `[EventBus][register] Invalid registration | name: ${String(name)} | handlerBindingKey: ${handlerBindingKey}`,
124
+ message: `[EventBus][register] Invalid registration | name: ${String(name)}`,
25
125
  });
26
126
  }
27
- const existing = this.handlerBindingKeysByName.get(name);
127
+ const maxAttempts = retry?.maxAttempts ?? constants_1.EventDispatchRetry.MAX_ATTEMPTS;
128
+ const baseDelayMs = retry?.baseDelayMs ?? constants_1.EventDispatchRetry.BASE_DELAY_MS;
129
+ EventBus.assertValidRetry({ name, maxAttempts, baseDelayMs });
130
+ const { invokeHandler, description } = EventBus.buildHandlerInvoker({
131
+ container: this.container,
132
+ handler,
133
+ name,
134
+ });
135
+ const registration = {
136
+ invokeHandler,
137
+ description,
138
+ maxAttempts,
139
+ baseDelayMs,
140
+ };
141
+ const existing = this.registrationsByName.get(name);
28
142
  if (existing) {
29
- existing.push(handlerBindingKey);
143
+ existing.push(registration);
30
144
  return;
31
145
  }
32
- this.handlerBindingKeysByName.set(name, [handlerBindingKey]);
146
+ this.registrationsByName.set(name, [registration]);
33
147
  }
34
148
  /**
35
149
  * Never blocks and never throws back to the caller: dispatch runs outside this call's flow via
@@ -44,55 +158,61 @@ class EventBus extends core_1.BaseHelper {
44
158
  occurredAt: new Date().toISOString(),
45
159
  traceId,
46
160
  };
47
- const handlerBindingKeys = this.handlerBindingKeysByName.get(name);
48
- if (!handlerBindingKeys?.length) {
161
+ const registrations = this.registrationsByName.get(name);
162
+ if (!registrations?.length) {
49
163
  // A typo is already a compile error, so at runtime this only means nobody is listening yet -
50
164
  // a legitimate state on a fire-and-forget bus, not an incident.
51
165
  this.logger.debug('[publish] No handler registered | name: %s | traceId: %s', name, traceId);
52
166
  return;
53
167
  }
54
- for (const handlerBindingKey of handlerBindingKeys) {
168
+ for (const registration of registrations) {
55
169
  queueMicrotask(() => {
56
170
  // `dispatch` catches every failure path itself and never rejects - this `.catch` is an
57
171
  // unreachable backstop, kept (and logged) rather than left floating, for the day it isn't.
58
- this.dispatch({ event, handlerBindingKey }).catch((error) => {
172
+ this.dispatch({ event, registration }).catch((error) => {
59
173
  this.logger.error('[publish] Unexpected dispatch failure | name: %s | Error: %s', event.name, error);
60
174
  });
61
175
  });
62
176
  }
63
177
  }
64
178
  /**
65
- * Fixed 3 attempts / ~100ms exponential backoff, no jitter - see `EventDispatchRetry`. The
66
- * handler is resolved fresh from the container on every attempt rather than once up front, so a
67
- * rebind takes effect on the very next attempt of a dispatch already in flight.
179
+ * Attempts/backoff come from the registration (`EventDispatchRetry`'s defaults when omitted),
180
+ * always with full jitter - `RetryJitterModes.FULL` decorrelates a shared-resource pile-up hardest,
181
+ * so many handlers retrying the same lock do not collide on the same instant a second and third
182
+ * time. `invokeHandler` already encodes whether that re-resolves (`BINDING_KEY`) or was captured
183
+ * once (`FUNCTION`) - see `buildHandlerInvoker` - so this method calls it uniformly. A handler that
184
+ * throws synchronously is caught exactly like one that returns a rejected promise: `execution`
185
+ * here is itself `async`, and JS converts a synchronous throw inside an async function body into a
186
+ * rejection of that function's own promise - `RetryHelper.executeWithRetry`'s attempt loop never
187
+ * sees the difference.
68
188
  *
69
189
  * `RetryHelper.executeWithRetry` is used without its own `logger` - its internal per-attempt/exhaustion
70
190
  * logging knows nothing about the event name or `traceId`, so it cannot be the trace anyone
71
191
  * relies on. The one line below, logged only on final failure, is.
72
192
  */
73
193
  async dispatch(opts) {
74
- const { event, handlerBindingKey } = opts;
194
+ const { event, registration } = opts;
195
+ const { invokeHandler, description, maxAttempts, baseDelayMs } = registration;
75
196
  let lastAttempt = 0;
76
197
  try {
77
198
  await core_1.RetryHelper.executeWithRetry({
78
199
  operation: `EventBus.dispatch:${event.name}`,
79
- maxAttempts: constants_1.EventDispatchRetry.MAX_ATTEMPTS,
200
+ maxAttempts,
80
201
  backoff: {
81
202
  strategy: core_1.RetryBackoffStrategies.EXPONENTIAL,
82
- initialDelayMs: constants_1.EventDispatchRetry.BASE_DELAY_MS,
83
- jitter: core_1.RetryJitterModes.NONE,
203
+ initialDelayMs: baseDelayMs,
204
+ jitter: core_1.RetryJitterModes.FULL,
84
205
  },
85
206
  execution: async ({ attempt }) => {
86
207
  lastAttempt = attempt;
87
- const handler = this.container.get({ key: handlerBindingKey });
88
- await handler.handle({ event });
208
+ await invokeHandler({ event });
89
209
  },
90
210
  });
91
211
  }
92
212
  catch (error) {
93
213
  // The only trace this failure leaves: it is caught here and never reaches the publisher, so
94
214
  // the event name, traceId and attempt count all have to be on this one line.
95
- this.logger.error('[dispatch] Handler exhausted retries | name: %s | traceId: %s | attempts: %d | handlerBindingKey: %s | Error: %s', event.name, event.traceId, lastAttempt, handlerBindingKey, error);
215
+ this.logger.error('[dispatch] Handler exhausted retries | name: %s | traceId: %s | attempts: %d | handler: %s | Error: %s', event.name, event.traceId, lastAttempt, description, error);
96
216
  }
97
217
  }
98
218
  }
@@ -1 +1 @@
1
- {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,26 @@ export type NumberIdType = number;
21
21
  export type StringIdType = string;
22
22
  export type BigIntIdType = bigint;
23
23
  export type IdType = NumberIdType | StringIdType | BigIntIdType;
24
+ declare const entityIdBrand: unique symbol;
25
+ /**
26
+ * A string id a plain `string` cannot be assigned to, so passing a name, code or email where an id
27
+ * belongs is a compile error. Opt a column in with `.$type<TEntityId>()`.
28
+ *
29
+ * IT VALIDATES NOTHING. `toEntityId` is a cast with a non-empty check; the value is making the
30
+ * laundering VISIBLE at each boundary, not proving the string is a real id.
31
+ *
32
+ * The cost is not optional: Drizzle derives `$inferInsert` and `$inferSelect` from the same field,
33
+ * so a branded column rejects every literal - `create({ data: { merchantId: 'M1' } })`, seeds,
34
+ * fixtures, path params - until each converts. A union with `string` would restore those but makes
35
+ * a plain `string` assignable again, which erases the whole guarantee. Measured, not assumed.
36
+ */
37
+ export type TEntityId = string & {
38
+ readonly [entityIdBrand]: never;
39
+ };
40
+ /** The only way into `TEntityId`. Rejects an empty string - an id that is `''` collapses a `where` to no condition. */
41
+ export declare const toEntityId: (opts: {
42
+ value: string;
43
+ }) => TEntityId;
24
44
  /** Path-param id shape every entity family resolves to (`AbstractEntity.getIdType()`). */
25
45
  export type TIdSchemaType = 'number' | 'string';
26
46
  export declare const idParamsSchema: (opts?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAItC;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;iBA6BpB,CAAC;AAEL,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEhE,0FAA0F;AAC1F,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD,eAAO,MAAM,cAAc,GAAI,OAAO;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE;;;;iBAkC9D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM;IACrD,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;CAMA,CAAC;AAEF,mCAAmC;AACnC,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAAC;AAEF,4CAA4C;AAC5C,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,SAAS,gBAAgB,GAAG,SAAS,IAAI;IACpF,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,CAAC;CACb,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,aAAa,SAAS,CAAC,CAAC,OAAO,EAC/B,YAAY,SAAS,gBAAgB,GAAG,SAAS,GAAG,SAAS,EAE7D,MAAM,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAcrD,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GACxE,GAAG,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,GACzC,CAAC,CAAC;AAEN,KAAK,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,IAAI;KAC5C,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAC1F,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GACZ,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,0SAW7D,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAItC;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;iBA6BpB,CAAC;AAEL,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEhE,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAErE,uHAAuH;AACvH,eAAO,MAAM,UAAU,GAAI,MAAM;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,KAAG,SAMpD,CAAC;AAEF,0FAA0F;AAC1F,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD,eAAO,MAAM,cAAc,GAAI,OAAO;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE;;;;iBAkC9D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM;IACrD,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;CAMA,CAAC;AAEF,mCAAmC;AACnC,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAAC;AAEF,4CAA4C;AAC5C,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,SAAS,gBAAgB,GAAG,SAAS,IAAI;IACpF,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,CAAC;CACb,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,aAAa,SAAS,CAAC,CAAC,OAAO,EAC/B,YAAY,SAAS,gBAAgB,GAAG,SAAS,GAAG,SAAS,EAE7D,MAAM,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAcrD,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GACxE,GAAG,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,GACzC,CAAC,CAAC;AAEN,KAAK,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,IAAI;KAC5C,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAC1F,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GACZ,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,0SAW7D,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.snakeToCamel = exports.jsonResponse = exports.jsonContent = exports.idParamsSchema = exports.ErrorSchema = void 0;
3
+ exports.snakeToCamel = exports.jsonResponse = exports.jsonContent = exports.idParamsSchema = exports.toEntityId = exports.ErrorSchema = void 0;
4
4
  const zod_openapi_1 = require("@hono/zod-openapi");
5
5
  const core_1 = require("@venizia/ignis-helpers/core");
6
6
  const common_1 = require("@venizia/ignis-helpers/common");
@@ -40,6 +40,14 @@ exports.ErrorSchema = zod_openapi_1.z
40
40
  details: { url: 'http://localhost:3000/categories', path: '/categories' },
41
41
  },
42
42
  });
43
+ /** The only way into `TEntityId`. Rejects an empty string - an id that is `''` collapses a `where` to no condition. */
44
+ const toEntityId = (opts) => {
45
+ if (opts.value.length === 0) {
46
+ throw (0, core_1.getError)({ message: '[toEntityId] Refusing an empty string as an entity id' });
47
+ }
48
+ return opts.value;
49
+ };
50
+ exports.toEntityId = toEntityId;
43
51
  const idParamsSchema = (opts) => {
44
52
  const { idType = 'number' } = opts ?? {};
45
53
  switch (idType) {
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,37 @@
1
+ import type { TConstValue } from '@venizia/ignis-helpers/common';
1
2
  export declare class EventDispatchRetry {
2
3
  static readonly MAX_ATTEMPTS = 3;
3
4
  static readonly BASE_DELAY_MS = 100;
5
+ /**
6
+ * Ceiling on `register`'s `retry.maxAttempts`. Dispatch is fire-and-forget - nobody awaits it - so
7
+ * an attempt count high enough to matter is already high enough to hammer a struggling downstream
8
+ * resource attempt after attempt. Twice the highest count any known consumer has asked for (5)
9
+ * leaves room to tune without permitting an attempt storm.
10
+ */
11
+ static readonly MAX_ATTEMPTS_CEILING = 10;
12
+ /**
13
+ * Ceiling, in ms, on the total backoff window `register`'s `retry` can produce (the sum of every
14
+ * inter-attempt delay, computed without jitter since jitter only shrinks it). Matches
15
+ * `RetryHelper`'s own default cap on a SINGLE delay: a dispatch holds a handler's resources - e.g.
16
+ * a database connection - for its entire retry window, so the sum across every attempt gets the
17
+ * same "unreasonable beyond this" line the framework already draws for one attempt.
18
+ */
19
+ static readonly MAX_TOTAL_WINDOW_MS = 30000;
4
20
  }
21
+ /**
22
+ * Tag for `EventBus.register`'s `handler` union (`TEventHandlerReference`). The tag makes the
23
+ * caller's choice explicit at the call site instead of implicit in whichever field is present, so a
24
+ * mismatched `type`/field pair (`BINDING_KEY` with `fn`, or `FUNCTION` with `key`) is a compile
25
+ * error there rather than a runtime surprise later, inside a `queueMicrotask` where nobody is
26
+ * watching.
27
+ */
28
+ export declare class EventHandlerTypes {
29
+ /** `handler.key` is resolved from the container on every retry attempt - a rebind reaches an attempt already in flight. */
30
+ static readonly BINDING_KEY = "binding-key";
31
+ /** `handler.fn` is invoked directly as a captured closure - there is nothing to rebind, so every attempt in a retry window calls the exact function registered here. */
32
+ static readonly FUNCTION = "function";
33
+ static readonly SCHEME_SET: Set<string>;
34
+ static isValid(value: string): value is TEventHandlerType;
35
+ }
36
+ export type TEventHandlerType = TConstValue<typeof EventHandlerTypes>;
5
37
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,aAAa,OAAO;CACrC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,aAAa,OAAO;IAEpC;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,oBAAoB,MAAM;IAE1C;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,mBAAmB,SAAU;CAC9C;AAED;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC5B,2HAA2H;IAC3H,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;IAE5C,wKAAwK;IACxK,MAAM,CAAC,QAAQ,CAAC,QAAQ,cAAc;IAEtC,MAAM,CAAC,QAAQ,CAAC,UAAU,cAAsD;IAEhF,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,iBAAiB;CAG1D;AAED,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
@@ -1,5 +1,37 @@
1
1
  export class EventDispatchRetry {
2
2
  static { this.MAX_ATTEMPTS = 3; }
3
3
  static { this.BASE_DELAY_MS = 100; }
4
+ /**
5
+ * Ceiling on `register`'s `retry.maxAttempts`. Dispatch is fire-and-forget - nobody awaits it - so
6
+ * an attempt count high enough to matter is already high enough to hammer a struggling downstream
7
+ * resource attempt after attempt. Twice the highest count any known consumer has asked for (5)
8
+ * leaves room to tune without permitting an attempt storm.
9
+ */
10
+ static { this.MAX_ATTEMPTS_CEILING = 10; }
11
+ /**
12
+ * Ceiling, in ms, on the total backoff window `register`'s `retry` can produce (the sum of every
13
+ * inter-attempt delay, computed without jitter since jitter only shrinks it). Matches
14
+ * `RetryHelper`'s own default cap on a SINGLE delay: a dispatch holds a handler's resources - e.g.
15
+ * a database connection - for its entire retry window, so the sum across every attempt gets the
16
+ * same "unreasonable beyond this" line the framework already draws for one attempt.
17
+ */
18
+ static { this.MAX_TOTAL_WINDOW_MS = 30_000; }
19
+ }
20
+ /**
21
+ * Tag for `EventBus.register`'s `handler` union (`TEventHandlerReference`). The tag makes the
22
+ * caller's choice explicit at the call site instead of implicit in whichever field is present, so a
23
+ * mismatched `type`/field pair (`BINDING_KEY` with `fn`, or `FUNCTION` with `key`) is a compile
24
+ * error there rather than a runtime surprise later, inside a `queueMicrotask` where nobody is
25
+ * watching.
26
+ */
27
+ export class EventHandlerTypes {
28
+ /** `handler.key` is resolved from the container on every retry attempt - a rebind reaches an attempt already in flight. */
29
+ static { this.BINDING_KEY = 'binding-key'; }
30
+ /** `handler.fn` is invoked directly as a captured closure - there is nothing to rebind, so every attempt in a retry window calls the exact function registered here. */
31
+ static { this.FUNCTION = 'function'; }
32
+ static { this.SCHEME_SET = new Set([this.BINDING_KEY, this.FUNCTION]); }
33
+ static isValid(value) {
34
+ return this.SCHEME_SET.has(value);
35
+ }
4
36
  }
5
37
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAkB;aACb,iBAAY,GAAG,CAAC,CAAC;aACjB,kBAAa,GAAG,GAAG,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../src/base/events/common/constants.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,kBAAkB;aACb,iBAAY,GAAG,CAAC,CAAC;aACjB,kBAAa,GAAG,GAAG,CAAC;IAEpC;;;;;OAKG;aACa,yBAAoB,GAAG,EAAE,CAAC;IAE1C;;;;;;OAMG;aACa,wBAAmB,GAAG,MAAM,CAAC;;AAG/C;;;;;;GAMG;AACH,MAAM,OAAO,iBAAiB;IAC5B,2HAA2H;aAC3G,gBAAW,GAAG,aAAa,CAAC;IAE5C,wKAAwK;aACxJ,aAAQ,GAAG,UAAU,CAAC;aAEtB,eAAU,GAAG,IAAI,GAAG,CAAS,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEhF,MAAM,CAAC,OAAO,CAAC,KAAa;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC"}
@@ -1,3 +1,5 @@
1
+ import type { ValueOrPromise } from '@venizia/ignis-helpers/common';
2
+ import { EventHandlerTypes } from './constants.js';
1
3
  /** One occurrence of a named domain event, decoupled from whatever publishes or handles it. */
2
4
  export interface IDomainEvent<TPayload = unknown> {
3
5
  name: string;
@@ -6,7 +8,41 @@ export interface IDomainEvent<TPayload = unknown> {
6
8
  traceId?: string;
7
9
  }
8
10
  /**
9
- * Handles one `IDomainEvent`.
11
+ * Per-registration retry override for `EventBus.register`. Both fields must be positive integers,
12
+ * and are bounded by `EventDispatchRetry.MAX_ATTEMPTS_CEILING` / `MAX_TOTAL_WINDOW_MS` - a value
13
+ * outside either throws at `register()`, never clamps.
14
+ */
15
+ export interface IEventHandlerRetryOptions {
16
+ /** Default `EventDispatchRetry.MAX_ATTEMPTS`. */
17
+ maxAttempts?: number;
18
+ /** First backoff delay in ms; exponential growth is computed from it. Default `EventDispatchRetry.BASE_DELAY_MS`. */
19
+ baseDelayMs?: number;
20
+ }
21
+ /** A handler callback - synchronous or asynchronous, `EventBus` awaits either the same way. */
22
+ export type TEventHandlerFunction<TPayload = unknown> = (opts: {
23
+ event: IDomainEvent<TPayload>;
24
+ }) => ValueOrPromise<void>;
25
+ /** `register`'s binding-key handler shape: resolved from the container by `key` on every retry attempt. */
26
+ export interface IEventHandlerBindingKeyReference {
27
+ type: typeof EventHandlerTypes.BINDING_KEY;
28
+ key: string;
29
+ }
30
+ /** `register`'s function handler shape: `fn` is invoked directly, captured as a closure - see `TEventHandlerReference`. */
31
+ export interface IEventHandlerFunctionReference<TPayload = unknown> {
32
+ type: typeof EventHandlerTypes.FUNCTION;
33
+ fn: TEventHandlerFunction<TPayload>;
34
+ }
35
+ /**
36
+ * The two shapes `EventBus.register`'s `handler` accepts, tagged by `type` so the caller states
37
+ * which rather than the bus inferring it from whichever field is present. Only `BINDING_KEY` shares
38
+ * `IEventHandler`'s rebind property; see its doc.
39
+ */
40
+ export type TEventHandlerReference<TPayload = unknown> = IEventHandlerBindingKeyReference | IEventHandlerFunctionReference<TPayload>;
41
+ /**
42
+ * Handles one `IDomainEvent`. Implemented by whatever is bound into the container under
43
+ * `register`'s `{ type: EventHandlerTypes.BINDING_KEY, key }` form - see `TEventHandlerReference`
44
+ * for the `FUNCTION` form, which does not implement this interface and does not share its rebind
45
+ * property.
10
46
  *
11
47
  * MUST be idempotent. The bus retries a failed handler, so delivery is at-least-once: one that
12
48
  * half-succeeds then throws runs again from the top, re-applying whatever already landed. Three
@@ -16,11 +52,13 @@ export interface IDomainEvent<TPayload = unknown> {
16
52
  * audit row, which simply gains a duplicate - corrupting the record used to diagnose the retry.
17
53
  *
18
54
  * Resolved from the container by binding key at dispatch time, never captured as a direct reference,
19
- * so rebinding the key takes effect on the next attempt - including one already in flight.
55
+ * so rebinding the key takes effect on the next attempt - including one already in flight. A
56
+ * `FUNCTION`-form handler does NOT have this property: `fn` is a captured closure, so every attempt
57
+ * in a long retry window calls the exact function registered at startup.
20
58
  */
21
59
  export interface IEventHandler<TEvent extends IDomainEvent = IDomainEvent> {
22
60
  handle(opts: {
23
61
  event: TEvent;
24
- }): Promise<void>;
62
+ }): ValueOrPromise<void>;
25
63
  }
26
64
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/types.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,WAAW,YAAY,CAAC,QAAQ,GAAG,OAAO;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,YAAY,GAAG,YAAY;IACvE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/events/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,+FAA+F;AAC/F,MAAM,WAAW,YAAY,CAAC,QAAQ,GAAG,OAAO;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,qHAAqH;IACrH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+FAA+F;AAC/F,MAAM,MAAM,qBAAqB,CAAC,QAAQ,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE;IAC7D,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;CAC/B,KAAK,cAAc,CAAC,IAAI,CAAC,CAAC;AAE3B,2GAA2G;AAC3G,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,OAAO,iBAAiB,CAAC,WAAW,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2HAA2H;AAC3H,MAAM,WAAW,8BAA8B,CAAC,QAAQ,GAAG,OAAO;IAChE,IAAI,EAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC;IACxC,EAAE,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;CACrC;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,CAAC,QAAQ,GAAG,OAAO,IACnD,gCAAgC,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,YAAY,GAAG,YAAY;IACvE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;CACvD"}
@@ -1,21 +1,52 @@
1
1
  import type { Container } from '../../helpers/inversion/container.js';
2
2
  import { BaseHelper } from '@venizia/ignis-helpers/core';
3
+ import type { IEventHandlerRetryOptions, TEventHandlerReference } from './common/types.js';
3
4
  /** In-process, fire-and-forget domain event bus. `TPayloadMap` keys the event names, so a wrong name
4
- * or payload shape is a compile error. Delivery is always async and retry is fixed - there is no
5
- * knob for either, so "published" guarantees the same thing at every call site. Retry makes delivery
6
- * at-least-once: handlers must be idempotent, see `IEventHandler`. */
5
+ * or payload shape is a compile error. Delivery is always async. Retry timing is a property of the
6
+ * handler's own failure mode, not of the event, so `register` may tune it per registration. But
7
+ * nobody awaits a fire-and-forget dispatch, so an unbounded window would let one event hold a
8
+ * handler - and whatever it holds open, e.g. a database connection - for an unbounded time with no
9
+ * one to report it. What the bus guarantees instead: a bounded MAXIMUM time a single dispatch can
10
+ * occupy, enforced as a hard ceiling at `register()` - see `EventDispatchRetry`. Retry makes
11
+ * delivery at-least-once: handlers must be idempotent, see `IEventHandler`. */
7
12
  export declare class EventBus<TPayloadMap extends object> extends BaseHelper {
8
13
  private readonly container;
9
14
  /** `register` appends, never replaces - two handlers may share an event name, and replacing would
10
15
  * drop the first with no way for the caller to notice. */
11
- private readonly handlerBindingKeysByName;
16
+ private readonly registrationsByName;
12
17
  constructor(opts: {
13
18
  scope?: string;
14
19
  container: Container;
15
20
  });
21
+ /** The pre-jitter total of every inter-attempt delay `maxAttempts`/`baseDelayMs` would produce -
22
+ * jitter (always on, see `dispatch`) only ever shrinks a delay, so this is a true upper bound. */
23
+ private static computeTotalWindowMs;
24
+ /** Loud rejection, never a silent clamp: a caller who believes a number the bus does not honour is
25
+ * worse off than one who sees the ceiling at boot. */
26
+ private static assertValidRetry;
27
+ /**
28
+ * Turns `handler` into a uniform invoker plus a description for the exhaustion log line.
29
+ * `BINDING_KEY` resolves through the container INSIDE the returned closure, so every call re-reads
30
+ * the current binding; `FUNCTION` calls `fn` directly, so the closure IS the resolution - there is
31
+ * nothing left to re-read on a later attempt. The tag (`handler.type`) is what this switches on,
32
+ * not which field happens to be present - see `EventHandlerTypes`' doc.
33
+ */
34
+ private static buildHandlerInvoker;
35
+ /**
36
+ * `retry` is optional and per REGISTRATION, not per publish: the right window belongs to the
37
+ * handler's own failure mode, and two handlers on the same event name may each pick their own.
38
+ * Omitting it reproduces today's `EventDispatchRetry` defaults exactly. Both `maxAttempts` and the
39
+ * total backoff window it implies are bounded - see `EventDispatchRetry` - and exceeding either
40
+ * throws here, at boot where a human sees it, rather than being silently clamped at dispatch time.
41
+ */
16
42
  register<K extends keyof TPayloadMap & string>(opts: {
17
43
  name: K;
18
- handlerBindingKey: string;
44
+ /** A `BINDING_KEY` reference re-resolves through the container on every retry attempt, so a
45
+ * rebind reaches a dispatch already in flight. A `FUNCTION` reference is captured as-is: a
46
+ * rebind has nothing to reach, and every attempt in a long retry window calls the exact `fn`
47
+ * registered here. */
48
+ handler: TEventHandlerReference<TPayloadMap[K]>;
49
+ retry?: IEventHandlerRetryOptions;
19
50
  }): void;
20
51
  /**
21
52
  * Never blocks and never throws back to the caller: dispatch runs outside this call's flow via
@@ -28,9 +59,15 @@ export declare class EventBus<TPayloadMap extends object> extends BaseHelper {
28
59
  traceId?: string;
29
60
  }): void;
30
61
  /**
31
- * Fixed 3 attempts / ~100ms exponential backoff, no jitter - see `EventDispatchRetry`. The
32
- * handler is resolved fresh from the container on every attempt rather than once up front, so a
33
- * rebind takes effect on the very next attempt of a dispatch already in flight.
62
+ * Attempts/backoff come from the registration (`EventDispatchRetry`'s defaults when omitted),
63
+ * always with full jitter - `RetryJitterModes.FULL` decorrelates a shared-resource pile-up hardest,
64
+ * so many handlers retrying the same lock do not collide on the same instant a second and third
65
+ * time. `invokeHandler` already encodes whether that re-resolves (`BINDING_KEY`) or was captured
66
+ * once (`FUNCTION`) - see `buildHandlerInvoker` - so this method calls it uniformly. A handler that
67
+ * throws synchronously is caught exactly like one that returns a rejected promise: `execution`
68
+ * here is itself `async`, and JS converts a synchronous throw inside an async function body into a
69
+ * rejection of that function's own promise - `RetryHelper.executeWithRetry`'s attempt loop never
70
+ * sees the difference.
34
71
  *
35
72
  * `RetryHelper.executeWithRetry` is used without its own `logger` - its internal per-attempt/exhaustion
36
73
  * logging knows nothing about the event name or `traceId`, so it cannot be the trace anyone
@@ -1 +1 @@
1
- {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EACL,UAAU,EAKX,MAAM,6BAA6B,CAAC;AAKrC;;;sEAGsE;AACtE,qBAAa,QAAQ,CAAC,WAAW,SAAS,MAAM,CAAE,SAAQ,UAAU;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC;8DAC0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAwB;gBAErD,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE;IAM1D,QAAQ,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QACnD,IAAI,EAAE,CAAC,CAAC;QACR,iBAAiB,EAAE,MAAM,CAAC;KAC3B,GAAG,IAAI;IAkBR;;;;OAIG;IACH,OAAO,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QAClD,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI;IAiCR;;;;;;;;OAQG;YACW,QAAQ;CAmCvB"}
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,EACL,UAAU,EAKX,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAGV,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,gBAAgB,CAAC;AAexB;;;;;;;+EAO+E;AAC/E,qBAAa,QAAQ,CAAC,WAAW,SAAS,MAAM,CAAE,SAAQ,UAAU;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC;8DAC0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA4C;gBAEpE,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE;IAM1D;sGACkG;IAClG,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAkBnC;0DACsD;IACtD,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiC/B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAkDlC;;;;;;OAMG;IACH,QAAQ,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QACnD,IAAI,EAAE,CAAC,CAAC;QACR;;;8BAGsB;QACtB,OAAO,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,KAAK,CAAC,EAAE,yBAAyB,CAAC;KACnC,GAAG,IAAI;IAmCR;;;;OAIG;IACH,OAAO,CAAC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE;QAClD,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI;IAiCR;;;;;;;;;;;;;;OAcG;YACW,QAAQ;CAmCvB"}
@@ -1,29 +1,143 @@
1
1
  import { BaseHelper, getError, RetryBackoffStrategies, RetryHelper, RetryJitterModes, } from '@venizia/ignis-helpers/core';
2
2
  import isEmpty from 'lodash/isEmpty';
3
- import { EventDispatchRetry } from './common/constants.js';
3
+ import { EventDispatchRetry, EventHandlerTypes } from './common/constants.js';
4
4
  /** In-process, fire-and-forget domain event bus. `TPayloadMap` keys the event names, so a wrong name
5
- * or payload shape is a compile error. Delivery is always async and retry is fixed - there is no
6
- * knob for either, so "published" guarantees the same thing at every call site. Retry makes delivery
7
- * at-least-once: handlers must be idempotent, see `IEventHandler`. */
5
+ * or payload shape is a compile error. Delivery is always async. Retry timing is a property of the
6
+ * handler's own failure mode, not of the event, so `register` may tune it per registration. But
7
+ * nobody awaits a fire-and-forget dispatch, so an unbounded window would let one event hold a
8
+ * handler - and whatever it holds open, e.g. a database connection - for an unbounded time with no
9
+ * one to report it. What the bus guarantees instead: a bounded MAXIMUM time a single dispatch can
10
+ * occupy, enforced as a hard ceiling at `register()` - see `EventDispatchRetry`. Retry makes
11
+ * delivery at-least-once: handlers must be idempotent, see `IEventHandler`. */
8
12
  export class EventBus extends BaseHelper {
9
13
  constructor(opts) {
10
14
  super({ scope: opts.scope ?? EventBus.name });
11
15
  this.container = opts.container;
12
- this.handlerBindingKeysByName = new Map();
16
+ this.registrationsByName = new Map();
13
17
  }
18
+ /** The pre-jitter total of every inter-attempt delay `maxAttempts`/`baseDelayMs` would produce -
19
+ * jitter (always on, see `dispatch`) only ever shrinks a delay, so this is a true upper bound. */
20
+ static computeTotalWindowMs(opts) {
21
+ const { maxAttempts, baseDelayMs } = opts;
22
+ let totalWindowMs = 0;
23
+ for (let attempt = 1; attempt < maxAttempts; attempt++) {
24
+ totalWindowMs += RetryHelper.computeBackoffDelayMs({
25
+ attempt,
26
+ backoff: {
27
+ strategy: RetryBackoffStrategies.EXPONENTIAL,
28
+ initialDelayMs: baseDelayMs,
29
+ jitter: RetryJitterModes.NONE,
30
+ },
31
+ });
32
+ }
33
+ return totalWindowMs;
34
+ }
35
+ /** Loud rejection, never a silent clamp: a caller who believes a number the bus does not honour is
36
+ * worse off than one who sees the ceiling at boot. */
37
+ static assertValidRetry(opts) {
38
+ const { name, maxAttempts, baseDelayMs } = opts;
39
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
40
+ throw getError({
41
+ message: `[EventBus][register] retry.maxAttempts must be a positive integer | name: ${name} | Got: ${maxAttempts}`,
42
+ });
43
+ }
44
+ if (!Number.isInteger(baseDelayMs) || baseDelayMs < 1) {
45
+ throw getError({
46
+ message: `[EventBus][register] retry.baseDelayMs must be a positive integer | name: ${name} | Got: ${baseDelayMs}`,
47
+ });
48
+ }
49
+ if (maxAttempts > EventDispatchRetry.MAX_ATTEMPTS_CEILING) {
50
+ throw getError({
51
+ message: `[EventBus][register] retry.maxAttempts exceeds the ceiling | name: ${name} | Got: ${maxAttempts} | Ceiling: ${EventDispatchRetry.MAX_ATTEMPTS_CEILING} | Lower retry.maxAttempts`,
52
+ });
53
+ }
54
+ const totalWindowMs = EventBus.computeTotalWindowMs({ maxAttempts, baseDelayMs });
55
+ if (totalWindowMs > EventDispatchRetry.MAX_TOTAL_WINDOW_MS) {
56
+ throw getError({
57
+ message: `[EventBus][register] retry window exceeds the ceiling | name: ${name} | Got: ${totalWindowMs}ms | Ceiling: ${EventDispatchRetry.MAX_TOTAL_WINDOW_MS}ms | Lower retry.maxAttempts or retry.baseDelayMs`,
58
+ });
59
+ }
60
+ }
61
+ /**
62
+ * Turns `handler` into a uniform invoker plus a description for the exhaustion log line.
63
+ * `BINDING_KEY` resolves through the container INSIDE the returned closure, so every call re-reads
64
+ * the current binding; `FUNCTION` calls `fn` directly, so the closure IS the resolution - there is
65
+ * nothing left to re-read on a later attempt. The tag (`handler.type`) is what this switches on,
66
+ * not which field happens to be present - see `EventHandlerTypes`' doc.
67
+ */
68
+ static buildHandlerInvoker(opts) {
69
+ const { container, handler, name } = opts;
70
+ if (isEmpty(handler)) {
71
+ throw getError({
72
+ message: `[EventBus][register] Invalid handler | name: ${name} | Got: ${handler}`,
73
+ });
74
+ }
75
+ switch (handler.type) {
76
+ case EventHandlerTypes.BINDING_KEY: {
77
+ const { key } = handler;
78
+ if (isEmpty(key)) {
79
+ throw getError({
80
+ message: `[EventBus][register] Invalid handler.key | name: ${name} | Got: ${key}`,
81
+ });
82
+ }
83
+ return {
84
+ invokeHandler: ({ event }) => container.get({ key }).handle({ event }),
85
+ description: `binding-key:${key}`,
86
+ };
87
+ }
88
+ case EventHandlerTypes.FUNCTION: {
89
+ const { fn } = handler;
90
+ if (typeof fn !== 'function') {
91
+ throw getError({
92
+ message: `[EventBus][register] Invalid handler.fn | name: ${name} | Expected a function | Got: ${typeof fn}`,
93
+ });
94
+ }
95
+ return {
96
+ invokeHandler: ({ event }) => fn({ event }),
97
+ description: `function:${fn.name || 'anonymous'}`,
98
+ };
99
+ }
100
+ default: {
101
+ throw getError({
102
+ message: `[EventBus][register] Unknown handler.type | name: ${name} | Expected one of: ${[...EventHandlerTypes.SCHEME_SET].join(', ')} | Got: ${handler.type}`,
103
+ });
104
+ }
105
+ }
106
+ }
107
+ /**
108
+ * `retry` is optional and per REGISTRATION, not per publish: the right window belongs to the
109
+ * handler's own failure mode, and two handlers on the same event name may each pick their own.
110
+ * Omitting it reproduces today's `EventDispatchRetry` defaults exactly. Both `maxAttempts` and the
111
+ * total backoff window it implies are bounded - see `EventDispatchRetry` - and exceeding either
112
+ * throws here, at boot where a human sees it, rather than being silently clamped at dispatch time.
113
+ */
14
114
  register(opts) {
15
- const { name, handlerBindingKey } = opts;
16
- if (isEmpty(name) || isEmpty(handlerBindingKey)) {
115
+ const { name, handler, retry } = opts;
116
+ if (isEmpty(name)) {
17
117
  throw getError({
18
- message: `[EventBus][register] Invalid registration | name: ${String(name)} | handlerBindingKey: ${handlerBindingKey}`,
118
+ message: `[EventBus][register] Invalid registration | name: ${String(name)}`,
19
119
  });
20
120
  }
21
- const existing = this.handlerBindingKeysByName.get(name);
121
+ const maxAttempts = retry?.maxAttempts ?? EventDispatchRetry.MAX_ATTEMPTS;
122
+ const baseDelayMs = retry?.baseDelayMs ?? EventDispatchRetry.BASE_DELAY_MS;
123
+ EventBus.assertValidRetry({ name, maxAttempts, baseDelayMs });
124
+ const { invokeHandler, description } = EventBus.buildHandlerInvoker({
125
+ container: this.container,
126
+ handler,
127
+ name,
128
+ });
129
+ const registration = {
130
+ invokeHandler,
131
+ description,
132
+ maxAttempts,
133
+ baseDelayMs,
134
+ };
135
+ const existing = this.registrationsByName.get(name);
22
136
  if (existing) {
23
- existing.push(handlerBindingKey);
137
+ existing.push(registration);
24
138
  return;
25
139
  }
26
- this.handlerBindingKeysByName.set(name, [handlerBindingKey]);
140
+ this.registrationsByName.set(name, [registration]);
27
141
  }
28
142
  /**
29
143
  * Never blocks and never throws back to the caller: dispatch runs outside this call's flow via
@@ -38,55 +152,61 @@ export class EventBus extends BaseHelper {
38
152
  occurredAt: new Date().toISOString(),
39
153
  traceId,
40
154
  };
41
- const handlerBindingKeys = this.handlerBindingKeysByName.get(name);
42
- if (!handlerBindingKeys?.length) {
155
+ const registrations = this.registrationsByName.get(name);
156
+ if (!registrations?.length) {
43
157
  // A typo is already a compile error, so at runtime this only means nobody is listening yet -
44
158
  // a legitimate state on a fire-and-forget bus, not an incident.
45
159
  this.logger.debug('[publish] No handler registered | name: %s | traceId: %s', name, traceId);
46
160
  return;
47
161
  }
48
- for (const handlerBindingKey of handlerBindingKeys) {
162
+ for (const registration of registrations) {
49
163
  queueMicrotask(() => {
50
164
  // `dispatch` catches every failure path itself and never rejects - this `.catch` is an
51
165
  // unreachable backstop, kept (and logged) rather than left floating, for the day it isn't.
52
- this.dispatch({ event, handlerBindingKey }).catch((error) => {
166
+ this.dispatch({ event, registration }).catch((error) => {
53
167
  this.logger.error('[publish] Unexpected dispatch failure | name: %s | Error: %s', event.name, error);
54
168
  });
55
169
  });
56
170
  }
57
171
  }
58
172
  /**
59
- * Fixed 3 attempts / ~100ms exponential backoff, no jitter - see `EventDispatchRetry`. The
60
- * handler is resolved fresh from the container on every attempt rather than once up front, so a
61
- * rebind takes effect on the very next attempt of a dispatch already in flight.
173
+ * Attempts/backoff come from the registration (`EventDispatchRetry`'s defaults when omitted),
174
+ * always with full jitter - `RetryJitterModes.FULL` decorrelates a shared-resource pile-up hardest,
175
+ * so many handlers retrying the same lock do not collide on the same instant a second and third
176
+ * time. `invokeHandler` already encodes whether that re-resolves (`BINDING_KEY`) or was captured
177
+ * once (`FUNCTION`) - see `buildHandlerInvoker` - so this method calls it uniformly. A handler that
178
+ * throws synchronously is caught exactly like one that returns a rejected promise: `execution`
179
+ * here is itself `async`, and JS converts a synchronous throw inside an async function body into a
180
+ * rejection of that function's own promise - `RetryHelper.executeWithRetry`'s attempt loop never
181
+ * sees the difference.
62
182
  *
63
183
  * `RetryHelper.executeWithRetry` is used without its own `logger` - its internal per-attempt/exhaustion
64
184
  * logging knows nothing about the event name or `traceId`, so it cannot be the trace anyone
65
185
  * relies on. The one line below, logged only on final failure, is.
66
186
  */
67
187
  async dispatch(opts) {
68
- const { event, handlerBindingKey } = opts;
188
+ const { event, registration } = opts;
189
+ const { invokeHandler, description, maxAttempts, baseDelayMs } = registration;
69
190
  let lastAttempt = 0;
70
191
  try {
71
192
  await RetryHelper.executeWithRetry({
72
193
  operation: `EventBus.dispatch:${event.name}`,
73
- maxAttempts: EventDispatchRetry.MAX_ATTEMPTS,
194
+ maxAttempts,
74
195
  backoff: {
75
196
  strategy: RetryBackoffStrategies.EXPONENTIAL,
76
- initialDelayMs: EventDispatchRetry.BASE_DELAY_MS,
77
- jitter: RetryJitterModes.NONE,
197
+ initialDelayMs: baseDelayMs,
198
+ jitter: RetryJitterModes.FULL,
78
199
  },
79
200
  execution: async ({ attempt }) => {
80
201
  lastAttempt = attempt;
81
- const handler = this.container.get({ key: handlerBindingKey });
82
- await handler.handle({ event });
202
+ await invokeHandler({ event });
83
203
  },
84
204
  });
85
205
  }
86
206
  catch (error) {
87
207
  // The only trace this failure leaves: it is caught here and never reaches the publisher, so
88
208
  // the event name, traceId and attempt count all have to be on this one line.
89
- this.logger.error('[dispatch] Handler exhausted retries | name: %s | traceId: %s | attempts: %d | handlerBindingKey: %s | Error: %s', event.name, event.traceId, lastAttempt, handlerBindingKey, error);
209
+ this.logger.error('[dispatch] Handler exhausted retries | name: %s | traceId: %s | attempts: %d | handler: %s | Error: %s', event.name, event.traceId, lastAttempt, description, error);
90
210
  }
91
211
  }
92
212
  }
@@ -1 +1 @@
1
- {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../../src/base/events/event-bus.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,26 @@ export type NumberIdType = number;
21
21
  export type StringIdType = string;
22
22
  export type BigIntIdType = bigint;
23
23
  export type IdType = NumberIdType | StringIdType | BigIntIdType;
24
+ declare const entityIdBrand: unique symbol;
25
+ /**
26
+ * A string id a plain `string` cannot be assigned to, so passing a name, code or email where an id
27
+ * belongs is a compile error. Opt a column in with `.$type<TEntityId>()`.
28
+ *
29
+ * IT VALIDATES NOTHING. `toEntityId` is a cast with a non-empty check; the value is making the
30
+ * laundering VISIBLE at each boundary, not proving the string is a real id.
31
+ *
32
+ * The cost is not optional: Drizzle derives `$inferInsert` and `$inferSelect` from the same field,
33
+ * so a branded column rejects every literal - `create({ data: { merchantId: 'M1' } })`, seeds,
34
+ * fixtures, path params - until each converts. A union with `string` would restore those but makes
35
+ * a plain `string` assignable again, which erases the whole guarantee. Measured, not assumed.
36
+ */
37
+ export type TEntityId = string & {
38
+ readonly [entityIdBrand]: never;
39
+ };
40
+ /** The only way into `TEntityId`. Rejects an empty string - an id that is `''` collapses a `where` to no condition. */
41
+ export declare const toEntityId: (opts: {
42
+ value: string;
43
+ }) => TEntityId;
24
44
  /** Path-param id shape every entity family resolves to (`AbstractEntity.getIdType()`). */
25
45
  export type TIdSchemaType = 'number' | 'string';
26
46
  export declare const idParamsSchema: (opts?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAItC;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;iBA6BpB,CAAC;AAEL,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEhE,0FAA0F;AAC1F,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD,eAAO,MAAM,cAAc,GAAI,OAAO;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE;;;;iBAkC9D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM;IACrD,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;CAMA,CAAC;AAEF,mCAAmC;AACnC,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAAC;AAEF,4CAA4C;AAC5C,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,SAAS,gBAAgB,GAAG,SAAS,IAAI;IACpF,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,CAAC;CACb,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,aAAa,SAAS,CAAC,CAAC,OAAO,EAC/B,YAAY,SAAS,gBAAgB,GAAG,SAAS,GAAG,SAAS,EAE7D,MAAM,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAcrD,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GACxE,GAAG,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,GACzC,CAAC,CAAC;AAEN,KAAK,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,IAAI;KAC5C,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAC1F,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GACZ,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,0SAW7D,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAItC;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;iBA6BpB,CAAC;AAEL,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEhE,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAErE,uHAAuH;AACvH,eAAO,MAAM,UAAU,GAAI,MAAM;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,KAAG,SAMpD,CAAC;AAEF,0FAA0F;AAC1F,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD,eAAO,MAAM,cAAc,GAAI,OAAO;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE;;;;iBAkC9D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM;IACrD,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;CAMA,CAAC;AAEF,mCAAmC;AACnC,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAAC;AAEF,4CAA4C;AAC5C,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,SAAS,gBAAgB,GAAG,SAAS,IAAI;IACpF,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,CAAC;CACb,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,aAAa,SAAS,CAAC,CAAC,OAAO,EAC/B,YAAY,SAAS,gBAAgB,GAAG,SAAS,GAAG,SAAS,EAE7D,MAAM,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAcrD,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GACxE,GAAG,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,GACzC,CAAC,CAAC;AAEN,KAAK,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,IAAI;KAC5C,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAC1F,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GACZ,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,0SAW7D,CAAC"}
@@ -37,6 +37,13 @@ export const ErrorSchema = z
37
37
  details: { url: 'http://localhost:3000/categories', path: '/categories' },
38
38
  },
39
39
  });
40
+ /** The only way into `TEntityId`. Rejects an empty string - an id that is `''` collapses a `where` to no condition. */
41
+ export const toEntityId = (opts) => {
42
+ if (opts.value.length === 0) {
43
+ throw getError({ message: '[toEntityId] Refusing an empty string as an entity id' });
44
+ }
45
+ return opts.value;
46
+ };
40
47
  export const idParamsSchema = (opts) => {
41
48
  const { idType = 'number' } = opts ?? {};
42
49
  switch (idType) {
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/base/models/common/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/ignis-kernel",
3
- "version": "0.2.0-10",
3
+ "version": "0.2.0-11",
4
4
  "description": "Browser-pure kernel of the IGNIS framework: dependency injection, lifecycle, REST controllers, repository and datasource abstractions, and the authentication and authorization seams. No node builtin and no server-only peer, so the same kernel serves a Bun server and a browser Worker.",
5
5
  "keywords": [
6
6
  "authentication",