@bimetal/devtools 0.15.3 → 0.16.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.
Files changed (40) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/causation-forest.d.ts +60 -0
  3. package/dist/causation-forest.d.ts.map +1 -0
  4. package/dist/causation-forest.js +191 -0
  5. package/dist/causation-forest.js.map +1 -0
  6. package/dist/index.d.ts +50 -8
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +36 -7
  9. package/dist/index.js.map +1 -1
  10. package/dist/inspectable-json.d.ts +71 -0
  11. package/dist/inspectable-json.d.ts.map +1 -0
  12. package/dist/inspectable-json.js +225 -0
  13. package/dist/inspectable-json.js.map +1 -0
  14. package/dist/observed-bridge.d.ts +71 -0
  15. package/dist/observed-bridge.d.ts.map +1 -0
  16. package/dist/observed-bridge.js +165 -0
  17. package/dist/observed-bridge.js.map +1 -0
  18. package/dist/observed-helpers.d.ts +88 -0
  19. package/dist/observed-helpers.d.ts.map +1 -0
  20. package/dist/observed-helpers.js +76 -0
  21. package/dist/observed-helpers.js.map +1 -0
  22. package/dist/registry.d.ts +48 -1
  23. package/dist/registry.d.ts.map +1 -1
  24. package/dist/registry.js +120 -0
  25. package/dist/registry.js.map +1 -1
  26. package/dist/replay-engine.d.ts +128 -0
  27. package/dist/replay-engine.d.ts.map +1 -0
  28. package/dist/replay-engine.js +199 -0
  29. package/dist/replay-engine.js.map +1 -0
  30. package/dist/snapshot-export.d.ts +73 -0
  31. package/dist/snapshot-export.d.ts.map +1 -0
  32. package/dist/snapshot-export.js +119 -0
  33. package/dist/snapshot-export.js.map +1 -0
  34. package/dist/time-travel.d.ts +62 -0
  35. package/dist/time-travel.d.ts.map +1 -0
  36. package/dist/time-travel.js +140 -0
  37. package/dist/time-travel.js.map +1 -0
  38. package/dist/types.d.ts +156 -2
  39. package/dist/types.d.ts.map +1 -1
  40. package/package.json +2 -2
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Observe-Helper für Konsumenten (v0.16.5 Sub 2).
3
+ *
4
+ * Bisher lebten diese Helper in `apps/demo/src/event-inspector/setup.ts`
5
+ * als Singleton-gebundene Funktionen. Mit der `@bimetal/devtools-react`-
6
+ * Extraktion ziehen sie hierher um — als reine TS-Wrapper, weil sie
7
+ * registry-agnostisch sind und keinen React-Bezug haben.
8
+ *
9
+ * **Vertrag:**
10
+ * - `registry` ist Pflicht-Argument (kein impliziter Singleton).
11
+ * - `id` ist Pflicht-Argument (kein versteckter Module-Level-Counter).
12
+ * - Pro Helper-Aufruf eine eigene `DiagnosticsSource` (sonst fan-outet
13
+ * ein gemeinsamer Source jedes Event an N Registry-Listener).
14
+ * - Returnt `unregister`-Unsubscribe; Konsument MUSS aufrufen im
15
+ * useEffect-Cleanup / Variant-Teardown.
16
+ *
17
+ * **Boundary:** Die Helper hängen an `@bimetal/event-sourcing`
18
+ * (`createInMemoryEventStore` als Default + `EventStore`-Type). Das ist
19
+ * konsistent mit der bestehenden devtools→event-sourcing-Abhängigkeit;
20
+ * Bridge-Wrapper aus v0.16.4 macht das genauso.
21
+ */
22
+ import type { EventStore } from '@bimetal/event-sourcing';
23
+ import type { DevtoolsRegistry } from './registry.js';
24
+ import type { AggregateLike, ProjectionLike, ReplayTargetHandle } from './replay-engine.js';
25
+ import type { DiagnosticsSource, Unsubscribe } from './types.js';
26
+ export interface ObservedEventStoreOptions {
27
+ readonly id: string;
28
+ /** Default: gleicher Wert wie `id`. */
29
+ readonly name?: string;
30
+ }
31
+ export interface ObservedEventStoreHandle {
32
+ readonly eventStore: EventStore;
33
+ /**
34
+ * Demontiert den Store aus dem Registry. Konsument MUSS aufrufen,
35
+ * sonst akkumulieren stale Store-Handles im Inspector über
36
+ * Variant-/Component-Wechsel hinweg.
37
+ */
38
+ readonly unregister: Unsubscribe;
39
+ }
40
+ /**
41
+ * Drop-in-Wrapper für `createInMemoryEventStore()`, der den Store
42
+ * gleichzeitig im `DevtoolsRegistry` anmeldet.
43
+ *
44
+ * Pro Aufruf eine eigene `DiagnosticsSource`. Sub-Klasse-Effekt: Events
45
+ * landen 1:1 in `state.events`, keine N-fach-Duplikate.
46
+ */
47
+ export declare function createObservedEventStore(registry: DevtoolsRegistry, options: ObservedEventStoreOptions): ObservedEventStoreHandle;
48
+ export interface ObservedSyncTransportOptions {
49
+ readonly id: string;
50
+ /** Default: gleicher Wert wie `id`. */
51
+ readonly name?: string;
52
+ }
53
+ export interface ObservedSyncTransportHandle {
54
+ /**
55
+ * `DiagnosticsSink`, den der Konsument an `createInMemorySync*` /
56
+ * `createWebSocketSync` als `{ diagnostics }` weitergibt. Pro Aufruf
57
+ * eine eigene Source — keine Cross-Transport-Lecks.
58
+ */
59
+ readonly diagnostics: DiagnosticsSource;
60
+ /** Stabile transportId, die der Adapter via `{ transportId }` nutzt. */
61
+ readonly transportId: string;
62
+ readonly unregister: Unsubscribe;
63
+ }
64
+ /**
65
+ * Erzeugt eine `DiagnosticsSource` + meldet den Transport beim
66
+ * Registry an. Konsument bindet `diagnostics` + `transportId` an seinen
67
+ * Sync-Adapter; Records erscheinen dann im Sync-Tab des Inspectors.
68
+ */
69
+ export declare function createObservedSyncTransport(registry: DevtoolsRegistry, options: ObservedSyncTransportOptions): ObservedSyncTransportHandle;
70
+ export interface ObservedReplayTargetOptions<S, R> {
71
+ readonly id: string;
72
+ /** Default: gleicher Wert wie `id`. */
73
+ readonly name?: string;
74
+ readonly eventStore: ReplayTargetHandle<S, R>['eventStore'];
75
+ readonly streamId: string;
76
+ readonly aggregate: AggregateLike<S>;
77
+ readonly projection: ProjectionLike<R>;
78
+ }
79
+ export interface ObservedReplayTargetHandle {
80
+ readonly unregister: Unsubscribe;
81
+ }
82
+ /**
83
+ * Registriert ein passives ReplayTarget am Registry. Engine baut den
84
+ * Stream-State live durch; im Inspector erscheint das Target als
85
+ * Eintrag im State-Tab.
86
+ */
87
+ export declare function createObservedReplayTarget<S, R>(registry: DevtoolsRegistry, options: ObservedReplayTargetOptions<S, R>): ObservedReplayTargetHandle;
88
+ //# sourceMappingURL=observed-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observed-helpers.d.ts","sourceRoot":"","sources":["../src/observed-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAIjE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CAU1B;AAID,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IACxC,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,4BAA4B,GACpC,2BAA2B,CAY7B;AAID,MAAM,WAAW,2BAA2B,CAAC,CAAC,EAAE,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,CAAC,EAC7C,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,GACzC,0BAA0B,CAU5B"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Observe-Helper für Konsumenten (v0.16.5 Sub 2).
3
+ *
4
+ * Bisher lebten diese Helper in `apps/demo/src/event-inspector/setup.ts`
5
+ * als Singleton-gebundene Funktionen. Mit der `@bimetal/devtools-react`-
6
+ * Extraktion ziehen sie hierher um — als reine TS-Wrapper, weil sie
7
+ * registry-agnostisch sind und keinen React-Bezug haben.
8
+ *
9
+ * **Vertrag:**
10
+ * - `registry` ist Pflicht-Argument (kein impliziter Singleton).
11
+ * - `id` ist Pflicht-Argument (kein versteckter Module-Level-Counter).
12
+ * - Pro Helper-Aufruf eine eigene `DiagnosticsSource` (sonst fan-outet
13
+ * ein gemeinsamer Source jedes Event an N Registry-Listener).
14
+ * - Returnt `unregister`-Unsubscribe; Konsument MUSS aufrufen im
15
+ * useEffect-Cleanup / Variant-Teardown.
16
+ *
17
+ * **Boundary:** Die Helper hängen an `@bimetal/event-sourcing`
18
+ * (`createInMemoryEventStore` als Default + `EventStore`-Type). Das ist
19
+ * konsistent mit der bestehenden devtools→event-sourcing-Abhängigkeit;
20
+ * Bridge-Wrapper aus v0.16.4 macht das genauso.
21
+ */
22
+ import { createInMemoryEventStore } from '@bimetal/event-sourcing';
23
+ import { createDiagnosticsSource } from './diagnostics-source.js';
24
+ /**
25
+ * Drop-in-Wrapper für `createInMemoryEventStore()`, der den Store
26
+ * gleichzeitig im `DevtoolsRegistry` anmeldet.
27
+ *
28
+ * Pro Aufruf eine eigene `DiagnosticsSource`. Sub-Klasse-Effekt: Events
29
+ * landen 1:1 in `state.events`, keine N-fach-Duplikate.
30
+ */
31
+ export function createObservedEventStore(registry, options) {
32
+ const source = createDiagnosticsSource();
33
+ const eventStore = createInMemoryEventStore({ diagnostics: source });
34
+ const unregister = registry.registerEventStore({
35
+ id: options.id,
36
+ name: options.name ?? options.id,
37
+ eventStore,
38
+ diagnostics: source,
39
+ });
40
+ return { eventStore, unregister };
41
+ }
42
+ /**
43
+ * Erzeugt eine `DiagnosticsSource` + meldet den Transport beim
44
+ * Registry an. Konsument bindet `diagnostics` + `transportId` an seinen
45
+ * Sync-Adapter; Records erscheinen dann im Sync-Tab des Inspectors.
46
+ */
47
+ export function createObservedSyncTransport(registry, options) {
48
+ const diagnostics = createDiagnosticsSource();
49
+ const unregister = registry.registerSyncTransport({
50
+ id: options.id,
51
+ name: options.name ?? options.id,
52
+ diagnostics,
53
+ });
54
+ return {
55
+ diagnostics,
56
+ transportId: options.id,
57
+ unregister,
58
+ };
59
+ }
60
+ /**
61
+ * Registriert ein passives ReplayTarget am Registry. Engine baut den
62
+ * Stream-State live durch; im Inspector erscheint das Target als
63
+ * Eintrag im State-Tab.
64
+ */
65
+ export function createObservedReplayTarget(registry, options) {
66
+ const unregister = registry.registerReplayTarget({
67
+ id: options.id,
68
+ name: options.name ?? options.id,
69
+ eventStore: options.eventStore,
70
+ streamId: options.streamId,
71
+ aggregate: options.aggregate,
72
+ projection: options.projection,
73
+ });
74
+ return { unregister };
75
+ }
76
+ //# sourceMappingURL=observed-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observed-helpers.js","sourceRoot":"","sources":["../src/observed-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAuBlE;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA0B,EAC1B,OAAkC;IAElC,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,wBAAwB,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,QAAQ,CAAC,kBAAkB,CAAC;QAC7C,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE;QAChC,UAAU;QACV,WAAW,EAAE,MAAM;KACpB,CAAC,CAAC;IACH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC;AAsBD;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAA0B,EAC1B,OAAqC;IAErC,MAAM,WAAW,GAAG,uBAAuB,EAAE,CAAC;IAC9C,MAAM,UAAU,GAAG,QAAQ,CAAC,qBAAqB,CAAC;QAChD,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE;QAChC,WAAW;KACZ,CAAC,CAAC;IACH,OAAO;QACL,WAAW;QACX,WAAW,EAAE,OAAO,CAAC,EAAE;QACvB,UAAU;KACX,CAAC;AACJ,CAAC;AAkBD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAA0B,EAC1B,OAA0C;IAE1C,MAAM,UAAU,GAAG,QAAQ,CAAC,oBAAoB,CAAC;QAC/C,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;IACH,OAAO,EAAE,UAAU,EAAE,CAAC;AACxB,CAAC"}
@@ -17,16 +17,63 @@
17
17
  * **Identity-Modell:** Stores werden über ihre `id` geführt, `name` ist
18
18
  * Display-only. Duplikat-Check ist auf `id`.
19
19
  */
20
- import type { DevtoolsState, EventStoreHandle, Unsubscribe } from './types.js';
20
+ import type { BridgeHandle, DevtoolsState, EventStoreHandle, SyncTransportHandle, Unsubscribe } from './types.js';
21
+ import { type ReplayTargetHandle } from './replay-engine.js';
22
+ import { type TimeTravelController } from './time-travel.js';
21
23
  export interface DevtoolsRegistryOptions {
22
24
  /**
23
25
  * Rolling-window size for captured events. Older events drop out.
24
26
  * Default 10 000.
25
27
  */
26
28
  readonly maxEvents?: number;
29
+ /**
30
+ * Rolling-window size for captured sync records (v0.15.5).
31
+ * Default 10 000.
32
+ */
33
+ readonly maxSyncRecords?: number;
34
+ /**
35
+ * Rolling-window size for captured bridge records (v0.16.4).
36
+ * Default 10 000.
37
+ */
38
+ readonly maxBridgeRecords?: number;
27
39
  }
28
40
  export interface DevtoolsRegistry {
29
41
  registerEventStore(handle: EventStoreHandle): Unsubscribe;
42
+ registerSyncTransport(handle: SyncTransportHandle): Unsubscribe;
43
+ /**
44
+ * Registriert ein ReplayTarget (v0.16.0). Engine wird intern erzeugt
45
+ * und folded den Stream live durch — der Konsument hat nichts zu
46
+ * subscribieren. Snapshot ist über `state.replayTargets` reichbar.
47
+ *
48
+ * Multiple Targets pro Stream sind erlaubt (verschiedene `handle.id`):
49
+ * z. B. ein Domain-Aggregate plus ein statistisches Side-Read-Model.
50
+ * Doppelte `handle.id` wirft.
51
+ */
52
+ registerReplayTarget(handle: ReplayTargetHandle): Unsubscribe;
53
+ /**
54
+ * Factory für einen ephemeren TimeTravelController über das mit
55
+ * `targetId` registrierte ReplayTarget (v0.16.2). Controller lebt
56
+ * außerhalb des `DevtoolsState`-Snapshots — Slider-Bewegungen churchen
57
+ * nicht die Always-On-Listener im Inspector.
58
+ *
59
+ * Wirft, wenn `targetId` nicht registriert ist. Mehrere Controller
60
+ * auf demselben Target sind erlaubt (z. B. zwei UI-Panels, die
61
+ * unabhängig durch die Historie scrollen).
62
+ */
63
+ createTimeTravelController(targetId: string): TimeTravelController;
64
+ /**
65
+ * Registriert eine Bridge (v0.16.4). Konsument liefert ein
66
+ * `BridgeHandle` mit eigener `BridgeDiagnosticsSource`; die Registry
67
+ * subscribet darauf und pumpt `BridgeRecord`s ins rolling-window.
68
+ *
69
+ * Doppelte `handle.id` wirft. Mehrere Bridges auf demselben Source/
70
+ * Target-Paar sind erlaubt (z. B. zwei verschiedene `toTopic`-Mappings).
71
+ *
72
+ * Üblicher Aufrufer ist `createObservedBridge`, der das Handle intern
73
+ * baut. Konsumenten mit eigener Bridge-Implementation können direkt
74
+ * registrieren.
75
+ */
76
+ registerBridge(handle: BridgeHandle): Unsubscribe;
30
77
  readonly state: DevtoolsState;
31
78
  subscribe(listener: (state: DevtoolsState) => void): Unsubscribe;
32
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAEV,aAAa,EACb,gBAAgB,EAEhB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,WAAW,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,WAAW,CAAC;CAClE;AAID,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAkFlB"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,YAAY,EAIZ,aAAa,EACb,gBAAgB,EAKhB,mBAAmB,EACnB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAyC,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAA8B,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEzF,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,WAAW,CAAC;IAC1D,qBAAqB,CAAC,MAAM,EAAE,mBAAmB,GAAG,WAAW,CAAC;IAChE;;;;;;;;OAQG;IACH,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAAC;IAC9D;;;;;;;;;OASG;IACH,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAAC;IACnE;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,WAAW,CAAC;CAClE;AAMD,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CA2NlB"}
package/dist/registry.js CHANGED
@@ -17,20 +17,46 @@
17
17
  * **Identity-Modell:** Stores werden über ihre `id` geführt, `name` ist
18
18
  * Display-only. Duplikat-Check ist auf `id`.
19
19
  */
20
+ import { createReplayEngine } from './replay-engine.js';
21
+ import { createTimeTravelController } from './time-travel.js';
20
22
  const DEFAULT_MAX_EVENTS = 10_000;
23
+ const DEFAULT_MAX_SYNC_RECORDS = 10_000;
24
+ const DEFAULT_MAX_BRIDGE_RECORDS = 10_000;
21
25
  export function createDevtoolsRegistry(options = {}) {
22
26
  const maxEvents = options.maxEvents ?? DEFAULT_MAX_EVENTS;
27
+ const maxSyncRecords = options.maxSyncRecords ?? DEFAULT_MAX_SYNC_RECORDS;
28
+ const maxBridgeRecords = options.maxBridgeRecords ?? DEFAULT_MAX_BRIDGE_RECORDS;
23
29
  const eventStores = new Map();
24
30
  const events = [];
31
+ const syncTransports = new Map();
32
+ const syncRecords = [];
33
+ const replayTargets = new Map();
34
+ const bridges = new Map();
35
+ const bridgeRecords = [];
25
36
  const listeners = new Set();
26
37
  let nextSeq = 1;
27
38
  // Reference-stable snapshot. Invalidated on every mutation in notify().
28
39
  let cachedSnapshot = null;
29
40
  function getSnapshot() {
30
41
  if (cachedSnapshot === null) {
42
+ const targetsView = [];
43
+ for (const { handle, engine } of replayTargets.values()) {
44
+ targetsView.push({
45
+ id: handle.id,
46
+ name: handle.name,
47
+ streamId: handle.streamId,
48
+ projectionVersion: handle.projection.version,
49
+ snapshot: engine.snapshot,
50
+ });
51
+ }
31
52
  cachedSnapshot = {
32
53
  eventStores: Array.from(eventStores.values()),
33
54
  events: events.slice(),
55
+ syncTransports: Array.from(syncTransports.values()),
56
+ syncRecords: syncRecords.slice(),
57
+ replayTargets: targetsView,
58
+ bridges: Array.from(bridges.values()),
59
+ bridgeRecords: bridgeRecords.slice(),
34
60
  };
35
61
  }
36
62
  return cachedSnapshot;
@@ -54,6 +80,18 @@ export function createDevtoolsRegistry(options = {}) {
54
80
  events.shift();
55
81
  }
56
82
  }
83
+ function pushSyncRecord(captured) {
84
+ syncRecords.push(captured);
85
+ while (syncRecords.length > maxSyncRecords) {
86
+ syncRecords.shift();
87
+ }
88
+ }
89
+ function pushBridgeRecord(captured) {
90
+ bridgeRecords.push(captured);
91
+ while (bridgeRecords.length > maxBridgeRecords) {
92
+ bridgeRecords.shift();
93
+ }
94
+ }
57
95
  return {
58
96
  registerEventStore(handle) {
59
97
  if (eventStores.has(handle.id)) {
@@ -80,6 +118,88 @@ export function createDevtoolsRegistry(options = {}) {
80
118
  notify();
81
119
  };
82
120
  },
121
+ registerSyncTransport(handle) {
122
+ if (syncTransports.has(handle.id)) {
123
+ throw new Error(`@bimetal/devtools: SyncTransport with id "${handle.id}" already registered`);
124
+ }
125
+ syncTransports.set(handle.id, { id: handle.id, name: handle.name });
126
+ const offDiag = handle.diagnostics.subscribe((record) => {
127
+ if (typeof record.kind === 'string' && record.kind.startsWith('sync-')) {
128
+ pushSyncRecord({
129
+ seq: nextSeq++,
130
+ transportId: handle.id,
131
+ transportName: handle.name,
132
+ capturedAt: Date.now(),
133
+ record: record,
134
+ });
135
+ notify();
136
+ }
137
+ });
138
+ notify();
139
+ return () => {
140
+ offDiag();
141
+ syncTransports.delete(handle.id);
142
+ notify();
143
+ };
144
+ },
145
+ registerReplayTarget(handle) {
146
+ if (replayTargets.has(handle.id)) {
147
+ throw new Error(`@bimetal/devtools: ReplayTarget with id "${handle.id}" already registered`);
148
+ }
149
+ const engine = createReplayEngine(handle);
150
+ replayTargets.set(handle.id, { handle, engine });
151
+ // Engine-Mutationen invalidieren den Registry-Snapshot, sodass
152
+ // useSyncExternalStore-Konsumenten neu rendern.
153
+ const offEngine = engine.subscribe(() => notify());
154
+ notify();
155
+ return () => {
156
+ offEngine();
157
+ engine.dispose();
158
+ replayTargets.delete(handle.id);
159
+ notify();
160
+ };
161
+ },
162
+ createTimeTravelController(targetId) {
163
+ const entry = replayTargets.get(targetId);
164
+ if (!entry) {
165
+ throw new Error(`@bimetal/devtools: ReplayTarget with id "${targetId}" not registered — register first via registerReplayTarget()`);
166
+ }
167
+ return createTimeTravelController(entry.handle);
168
+ },
169
+ registerBridge(handle) {
170
+ if (bridges.has(handle.id)) {
171
+ throw new Error(`@bimetal/devtools: Bridge with id "${handle.id}" already registered`);
172
+ }
173
+ bridges.set(handle.id, {
174
+ id: handle.id,
175
+ name: handle.name,
176
+ kind: handle.kind,
177
+ source: handle.source,
178
+ target: handle.target,
179
+ });
180
+ const offDiag = handle.diagnostics.subscribe((record) => {
181
+ // structuredClone: das Forward-Pattern in createObservedBridge
182
+ // emittiert den Record VOR dem Publish-Call. Würde der Broker
183
+ // (oder ein Test-Stub) das Event-Objekt mutieren, würde sich der
184
+ // bereits captured Record nachträglich ändern. Pilot-Finding
185
+ // Sub 1. Clone hier zentral, damit jeder Captor (auch ein
186
+ // custom-Konsumenten-Handle) den Snapshot-Vertrag bekommt.
187
+ pushBridgeRecord({
188
+ seq: nextSeq++,
189
+ bridgeId: handle.id,
190
+ bridgeName: handle.name,
191
+ capturedAt: Date.now(),
192
+ record: structuredClone(record),
193
+ });
194
+ notify();
195
+ });
196
+ notify();
197
+ return () => {
198
+ offDiag();
199
+ bridges.delete(handle.id);
200
+ notify();
201
+ };
202
+ },
83
203
  get state() {
84
204
  return getSnapshot();
85
205
  },
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAgBH,OAAO,EAAE,kBAAkB,EAA8C,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAE,0BAA0B,EAA6B,MAAM,kBAAkB,CAAC;AA6DzF,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAE1C,MAAM,UAAU,sBAAsB,CACpC,UAAmC,EAAE;IAErC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAC1D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,wBAAwB,CAAC;IAC1E,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,0BAA0B,CAAC;IAEhF,MAAM,WAAW,GAAG,IAAI,GAAG,EAAgC,CAAC;IAC5D,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAmC,CAAC;IAClE,MAAM,WAAW,GAAyB,EAAE,CAAC;IAC7C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkF,CAAC;IAChH,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IACpD,MAAM,aAAa,GAA2B,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkC,CAAC;IAC5D,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,wEAAwE;IACxE,IAAI,cAAc,GAAyB,IAAI,CAAC;IAEhD,SAAS,WAAW;QAClB,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YAC5B,MAAM,WAAW,GAA6B,EAAE,CAAC;YACjD,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;gBACxD,WAAW,CAAC,IAAI,CAAC;oBACf,EAAE,EAAE,MAAM,CAAC,EAAE;oBACb,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,iBAAiB,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO;oBAC5C,QAAQ,EAAE,MAAM,CAAC,QAAQ;iBAC1B,CAAC,CAAC;YACL,CAAC;YACD,cAAc,GAAG;gBACf,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;gBAC7C,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;gBACtB,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;gBACnD,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE;gBAChC,aAAa,EAAE,WAAW;gBAC1B,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACrC,aAAa,EAAE,aAAa,CAAC,KAAK,EAAE;aACrC,CAAC;QACJ,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,SAAS,MAAM;QACb,cAAc,GAAG,IAAI,CAAC;QACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACrB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,sCAAsC;gBACtC,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,SAAS,CAAC,QAAuB;QACxC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,OAAO,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YACjC,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,SAAS,cAAc,CAAC,QAA4B;QAClD,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,OAAO,WAAW,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YAC3C,WAAW,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAED,SAAS,gBAAgB,CAAC,QAA8B;QACtD,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,aAAa,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YAC/C,aAAa,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO;QACL,kBAAkB,CAAC,MAAwB;YACzC,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACb,0CAA0C,MAAM,CAAC,EAAE,sBAAsB,CAC1E,CAAC;YACJ,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAEjE,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;gBACtD,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;oBACrC,SAAS,CAAC;wBACR,GAAG,EAAE,OAAO,EAAE;wBACd,OAAO,EAAE,MAAM,CAAC,EAAE;wBAClB,SAAS,EAAE,MAAM,CAAC,IAAI;wBACtB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;wBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;qBACtB,CAAC,CAAC;oBACH,MAAM,EAAE,CAAC;gBACX,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,EAAE,CAAC;YAET,OAAO,GAAG,EAAE;gBACV,OAAO,EAAE,CAAC;gBACV,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC9B,MAAM,EAAE,CAAC;YACX,CAAC,CAAC;QACJ,CAAC;QAED,qBAAqB,CAAC,MAA2B;YAC/C,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;gBAClC,MAAM,IAAI,KAAK,CACb,6CAA6C,MAAM,CAAC,EAAE,sBAAsB,CAC7E,CAAC;YACJ,CAAC;YACD,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAEpE,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;gBACtD,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBACvE,cAAc,CAAC;wBACb,GAAG,EAAE,OAAO,EAAE;wBACd,WAAW,EAAE,MAAM,CAAC,EAAE;wBACtB,aAAa,EAAE,MAAM,CAAC,IAAI;wBAC1B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;wBACtB,MAAM,EAAE,MAAsC;qBAC/C,CAAC,CAAC;oBACH,MAAM,EAAE,CAAC;gBACX,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,EAAE,CAAC;YAET,OAAO,GAAG,EAAE;gBACV,OAAO,EAAE,CAAC;gBACV,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACjC,MAAM,EAAE,CAAC;YACX,CAAC,CAAC;QACJ,CAAC;QAED,oBAAoB,CAAC,MAA0B;YAC7C,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CACb,4CAA4C,MAAM,CAAC,EAAE,sBAAsB,CAC5E,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAmC,CAAC;YAC5E,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YACjD,+DAA+D;YAC/D,gDAAgD;YAChD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;YACnD,MAAM,EAAE,CAAC;YAET,OAAO,GAAG,EAAE;gBACV,SAAS,EAAE,CAAC;gBACZ,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAChC,MAAM,EAAE,CAAC;YACX,CAAC,CAAC;QACJ,CAAC;QAED,0BAA0B,CAAC,QAAgB;YACzC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CACb,4CAA4C,QAAQ,8DAA8D,CACnH,CAAC;YACJ,CAAC;YACD,OAAO,0BAA0B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC;QAED,cAAc,CAAC,MAAoB;YACjC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CACb,sCAAsC,MAAM,CAAC,EAAE,sBAAsB,CACtE,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE;gBACrB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;gBACtD,+DAA+D;gBAC/D,8DAA8D;gBAC9D,iEAAiE;gBACjE,6DAA6D;gBAC7D,0DAA0D;gBAC1D,2DAA2D;gBAC3D,gBAAgB,CAAC;oBACf,GAAG,EAAE,OAAO,EAAE;oBACd,QAAQ,EAAE,MAAM,CAAC,EAAE;oBACnB,UAAU,EAAE,MAAM,CAAC,IAAI;oBACvB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;oBACtB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;iBAChC,CAAC,CAAC;gBACH,MAAM,EAAE,CAAC;YACX,CAAC,CAAC,CAAC;YAEH,MAAM,EAAE,CAAC;YAET,OAAO,GAAG,EAAE;gBACV,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC1B,MAAM,EAAE,CAAC;YACX,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,KAAK;YACP,OAAO,WAAW,EAAE,CAAC;QACvB,CAAC;QAED,SAAS,CAAC,QAAwC;YAChD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * `createReplayEngine` — pure synchrone Fold-Function über einen Stream.
3
+ *
4
+ * Architektur-Verträge aus `design/calendar/16-replay-target-architecture.md`:
5
+ * - **Passive Beobachtung**: Engine ruft NIEMALS `eventStore.append`,
6
+ * `store.dispatch` oder `broker.publish`. Architecture-Test verriegelt.
7
+ * - **subscribe-first + buffer + read + drain**: kein Race-Window zwischen
8
+ * Catch-up und Live-Tail (v0.15.7-Lehre).
9
+ * - **Sticky Error**: bei `apply`-Wurf wird `status = 'error'` und KEIN
10
+ * weiteres Event mehr gefolded — sonst entstände Fold auf staleren
11
+ * Zustand und der User sähe vorgegaukelten Aggregat-Stand.
12
+ * - **Recovery nur via `dispose()` + neuer `createReplayEngine`-Call.**
13
+ * Engine kennt keine `clearError`-Operation.
14
+ *
15
+ * Implementations-Notes:
16
+ * - `handleEvent` ist **synchron** (Architektur-Vertrag).
17
+ * - Initial-Read ist async (das ist OK — `read()` ist der einzige
18
+ * await; danach läuft alles synchron).
19
+ * - `snapshot`-Getter ist reference-stable bis zur nächsten Mutation
20
+ * (analog Devtools-Registry, useSyncExternalStore-Vertrag).
21
+ */
22
+ import type { DomainEvent, Unsubscribe } from '@bimetal/event-sourcing';
23
+ import type { EventStoreLike } from './types.js';
24
+ /**
25
+ * Domain-agnostisches Aggregate-Interface. Bewusst KEIN `handle(state, command)`
26
+ * — Command-Semantik gehört nicht in den Devtools-Vertrag.
27
+ */
28
+ export interface AggregateLike<S> {
29
+ readonly initialState: S;
30
+ apply(state: S, event: DomainEvent): S;
31
+ }
32
+ export interface ProjectionLike<R> {
33
+ readonly initialState: R;
34
+ apply(readModel: R, event: DomainEvent): R;
35
+ readonly version: number;
36
+ }
37
+ /**
38
+ * Strukturelles SnapshotStore-Interface. Optional — Engine liest nur,
39
+ * schreibt NIE rein. Aktuell für Konsistenz-Checks reserviert (in v0.16.0
40
+ * noch nicht genutzt, kommt mit späterer Slice).
41
+ */
42
+ export interface SnapshotStoreLike {
43
+ load(streamId: string): Promise<SnapshotLike | null>;
44
+ }
45
+ export interface SnapshotLike {
46
+ readonly state: unknown;
47
+ readonly projectionVersion: number;
48
+ readonly version: number;
49
+ readonly timestamp: number;
50
+ }
51
+ export interface ReplayTargetHandle<S = unknown, R = unknown> {
52
+ readonly id: string;
53
+ readonly name: string;
54
+ readonly eventStore: EventStoreLike;
55
+ readonly streamId: string;
56
+ readonly aggregate: AggregateLike<S>;
57
+ readonly projection: ProjectionLike<R>;
58
+ readonly snapshotStore?: SnapshotStoreLike;
59
+ }
60
+ export interface ReplayEngineSnapshot<S, R> {
61
+ readonly state: S;
62
+ readonly readModel: R;
63
+ /** `envelope.version` des zuletzt erfolgreich applied Events; `0` bei initialState. */
64
+ readonly lastAppliedVersion: number;
65
+ readonly status: 'replaying' | 'live' | 'error';
66
+ /**
67
+ * Bei `status='error'`: gesetzt, mit `event` als der Event, der den
68
+ * Fehler auslöste — oder als der zuletzt blockierte Event (nach
69
+ * status='error' aktualisiert sich `event` mit jedem eingehenden,
70
+ * nicht-applied Event, damit der User „letzter blockierter Event war v9"
71
+ * sehen kann). `event=null` zeigt: Fehler kam aus `read()`, nicht aus `apply()`.
72
+ */
73
+ readonly lastError?: {
74
+ readonly event: DomainEvent | null;
75
+ readonly error: Error;
76
+ };
77
+ readonly lastAppliedEventId?: string;
78
+ /**
79
+ * `metadata.schemaVersion` des zuletzt erfolgreich applied Events.
80
+ * Konsumenten-UI vergleicht das mit der `projection.version` aus dem
81
+ * Handle, um Schema-Drift sichtbar zu machen (v0.16-Architektur-Doc
82
+ * Leitplanke 6).
83
+ */
84
+ readonly lastAppliedSchemaVersion?: number;
85
+ /** Events nach `status='error'` eingegangen, aber NICHT applied. */
86
+ readonly blockedEventCount: number;
87
+ }
88
+ export interface ReplayEngine<S, R> {
89
+ /** Reference-stable bis zur nächsten Mutation. */
90
+ readonly snapshot: ReplayEngineSnapshot<S, R>;
91
+ subscribe(listener: () => void): Unsubscribe;
92
+ /** Cleanup: stoppt Live-Subscriber, befreit Listener. */
93
+ dispose(): void;
94
+ }
95
+ /**
96
+ * Initialer Snapshot für eine fresh angesetzte Replay-Sequenz. `status`
97
+ * beginnt bei `'replaying'`; der Konsument (Engine ODER TimeTravelController)
98
+ * entscheidet selbst, wann er auf `'live'`/`'ready'` umschaltet.
99
+ */
100
+ export declare function createInitialSnapshot<S, R>(aggregate: AggregateLike<S>, projection: ProjectionLike<R>): ReplayEngineSnapshot<S, R>;
101
+ /**
102
+ * Pure synchroner Fold von genau einem Event auf einen Snapshot.
103
+ *
104
+ * **Atomarer Commit:** beide `apply`-Aufrufe (aggregate + projection)
105
+ * laufen ZUERST in lokale `next*`-Variablen. Erst wenn BEIDE
106
+ * erfolgreich sind, wird das neue Snapshot-Objekt mit allen Tracking-
107
+ * Feldern (`lastAppliedVersion`, `lastAppliedEventId`,
108
+ * `lastAppliedSchemaVersion`) zurückgegeben. Wirft `projection.apply`,
109
+ * ist `nextState` lokal verloren, der Input-`snap` bleibt unverändert —
110
+ * Half-Update unmöglich.
111
+ *
112
+ * **Sticky-Error:** Bei Input-`snap.status === 'error'` wird der Event
113
+ * NICHT applied. Output trägt `blockedEventCount + 1` und ein
114
+ * aktualisiertes `lastError.event` (auf den jeweils zuletzt blockierten
115
+ * Event), damit der User „letzter blockierter Event war v9" sehen kann.
116
+ *
117
+ * **Nichts read/subscribe-bezogenes.** Reine Funktion: Snapshot rein,
118
+ * Event rein, Snapshot raus. Live-Engine UND TimeTravelController
119
+ * konsumieren dieselbe Funktion.
120
+ */
121
+ export declare function applyEventToSnapshot<S, R>(snap: ReplayEngineSnapshot<S, R>, event: DomainEvent, aggregate: AggregateLike<S>, projection: ProjectionLike<R>): ReplayEngineSnapshot<S, R>;
122
+ /**
123
+ * Convenience: Reduce über ein Array von Events — equivalent zu
124
+ * sequenziellem `applyEventToSnapshot`. Pure Funktion, keine Side-Effects.
125
+ */
126
+ export declare function foldEvents<S, R>(events: readonly DomainEvent[], aggregate: AggregateLike<S>, projection: ProjectionLike<R>, initial: ReplayEngineSnapshot<S, R>): ReplayEngineSnapshot<S, R>;
127
+ export declare function createReplayEngine<S, R>(handle: ReplayTargetHandle<S, R>): ReplayEngine<S, R>;
128
+ //# sourceMappingURL=replay-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-engine.d.ts","sourceRoot":"","sources":["../src/replay-engine.ts"],"names":[],"mappings":"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"}