@bimetal/devtools 0.15.10 → 0.16.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/causation-forest.d.ts +60 -0
- package/dist/causation-forest.d.ts.map +1 -0
- package/dist/causation-forest.js +191 -0
- package/dist/causation-forest.js.map +1 -0
- package/dist/index.d.ts +50 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -7
- package/dist/index.js.map +1 -1
- package/dist/inspectable-json.d.ts +71 -0
- package/dist/inspectable-json.d.ts.map +1 -0
- package/dist/inspectable-json.js +225 -0
- package/dist/inspectable-json.js.map +1 -0
- package/dist/observed-bridge.d.ts +71 -0
- package/dist/observed-bridge.d.ts.map +1 -0
- package/dist/observed-bridge.js +165 -0
- package/dist/observed-bridge.js.map +1 -0
- package/dist/observed-helpers.d.ts +88 -0
- package/dist/observed-helpers.d.ts.map +1 -0
- package/dist/observed-helpers.js +76 -0
- package/dist/observed-helpers.js.map +1 -0
- package/dist/registry.d.ts +42 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +84 -0
- package/dist/registry.js.map +1 -1
- package/dist/replay-engine.d.ts +128 -0
- package/dist/replay-engine.d.ts.map +1 -0
- package/dist/replay-engine.js +199 -0
- package/dist/replay-engine.js.map +1 -0
- package/dist/snapshot-export.d.ts +73 -0
- package/dist/snapshot-export.d.ts.map +1 -0
- package/dist/snapshot-export.js +119 -0
- package/dist/snapshot-export.js.map +1 -0
- package/dist/time-travel.d.ts +62 -0
- package/dist/time-travel.d.ts.map +1 -0
- package/dist/time-travel.js +140 -0
- package/dist/time-travel.js.map +1 -0
- package/dist/types.d.ts +121 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createObservedBridge` — Devtools-Wrapper-Helper für die EventStore→
|
|
3
|
+
* Broker-Forward-Semantik (v0.16.4 Sub 1).
|
|
4
|
+
*
|
|
5
|
+
* Verriegelt aus `design/calendar/16-bridges-inspector-architecture.md`:
|
|
6
|
+
*
|
|
7
|
+
* **Ehrlichkeits-Vertrag — eigene Forward-Implementation:**
|
|
8
|
+
* Der Helper ruft die rohe EventStore→Broker-Bridge-Utility aus
|
|
9
|
+
* `@bimetal/event-sourcing` NICHT auf (die exakten Identifier sind im
|
|
10
|
+
* Architecture-Test verriegelt — diese Quelle vermeidet sie auch in
|
|
11
|
+
* Kommentaren, damit der Token-Scan über die ganze Datei einfach
|
|
12
|
+
* bleibt). Die rohe Bridge hat aktuell keinen beobachtbaren Hook —
|
|
13
|
+
* ein Wrapper, der sie nutzte, müsste entweder eine zweite Forward-
|
|
14
|
+
* Schiene erzeugen (jedes Event doppelt publiziert) oder die User-
|
|
15
|
+
* Subscribe-Reihenfolge raten. Stattdessen implementiert dieser Helper
|
|
16
|
+
* dieselbe Forward-Semantik (`subscribe` → `toTopic` → `publish` +
|
|
17
|
+
* Safe-Wrap-Error-Handler) selbst und hängt seinen Diagnostics-
|
|
18
|
+
* Subscriber direkt an die eigene Code-Stelle. Vertragsäquivalenz zur
|
|
19
|
+
* rohen Utility wird durch Tests verriegelt.
|
|
20
|
+
*
|
|
21
|
+
* **Keine neue Semantik:**
|
|
22
|
+
* - Kein Retry. `publish()`-Rejection wird via `onPublishError`-Hook
|
|
23
|
+
* propagiert, nicht wiederholt.
|
|
24
|
+
* - Kein Dedup.
|
|
25
|
+
* - Keine Backpressure. `publish()` läuft fire-and-forget (`.catch()`).
|
|
26
|
+
* - Keine Fehlerunterdrückung. Werfender User-Handler wird im
|
|
27
|
+
* Safe-Wrap gefangen (genau wie in der rohen Bridge), nicht
|
|
28
|
+
* stillschweigend verschluckt.
|
|
29
|
+
*
|
|
30
|
+
* **publish-error-Reihenfolge:**
|
|
31
|
+
* Der Record landet IMMER im rolling-window — VOR dem User-Handler-
|
|
32
|
+
* Aufruf. Sonst sähe der Inspector nur Erfolgspfade, wenn der User
|
|
33
|
+
* den Fehler verschluckt.
|
|
34
|
+
*/
|
|
35
|
+
export function createObservedBridge(registry, options) {
|
|
36
|
+
const toTopic = options.toTopic ?? defaultToTopic;
|
|
37
|
+
const userOnError = options.onPublishError ?? defaultPublishErrorHandler;
|
|
38
|
+
// Eigener Diagnostics-Subject pro Bridge — typisiert auf BridgeRecord.
|
|
39
|
+
const diagnostics = createBridgeDiagnostics();
|
|
40
|
+
// Source-Label-Fallback-Kette (Sub-1-Pilot-Schärfung):
|
|
41
|
+
// 1. explizites sourceLabel (Konsument hat etwas Konkretes im Kopf)
|
|
42
|
+
// 2. sourceStoreId (Identitäts-Label des registrierten Stores)
|
|
43
|
+
// 3. 'event-store' (generische Konstante als letzter Ausweg)
|
|
44
|
+
const source = {
|
|
45
|
+
label: options.sourceLabel ?? options.sourceStoreId ?? 'event-store',
|
|
46
|
+
...(options.sourceStoreId !== undefined ? { storeId: options.sourceStoreId } : {}),
|
|
47
|
+
};
|
|
48
|
+
const target = {
|
|
49
|
+
label: options.targetLabel,
|
|
50
|
+
};
|
|
51
|
+
const handle = {
|
|
52
|
+
id: options.id,
|
|
53
|
+
name: options.name,
|
|
54
|
+
kind: 'event-store-to-broker',
|
|
55
|
+
source,
|
|
56
|
+
target,
|
|
57
|
+
diagnostics,
|
|
58
|
+
};
|
|
59
|
+
// Registry-Registrierung VOR Subscribe — sonst landen die ersten
|
|
60
|
+
// Events in der Pipe, bevor der Inspector das Handle sieht.
|
|
61
|
+
const offRegister = registry.registerBridge(handle);
|
|
62
|
+
// EIGENE Forward-Implementation. KEIN Aufruf der rohen
|
|
63
|
+
// EventStore→Broker-Bridge-Utility aus event-sourcing — siehe
|
|
64
|
+
// Datei-Header zur Begründung (Token im Architecture-Test verriegelt).
|
|
65
|
+
//
|
|
66
|
+
// try/catch: wenn `subscribe()` synchron wirft, würde sonst die
|
|
67
|
+
// Bridge im Registry hängen bleiben (Handle registriert, kein
|
|
68
|
+
// Subscriber aktiv). Pilot-Finding Sub 1.
|
|
69
|
+
let offSubscribe;
|
|
70
|
+
try {
|
|
71
|
+
offSubscribe = options.eventStore.subscribe((event) => {
|
|
72
|
+
const topic = toTopic(event);
|
|
73
|
+
// 1. „forwarded"-Record emittieren VOR der publish-Call-Site —
|
|
74
|
+
// fire-and-forget heißt: wir markieren als forwarded, sobald
|
|
75
|
+
// wir den Wurf weggeschickt haben. Kein await, kein tookMs.
|
|
76
|
+
diagnostics.emit({
|
|
77
|
+
kind: 'bridge-event-forwarded',
|
|
78
|
+
topic,
|
|
79
|
+
event,
|
|
80
|
+
});
|
|
81
|
+
// 2. publish() fire-and-forget mit .catch() — wie in der rohen
|
|
82
|
+
// Bridge. Plus try/catch um den Aufruf selbst: strukturell ist
|
|
83
|
+
// publish() zwar Promise<void>, aber ein Adapter oder Test-
|
|
84
|
+
// Double kann synchron werfen. Ohne try/catch würde der Wurf
|
|
85
|
+
// aus dem EventStore-Subscriber rausfliegen und Record +
|
|
86
|
+
// User-Handler überspringen. Pilot-Finding Sub 1.
|
|
87
|
+
try {
|
|
88
|
+
Promise.resolve(options.target.publish(topic, event)).catch((error) => {
|
|
89
|
+
safeOnError(error, event, topic);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (syncError) {
|
|
93
|
+
safeOnError(syncError, event, topic);
|
|
94
|
+
}
|
|
95
|
+
}, options.streamId);
|
|
96
|
+
}
|
|
97
|
+
catch (subscribeError) {
|
|
98
|
+
offRegister();
|
|
99
|
+
throw subscribeError;
|
|
100
|
+
}
|
|
101
|
+
function safeOnError(error, event, topic) {
|
|
102
|
+
// Pilot-Verriegelung: Record ZUERST. Auch wenn der User-Handler
|
|
103
|
+
// wirft oder den Fehler verschluckt, ist er im Inspector sichtbar.
|
|
104
|
+
diagnostics.emit({
|
|
105
|
+
kind: 'bridge-publish-error',
|
|
106
|
+
topic,
|
|
107
|
+
event,
|
|
108
|
+
error: extractError(error),
|
|
109
|
+
});
|
|
110
|
+
// DANN User-Handler, in Safe-Wrap.
|
|
111
|
+
try {
|
|
112
|
+
userOnError(error, event, topic);
|
|
113
|
+
}
|
|
114
|
+
catch (innerError) {
|
|
115
|
+
// eslint-disable-next-line no-console
|
|
116
|
+
console.error('[@bimetal/devtools/observed-bridge] onPublishError handler itself threw — original error follows:', innerError, error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return () => {
|
|
120
|
+
offSubscribe();
|
|
121
|
+
offRegister();
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function defaultToTopic(event) {
|
|
125
|
+
return event.type;
|
|
126
|
+
}
|
|
127
|
+
function defaultPublishErrorHandler(error, event, topic) {
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.error(`[@bimetal/devtools/observed-bridge] publish failed for topic "${topic}" event ${event.envelope.id}:`, error);
|
|
130
|
+
}
|
|
131
|
+
function extractError(error) {
|
|
132
|
+
if (error instanceof Error) {
|
|
133
|
+
return error.stack !== undefined
|
|
134
|
+
? { message: error.message, stack: error.stack }
|
|
135
|
+
: { message: error.message };
|
|
136
|
+
}
|
|
137
|
+
return { message: String(error) };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Bridge-Diagnostics-Subject: Listener-Pool wie `createDiagnosticsSource`,
|
|
141
|
+
* aber typed auf `BridgeRecord`. Throw-Isolation pro Listener.
|
|
142
|
+
*/
|
|
143
|
+
export function createBridgeDiagnostics() {
|
|
144
|
+
const listeners = new Set();
|
|
145
|
+
return {
|
|
146
|
+
emit(record) {
|
|
147
|
+
for (const listener of listeners) {
|
|
148
|
+
try {
|
|
149
|
+
listener(record);
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
// eslint-disable-next-line no-console
|
|
153
|
+
console.error('[@bimetal/devtools/observed-bridge] listener threw:', err);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
subscribe(listener) {
|
|
158
|
+
listeners.add(listener);
|
|
159
|
+
return () => {
|
|
160
|
+
listeners.delete(listener);
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=observed-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observed-bridge.js","sourceRoot":"","sources":["../src/observed-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -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"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
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, SyncTransportHandle, 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.
|
|
@@ -29,10 +31,49 @@ export interface DevtoolsRegistryOptions {
|
|
|
29
31
|
* Default 10 000.
|
|
30
32
|
*/
|
|
31
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;
|
|
32
39
|
}
|
|
33
40
|
export interface DevtoolsRegistry {
|
|
34
41
|
registerEventStore(handle: EventStoreHandle): Unsubscribe;
|
|
35
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;
|
|
36
77
|
readonly state: DevtoolsState;
|
|
37
78
|
subscribe(listener: (state: DevtoolsState) => void): Unsubscribe;
|
|
38
79
|
}
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,
|
|
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,26 +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;
|
|
21
23
|
const DEFAULT_MAX_SYNC_RECORDS = 10_000;
|
|
24
|
+
const DEFAULT_MAX_BRIDGE_RECORDS = 10_000;
|
|
22
25
|
export function createDevtoolsRegistry(options = {}) {
|
|
23
26
|
const maxEvents = options.maxEvents ?? DEFAULT_MAX_EVENTS;
|
|
24
27
|
const maxSyncRecords = options.maxSyncRecords ?? DEFAULT_MAX_SYNC_RECORDS;
|
|
28
|
+
const maxBridgeRecords = options.maxBridgeRecords ?? DEFAULT_MAX_BRIDGE_RECORDS;
|
|
25
29
|
const eventStores = new Map();
|
|
26
30
|
const events = [];
|
|
27
31
|
const syncTransports = new Map();
|
|
28
32
|
const syncRecords = [];
|
|
33
|
+
const replayTargets = new Map();
|
|
34
|
+
const bridges = new Map();
|
|
35
|
+
const bridgeRecords = [];
|
|
29
36
|
const listeners = new Set();
|
|
30
37
|
let nextSeq = 1;
|
|
31
38
|
// Reference-stable snapshot. Invalidated on every mutation in notify().
|
|
32
39
|
let cachedSnapshot = null;
|
|
33
40
|
function getSnapshot() {
|
|
34
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
|
+
}
|
|
35
52
|
cachedSnapshot = {
|
|
36
53
|
eventStores: Array.from(eventStores.values()),
|
|
37
54
|
events: events.slice(),
|
|
38
55
|
syncTransports: Array.from(syncTransports.values()),
|
|
39
56
|
syncRecords: syncRecords.slice(),
|
|
57
|
+
replayTargets: targetsView,
|
|
58
|
+
bridges: Array.from(bridges.values()),
|
|
59
|
+
bridgeRecords: bridgeRecords.slice(),
|
|
40
60
|
};
|
|
41
61
|
}
|
|
42
62
|
return cachedSnapshot;
|
|
@@ -66,6 +86,12 @@ export function createDevtoolsRegistry(options = {}) {
|
|
|
66
86
|
syncRecords.shift();
|
|
67
87
|
}
|
|
68
88
|
}
|
|
89
|
+
function pushBridgeRecord(captured) {
|
|
90
|
+
bridgeRecords.push(captured);
|
|
91
|
+
while (bridgeRecords.length > maxBridgeRecords) {
|
|
92
|
+
bridgeRecords.shift();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
69
95
|
return {
|
|
70
96
|
registerEventStore(handle) {
|
|
71
97
|
if (eventStores.has(handle.id)) {
|
|
@@ -116,6 +142,64 @@ export function createDevtoolsRegistry(options = {}) {
|
|
|
116
142
|
notify();
|
|
117
143
|
};
|
|
118
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
|
+
},
|
|
119
203
|
get state() {
|
|
120
204
|
return getSnapshot();
|
|
121
205
|
},
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|