footprintjs 4.14.0 → 4.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -268,6 +268,83 @@ const llmCommit = findCommit(commitLog, 'call-llm', 'adapterRawResponse');
268
268
  | `findLastWriter(commitLog, key, beforeIdx?)` | `CommitBundle \| undefined` | Search backwards for who wrote a key |
269
269
  | `KeyedRecorder<T>` | abstract class | Base for 1:1 Map-based recorders |
270
270
  | `SequenceRecorder<T>` | abstract class | Base for 1:N ordered sequence recorders (has `getEntryRanges()` for O(1) time-travel) |
271
+ | `topologyRecorder()` / `TopologyRecorder` | factory / class | Live composition graph for streaming consumers (subflow nodes + control-flow edges) |
272
+
273
+ ### TopologyRecorder — Composition Graph for Streaming Consumers
274
+
275
+ **One-liner:** reconstructs a live, queryable mini-flowchart of what your run actually traced, built from the 3 primitive recorder channels during traversal.
276
+
277
+ **Mental model:**
278
+
279
+ ```
280
+ flowChart() builder → STATIC flowchart (design-time definition)
281
+
282
+ ▼ executor runs it
283
+ Traversal emits events on 3 channels:
284
+ Recorder · FlowRecorder · EmitRecorder
285
+
286
+ ▼ TopologyRecorder listens
287
+ DYNAMIC flowchart (runtime shape):
288
+ Nodes = composition points
289
+ (subflow / fork-branch / decision-branch)
290
+ Edges = transitions
291
+ (next / fork / decision / loop)
292
+ Queryable any moment — during or after run
293
+ ```
294
+
295
+ **What it IS:**
296
+ - Live composition graph derived from 3 primitive channels
297
+ - Each node = one composition-significant moment (subflow entered, fork child, decision chosen)
298
+ - Each edge = a control-flow transition, timestamped with `runtimeStageId`
299
+ - Works identically during or after a run
300
+
301
+ **What it ISN'T:**
302
+ - Not a full execution tree — that's `StageContext` / `executor.getSnapshot()`
303
+ - Not per-stage data — that's `MetricRecorder` / custom `KeyedRecorder<T>`
304
+ - Not agent-specific — agentfootprint composes it; footprintjs owns it
305
+
306
+ **Why live consumers need it:** The executor already has the topology internally (execution tree in `StageContext`). But streaming consumers can't access that tree mid-run — they only see events. `TopologyRecorder` = "the tree, reconstructed from events, live-queryable."
307
+
308
+ Fills the gap between "post-run snapshot (full tree available)" and "live event stream (only point observations)." Attach once; query `getTopology()` anytime during or after a run.
309
+
310
+ ```typescript
311
+ import { topologyRecorder } from 'footprintjs/trace';
312
+
313
+ const topo = topologyRecorder();
314
+ executor.attachCombinedRecorder(topo); // auto-routes to FlowRecorder channel
315
+
316
+ await executor.run({ input });
317
+
318
+ const { nodes, edges, activeNodeId, rootId } = topo.getTopology();
319
+ topo.getSubflowNodes(); // agent-centric view
320
+ topo.getByKind('fork-branch'); // all parallel branches
321
+ topo.getParallelSiblings(id); // siblings of a parallel branch
322
+ ```
323
+
324
+ **Three node kinds — complete composition coverage:**
325
+
326
+ | Kind | Fires on | Represents |
327
+ |---|---|---|
328
+ | `subflow` | `onSubflowEntry` | Mounted subflow boundary (with stable `subflowId`) |
329
+ | `fork-branch` | `onFork` (synthesized one per child) | One branch of a parallel split — works for plain stages AND subflows |
330
+ | `decision-branch` | `onDecision` (synthesized for chosen) | The chosen branch of a conditional |
331
+
332
+ When a fork-branch or decision-branch target is also a subflow, the subsequent `onSubflowEntry` creates a subflow CHILD of the synthetic node. Layered shape preserves both "who branched" and "what the branch ran."
333
+
334
+ **Edges:** one per control-flow transition. `edge.kind ∈ 'next' | 'fork-branch' | 'decision-branch' | 'loop-iteration'`. Each carries `at: runtimeStageId` for time correlation.
335
+
336
+ **Correlation rules:**
337
+ - `onFork({ parent, children })` → N `fork-branch` nodes synthesized up-front; subsequent matching `onSubflowEntry` nests under the right fork-branch
338
+ - `onDecision({ chosen })` → `decision-branch` node synthesized up-front; matching `onSubflowEntry` nests under it
339
+ - Pending correlation clears on `onSubflowExit` so state doesn't leak across scopes
340
+ - `onLoop` → self-edge on the currently-active subflow (synthetic nodes don't participate)
341
+ - Re-entry of same `subflowId` (loop body) disambiguates via `id#n` suffix
342
+
343
+ **What it does NOT track:** plain sequential stages. Use `MetricRecorder` / `StageContext` for per-stage data. Topology is a graph of control-flow branching, not a full execution tree.
344
+
345
+ **For downstream libraries:** compose, don't duplicate. An agent-shaped recorder should wrap a `topologyRecorder()` internally and translate topology nodes into agent semantics — not re-implement subflow-stack + fork + decision tracking.
346
+
347
+ Example: [examples/flow-recorders/06-topology-recorder.ts](examples/flow-recorders/06-topology-recorder.ts)
271
348
 
272
349
  **Two recorder base classes** — choose based on data shape:
273
350
 
@@ -0,0 +1,272 @@
1
+ /**
2
+ * TopologyRecorder — composition graph built during traversal.
3
+ *
4
+ * The gap this fills:
5
+ * footprintjs fires atomic flow events (onSubflowEntry, onFork, onDecision,
6
+ * onLoop) but the accumulated *shape* of a run — who nests inside whom,
7
+ * which nodes are parallel siblings vs branches of a decision — is only
8
+ * visible post-run via `executor.getSnapshot()` tree-walking.
9
+ *
10
+ * Streaming consumers (live UIs, in-flight debuggers) see only the event
11
+ * stream. Every such consumer has to rebuild subflow-stack + fork-map +
12
+ * decision-tracker from scratch, usually slightly wrong in different ways.
13
+ *
14
+ * TopologyRecorder is the standard accumulator: one subscription to the
15
+ * three primitive channels, one live graph, queryable at any moment during
16
+ * or after a run.
17
+ *
18
+ * What it records — THREE node kinds for complete composition coverage:
19
+ * 1. 'subflow' — via onSubflowEntry (a mounted subflow boundary)
20
+ * 2. 'fork-branch' — via onFork (one node per child, synthesized)
21
+ * 3. 'decision-branch' — via onDecision (the chosen branch, synthesized)
22
+ *
23
+ * When a fork-branch or decision-branch target IS ALSO a subflow, the
24
+ * subsequent onSubflowEntry creates a subflow CHILD of the synthetic node.
25
+ * The layered shape preserves both "who branched" and "what the branch ran."
26
+ *
27
+ * Plain sequential stages are NOT nodes — that's StageContext's job.
28
+ * Topology is a graph of control-flow branching, not a full execution tree.
29
+ *
30
+ * Edges:
31
+ * One edge per traversal transition — `kind` matches the child's
32
+ * `incomingKind`. A consumer rendering "parallel columns" filters edges
33
+ * where `kind === 'fork-branch'` sharing the same `from`.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * import { topologyRecorder } from 'footprintjs/trace';
38
+ *
39
+ * const topo = topologyRecorder();
40
+ * executor.attachCombinedRecorder(topo); // auto-routes to FlowRecorder channel
41
+ *
42
+ * await executor.run();
43
+ *
44
+ * const { nodes, edges, activeNodeId, rootId } = topo.getTopology();
45
+ * // Consumer queries:
46
+ * topo.getChildren('sf-parent'); // direct children (any kind)
47
+ * topo.getByKind('fork-branch'); // all parallel branches
48
+ * topo.getSubflowNodes(); // only mounted subflows
49
+ * ```
50
+ */
51
+ let _counter = 0;
52
+ /**
53
+ * Factory — matches the `narrative()` / `metrics()` style.
54
+ */
55
+ export function topologyRecorder(options = {}) {
56
+ return new TopologyRecorder(options);
57
+ }
58
+ /**
59
+ * Stateful accumulator that watches FlowRecorder events and maintains a live
60
+ * composition graph. Attach via `executor.attachCombinedRecorder(recorder)` —
61
+ * footprintjs detects the `FlowRecorder` method shape and routes events.
62
+ */
63
+ export class TopologyRecorder {
64
+ constructor(options = {}) {
65
+ var _a;
66
+ this.nodesById = new Map();
67
+ this.nodeOrder = [];
68
+ this.edges = [];
69
+ /** Stack of active SUBFLOW node ids. Fork/decision-branch nodes never push. */
70
+ this.subflowStack = [];
71
+ /** Map of childName → pending fork-branch synthetic node, consumed by
72
+ * the next matching `onSubflowEntry`. */
73
+ this.pendingForkByName = new Map();
74
+ this.id = (_a = options.id) !== null && _a !== void 0 ? _a : `topology-${++_counter}`;
75
+ }
76
+ // ── FlowRecorder hooks ────────────────────────────────────────────────
77
+ onSubflowEntry(event) {
78
+ var _a, _b;
79
+ const subflowId = event.subflowId;
80
+ if (!subflowId)
81
+ return; // Need a stable id to track.
82
+ const enteredAt = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
83
+ // Determine the parent: prefer a pending fork/decision match by name,
84
+ // otherwise the current top-of-subflow-stack.
85
+ let parentId;
86
+ let incomingKind;
87
+ const pendingFork = this.pendingForkByName.get(event.name);
88
+ if (pendingFork) {
89
+ parentId = pendingFork.nodeId;
90
+ incomingKind = 'next'; // Child OF a fork-branch node; the fork semantic
91
+ // is captured by the fork-branch's own incomingKind.
92
+ this.pendingForkByName.delete(event.name);
93
+ }
94
+ else if (this.pendingDecision && this.pendingDecision.name === event.name) {
95
+ parentId = this.pendingDecision.nodeId;
96
+ incomingKind = 'next';
97
+ this.pendingDecision = undefined;
98
+ }
99
+ else {
100
+ parentId = this.subflowStack[this.subflowStack.length - 1];
101
+ incomingKind = parentId ? 'next' : 'root';
102
+ }
103
+ // Disambiguate re-entry (e.g., loop body re-enters the same subflow).
104
+ let nodeId = subflowId;
105
+ if (this.nodesById.has(nodeId)) {
106
+ let n = 1;
107
+ while (this.nodesById.has(`${subflowId}#${n}`))
108
+ n++;
109
+ nodeId = `${subflowId}#${n}`;
110
+ }
111
+ const depth = parentId ? this.nodesById.get(parentId).depth + 1 : 0;
112
+ const metadata = event.description ? { description: event.description } : undefined;
113
+ const node = {
114
+ id: nodeId,
115
+ kind: 'subflow',
116
+ name: event.name,
117
+ parentId,
118
+ depth,
119
+ incomingKind,
120
+ enteredAt,
121
+ metadata,
122
+ };
123
+ this.nodesById.set(nodeId, node);
124
+ this.nodeOrder.push(nodeId);
125
+ if (parentId && incomingKind !== 'root') {
126
+ this.edges.push({
127
+ from: parentId,
128
+ to: nodeId,
129
+ kind: incomingKind,
130
+ at: enteredAt,
131
+ });
132
+ }
133
+ this.subflowStack.push(nodeId);
134
+ }
135
+ onSubflowExit(event) {
136
+ var _a, _b;
137
+ const nodeId = this.subflowStack.pop();
138
+ if (!nodeId)
139
+ return;
140
+ const node = this.nodesById.get(nodeId);
141
+ if (node) {
142
+ node.exitedAt = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
143
+ }
144
+ // A subflow exit implies no more children are pending for this scope —
145
+ // clear stale pending state that belonged to the scope we just left.
146
+ this.pendingForkByName.clear();
147
+ this.pendingDecision = undefined;
148
+ }
149
+ onFork(event) {
150
+ var _a, _b;
151
+ const activeId = this.subflowStack[this.subflowStack.length - 1];
152
+ const at = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
153
+ const depth = activeId ? this.nodesById.get(activeId).depth + 1 : 0;
154
+ // Reset any prior pending fork state — a new fork starts fresh.
155
+ this.pendingForkByName.clear();
156
+ event.children.forEach((childName, i) => {
157
+ const nodeId = `fork-${at || event.parent}-${i}-${childName}`;
158
+ const node = {
159
+ id: nodeId,
160
+ kind: 'fork-branch',
161
+ name: childName,
162
+ parentId: activeId,
163
+ depth,
164
+ incomingKind: 'fork-branch',
165
+ enteredAt: at,
166
+ metadata: { forkParent: event.parent },
167
+ };
168
+ this.nodesById.set(nodeId, node);
169
+ this.nodeOrder.push(nodeId);
170
+ if (activeId) {
171
+ this.edges.push({ from: activeId, to: nodeId, kind: 'fork-branch', at });
172
+ }
173
+ this.pendingForkByName.set(childName, { nodeId, at });
174
+ });
175
+ }
176
+ onDecision(event) {
177
+ var _a, _b;
178
+ const activeId = this.subflowStack[this.subflowStack.length - 1];
179
+ const at = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
180
+ const depth = activeId ? this.nodesById.get(activeId).depth + 1 : 0;
181
+ // A new decision supersedes any prior unresolved pending one.
182
+ this.pendingDecision = undefined;
183
+ const nodeId = `decision-${at || event.decider}-${event.chosen}`;
184
+ const metadata = { decider: event.decider };
185
+ if (event.rationale)
186
+ metadata.rationale = event.rationale;
187
+ if (event.description)
188
+ metadata.description = event.description;
189
+ const node = {
190
+ id: nodeId,
191
+ kind: 'decision-branch',
192
+ name: event.chosen,
193
+ parentId: activeId,
194
+ depth,
195
+ incomingKind: 'decision-branch',
196
+ enteredAt: at,
197
+ metadata,
198
+ };
199
+ this.nodesById.set(nodeId, node);
200
+ this.nodeOrder.push(nodeId);
201
+ if (activeId) {
202
+ this.edges.push({ from: activeId, to: nodeId, kind: 'decision-branch', at });
203
+ }
204
+ this.pendingDecision = { name: event.chosen, nodeId, at };
205
+ }
206
+ onLoop(event) {
207
+ var _a, _b;
208
+ // loopTo jumps back inside the CURRENT subflow. Record a self-edge on the
209
+ // active subflow — synthetic fork/decision nodes don't participate in loops.
210
+ const activeId = this.subflowStack[this.subflowStack.length - 1];
211
+ if (!activeId)
212
+ return;
213
+ this.edges.push({
214
+ from: activeId,
215
+ to: activeId,
216
+ kind: 'loop-iteration',
217
+ at: (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '',
218
+ });
219
+ }
220
+ /** Called by the executor before each `run()` — resets all state. */
221
+ clear() {
222
+ this.nodesById.clear();
223
+ this.nodeOrder.length = 0;
224
+ this.edges.length = 0;
225
+ this.subflowStack.length = 0;
226
+ this.pendingForkByName.clear();
227
+ this.pendingDecision = undefined;
228
+ }
229
+ // ── Query API ─────────────────────────────────────────────────────────
230
+ /** Live snapshot of the composition graph. Safe during or after a run. */
231
+ getTopology() {
232
+ var _a, _b;
233
+ const nodes = this.nodeOrder.map((id) => this.nodesById.get(id));
234
+ return {
235
+ nodes,
236
+ edges: [...this.edges],
237
+ activeNodeId: (_a = this.subflowStack[this.subflowStack.length - 1]) !== null && _a !== void 0 ? _a : null,
238
+ rootId: (_b = this.nodeOrder[0]) !== null && _b !== void 0 ? _b : null,
239
+ };
240
+ }
241
+ /** Direct children of a node — insertion-ordered. */
242
+ getChildren(nodeId) {
243
+ return this.nodeOrder.map((id) => this.nodesById.get(id)).filter((n) => n.parentId === nodeId);
244
+ }
245
+ /** All nodes of a given kind. */
246
+ getByKind(kind) {
247
+ return this.nodeOrder.map((id) => this.nodesById.get(id)).filter((n) => n.kind === kind);
248
+ }
249
+ /** All mounted subflow nodes. Convenience for agent-centric views. */
250
+ getSubflowNodes() {
251
+ return this.getByKind('subflow');
252
+ }
253
+ /** All fork-branch nodes sharing the same parent as `nodeId` — i.e.,
254
+ * parallel siblings of a parallel branch. Empty if `nodeId` isn't a
255
+ * fork-branch or has no parent. */
256
+ getParallelSiblings(nodeId) {
257
+ const node = this.nodesById.get(nodeId);
258
+ if (!node || node.kind !== 'fork-branch' || !node.parentId)
259
+ return [];
260
+ return this.getChildren(node.parentId).filter((n) => n.kind === 'fork-branch');
261
+ }
262
+ /** Emit a snapshot bundle for inclusion in `executor.getSnapshot()`. */
263
+ toSnapshot() {
264
+ return {
265
+ name: 'Topology',
266
+ description: 'Composition graph: subflow boundaries, fork branches, decision branches',
267
+ preferredOperation: 'translate',
268
+ data: this.getTopology(),
269
+ };
270
+ }
271
+ }
272
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9wb2xvZ3lSZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvcmVjb3JkZXIvVG9wb2xvZ3lSZWNvcmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlERztBQTJFSCxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7QUFFakI7O0dBRUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsVUFBbUMsRUFBRTtJQUNwRSxPQUFPLElBQUksZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDdkMsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBZTNCLFlBQVksVUFBbUMsRUFBRTs7UUFaaEMsY0FBUyxHQUFHLElBQUksR0FBRyxFQUF3QixDQUFDO1FBQzVDLGNBQVMsR0FBYSxFQUFFLENBQUM7UUFDekIsVUFBSyxHQUFtQixFQUFFLENBQUM7UUFDNUMsK0VBQStFO1FBQzlELGlCQUFZLEdBQWEsRUFBRSxDQUFDO1FBRTdDO2tEQUMwQztRQUN6QixzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBd0IsQ0FBQztRQUtuRSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQUEsT0FBTyxDQUFDLEVBQUUsbUNBQUksWUFBWSxFQUFFLFFBQVEsRUFBRSxDQUFDO0lBQ25ELENBQUM7SUFFRCx5RUFBeUU7SUFFekUsY0FBYyxDQUFDLEtBQXVCOztRQUNwQyxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxTQUFTO1lBQUUsT0FBTyxDQUFDLDZCQUE2QjtRQUVyRCxNQUFNLFNBQVMsR0FBRyxNQUFBLE1BQUEsS0FBSyxDQUFDLGdCQUFnQiwwQ0FBRSxjQUFjLG1DQUFJLEVBQUUsQ0FBQztRQUUvRCxzRUFBc0U7UUFDdEUsOENBQThDO1FBQzlDLElBQUksUUFB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Q0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLGFBQWEsQ0FBQyxDQUFDO0lBQ2pGLENBQUM7SUFFRCx3RUFBd0U7SUFDeEUsVUFBVTtRQUNSLE9BQU87WUFDTCxJQUFJLEVBQUUsVUFBVTtZQUNoQixXQUFXLEVBQUUseUVBQXlFO1lBQ3RGLGtCQUFrQixFQUFFLFdBQW9CO1lBQ3hDLElBQUksRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFO1NBQ3pCLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRvcG9sb2d5UmVjb3JkZXIg4oCUIGNvbXBvc2l0aW9uIGdyYXBoIGJ1aWx0IGR1cmluZyB0cmF2ZXJzYWwuXG4gKlxuICogVGhlIGdhcCB0aGlzIGZpbGxzOlxuICogICBmb290cHJpbnRqcyBmaXJlcyBhdG9taWMgZmxvdyBldmVudHMgKG9uU3ViZmxvd0VudHJ5LCBvbkZvcmssIG9uRGVjaXNpb24sXG4gKiAgIG9uTG9vcCkgYnV0IHRoZSBhY2N1bXVsYXRlZCAqc2hhcGUqIG9mIGEgcnVuIOKAlCB3aG8gbmVzdHMgaW5zaWRlIHdob20sXG4gKiAgIHdoaWNoIG5vZGVzIGFyZSBwYXJhbGxlbCBzaWJsaW5ncyB2cyBicmFuY2hlcyBvZiBhIGRlY2lzaW9uIOKAlCBpcyBvbmx5XG4gKiAgIHZpc2libGUgcG9zdC1ydW4gdmlhIGBleGVjdXRvci5nZXRTbmFwc2hvdCgpYCB0cmVlLXdhbGtpbmcuXG4gKlxuICogICBTdHJlYW1pbmcgY29uc3VtZXJzIChsaXZlIFVJcywgaW4tZmxpZ2h0IGRlYnVnZ2Vycykgc2VlIG9ubHkgdGhlIGV2ZW50XG4gKiAgIHN0cmVhbS4gRXZlcnkgc3VjaCBjb25zdW1lciBoYXMgdG8gcmVidWlsZCBzdWJmbG93LXN0YWNrICsgZm9yay1tYXAgK1xuICogICBkZWNpc2lvbi10cmFja2VyIGZyb20gc2NyYXRjaCwgdXN1YWxseSBzbGlnaHRseSB3cm9uZyBpbiBkaWZmZXJlbnQgd2F5cy5cbiAqXG4gKiAgIFRvcG9sb2d5UmVjb3JkZXIgaXMgdGhlIHN0YW5kYXJkIGFjY3VtdWxhdG9yOiBvbmUgc3Vic2NyaXB0aW9uIHRvIHRoZVxuICogICB0aHJlZSBwcmltaXRpdmUgY2hhbm5lbHMsIG9uZSBsaXZlIGdyYXBoLCBxdWVyeWFibGUgYXQgYW55IG1vbWVudCBkdXJpbmdcbiAqICAgb3IgYWZ0ZXIgYSBydW4uXG4gKlxuICogV2hhdCBpdCByZWNvcmRzIOKAlCBUSFJFRSBub2RlIGtpbmRzIGZvciBjb21wbGV0ZSBjb21wb3NpdGlvbiBjb3ZlcmFnZTpcbiAqICAgMS4gJ3N1YmZsb3cnICAgICAgICAgIOKAlCB2aWEgb25TdWJmbG93RW50cnkgKGEgbW91bnRlZCBzdWJmbG93IGJvdW5kYXJ5KVxuICogICAyLiAnZm9yay1icmFuY2gnICAgICAg4oCUIHZpYSBvbkZvcmsgKG9uZSBub2RlIHBlciBjaGlsZCwgc3ludGhlc2l6ZWQpXG4gKiAgIDMuICdkZWNpc2lvbi1icmFuY2gnICDigJQgdmlhIG9uRGVjaXNpb24gKHRoZSBjaG9zZW4gYnJhbmNoLCBzeW50aGVzaXplZClcbiAqXG4gKiAgIFdoZW4gYSBmb3JrLWJyYW5jaCBvciBkZWNpc2lvbi1icmFuY2ggdGFyZ2V0IElTIEFMU08gYSBzdWJmbG93LCB0aGVcbiAqICAgc3Vic2VxdWVudCBvblN1YmZsb3dFbnRyeSBjcmVhdGVzIGEgc3ViZmxvdyBDSElMRCBvZiB0aGUgc3ludGhldGljIG5vZGUuXG4gKiAgIFRoZSBsYXllcmVkIHNoYXBlIHByZXNlcnZlcyBib3RoIFwid2hvIGJyYW5jaGVkXCIgYW5kIFwid2hhdCB0aGUgYnJhbmNoIHJhbi5cIlxuICpcbiAqICAgUGxhaW4gc2VxdWVudGlhbCBzdGFnZXMgYXJlIE5PVCBub2RlcyDigJQgdGhhdCdzIFN0YWdlQ29udGV4dCdzIGpvYi5cbiAqICAgVG9wb2xvZ3kgaXMgYSBncmFwaCBvZiBjb250cm9sLWZsb3cgYnJhbmNoaW5nLCBub3QgYSBmdWxsIGV4ZWN1dGlvbiB0cmVlLlxuICpcbiAqIEVkZ2VzOlxuICogICBPbmUgZWRnZSBwZXIgdHJhdmVyc2FsIHRyYW5zaXRpb24g4oCUIGBraW5kYCBtYXRjaGVzIHRoZSBjaGlsZCdzXG4gKiAgIGBpbmNvbWluZ0tpbmRgLiBBIGNvbnN1bWVyIHJlbmRlcmluZyBcInBhcmFsbGVsIGNvbHVtbnNcIiBmaWx0ZXJzIGVkZ2VzXG4gKiAgIHdoZXJlIGBraW5kID09PSAnZm9yay1icmFuY2gnYCBzaGFyaW5nIHRoZSBzYW1lIGBmcm9tYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgdG9wb2xvZ3lSZWNvcmRlciB9IGZyb20gJ2Zvb3RwcmludGpzL3RyYWNlJztcbiAqXG4gKiBjb25zdCB0b3BvID0gdG9wb2xvZ3lSZWNvcmRlcigpO1xuICogZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcih0b3BvKTsgIC8vIGF1dG8tcm91dGVzIHRvIEZsb3dSZWNvcmRlciBjaGFubmVsXG4gKlxuICogYXdhaXQgZXhlY3V0b3IucnVuKCk7XG4gKlxuICogY29uc3QgeyBub2RlcywgZWRnZXMsIGFjdGl2ZU5vZGVJZCwgcm9vdElkIH0gPSB0b3BvLmdldFRvcG9sb2d5KCk7XG4gKiAvLyBDb25zdW1lciBxdWVyaWVzOlxuICogdG9wby5nZXRDaGlsZHJlbignc2YtcGFyZW50Jyk7ICAgICAgICAgICAgICAvLyBkaXJlY3QgY2hpbGRyZW4gKGFueSBraW5kKVxuICogdG9wby5nZXRCeUtpbmQoJ2ZvcmstYnJhbmNoJyk7ICAgICAgICAgICAgICAvLyBhbGwgcGFyYWxsZWwgYnJhbmNoZXNcbiAqIHRvcG8uZ2V0U3ViZmxvd05vZGVzKCk7ICAgICAgICAgICAgICAgICAgICAgLy8gb25seSBtb3VudGVkIHN1YmZsb3dzXG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIEZsb3dEZWNpc2lvbkV2ZW50LFxuICBGbG93Rm9ya0V2ZW50LFxuICBGbG93TG9vcEV2ZW50LFxuICBGbG93UmVjb3JkZXIsXG4gIEZsb3dTdWJmbG93RXZlbnQsXG59IGZyb20gJy4uL2VuZ2luZS9uYXJyYXRpdmUvdHlwZXMuanMnO1xuXG4vKiogVGhlIGtpbmQgb2YgY29tcG9zaXRpb24gdW5pdCBhIG5vZGUgcmVwcmVzZW50cy4gKi9cbmV4cG9ydCB0eXBlIFRvcG9sb2d5Tm9kZUtpbmQgPSAnc3ViZmxvdycgfCAnZm9yay1icmFuY2gnIHwgJ2RlY2lzaW9uLWJyYW5jaCc7XG5cbi8qKiBIb3cgdGhlIHRyYXZlcnNhbCByZWFjaGVkIHRoaXMgbm9kZSDigJQgZHJpdmVzIGNvbnN1bWVyIGxheW91dCBkZWNpc2lvbnMuICovXG5leHBvcnQgdHlwZSBUb3BvbG9neUluY29taW5nS2luZCA9ICdyb290JyB8ICduZXh0JyB8ICdmb3JrLWJyYW5jaCcgfCAnZGVjaXNpb24tYnJhbmNoJyB8ICdsb29wLWl0ZXJhdGlvbic7XG5cbi8qKiBBIGNvbXBvc2l0aW9uLXNpZ25pZmljYW50IHBvaW50IGluIHRoZSBncmFwaC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9wb2xvZ3lOb2RlIHtcbiAgLyoqIFVuaXF1ZSBpZC4gU3ViZmxvd3MgdXNlIHRoZWlyIHN1YmZsb3dJZCAod2l0aCBgI25gIHN1ZmZpeCBvbiByZS1lbnRyeSkuXG4gICAqICBTeW50aGV0aWMgbm9kZXMgKGZvcmstYnJhbmNoIC8gZGVjaXNpb24tYnJhbmNoKSB1c2VcbiAgICogIGBmb3JrLSR7cnVudGltZVN0YWdlSWR9LSR7aX1gIC8gYGRlY2lzaW9uLSR7cnVudGltZVN0YWdlSWR9YCBmb3JtLiAqL1xuICByZWFkb25seSBpZDogc3RyaW5nO1xuICAvKiogV2hhdCB0aGlzIG5vZGUgcmVwcmVzZW50cy4gKi9cbiAgcmVhZG9ubHkga2luZDogVG9wb2xvZ3lOb2RlS2luZDtcbiAgLyoqIERpc3BsYXkgbmFtZS4gRm9yIHN1YmZsb3dzOiBgRmxvd1N1YmZsb3dFdmVudC5uYW1lYC4gRm9yIGZvcmstYnJhbmNoZXM6XG4gICAqICB0aGUgY2hpbGQgbmFtZSBmcm9tIGBGbG93Rm9ya0V2ZW50LmNoaWxkcmVuYC4gRm9yIGRlY2lzaW9uLWJyYW5jaGVzOlxuICAgKiAgdGhlIGNob3NlbiBuYW1lIGZyb20gYEZsb3dEZWNpc2lvbkV2ZW50LmNob3NlbmAuICovXG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgLyoqIFBhcmVudCBub2RlIGlkLiBVbmRlZmluZWQgd2hlbiB0aGlzIG5vZGUgc2l0cyBhdCB0aGUgcnVuJ3MgdG9wIGxldmVsLiAqL1xuICByZWFkb25seSBwYXJlbnRJZD86IHN0cmluZztcbiAgLyoqIERlcHRoIGluIHRoZSB0b3BvbG9neSB0cmVlICgwID0gdG9wLWxldmVsKS4gKi9cbiAgcmVhZG9ubHkgZGVwdGg6IG51bWJlcjtcbiAgLyoqIEhvdyB0aGUgdHJhdmVyc2FsIHJlYWNoZWQgdGhpcyBub2RlLiAqL1xuICByZWFkb25seSBpbmNvbWluZ0tpbmQ6IFRvcG9sb2d5SW5jb21pbmdLaW5kO1xuICAvKiogcnVudGltZVN0YWdlSWQgYXQgdGhlIG1vbWVudCB0aGUgbm9kZSB3YXMgY3JlYXRlZC4gKi9cbiAgcmVhZG9ubHkgZW50ZXJlZEF0OiBzdHJpbmc7XG4gIC8qKiBydW50aW1lU3RhZ2VJZCB3aGVuIHRoZSBjb3JyZXNwb25kaW5nIHN1YmZsb3cgZXhpdGVkLiBPbmx5IG1lYW5pbmdmdWxcbiAgICogIGZvciBraW5kPSdzdWJmbG93JzsgZm9yay9kZWNpc2lvbi1icmFuY2ggbm9kZXMgYXJlIGluc3RhbnRhbmVvdXMuICovXG4gIGV4aXRlZEF0Pzogc3RyaW5nO1xuICAvKiogS2luZC1zcGVjaWZpYyBleHRyYXM6IGZvcmtQYXJlbnQsIGRlY2lkZXIsIHJhdGlvbmFsZSwgZGVzY3JpcHRpb24uICovXG4gIHJlYWRvbmx5IG1ldGFkYXRhPzogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+O1xufVxuXG4vKiogQSB0cmF2ZXJzYWwgdHJhbnNpdGlvbiBiZXR3ZWVuIHR3byBub2Rlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9wb2xvZ3lFZGdlIHtcbiAgcmVhZG9ubHkgZnJvbTogc3RyaW5nO1xuICByZWFkb25seSB0bzogc3RyaW5nO1xuICByZWFkb25seSBraW5kOiBFeGNsdWRlPFRvcG9sb2d5SW5jb21pbmdLaW5kLCAncm9vdCc+O1xuICByZWFkb25seSBhdDogc3RyaW5nO1xufVxuXG4vKiogU25hcHNob3Qgb2YgdGhlIGNvbXBvc2l0aW9uIGdyYXBoLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb3BvbG9neSB7XG4gIHJlYWRvbmx5IG5vZGVzOiBSZWFkb25seUFycmF5PFRvcG9sb2d5Tm9kZT47XG4gIHJlYWRvbmx5IGVkZ2VzOiBSZWFkb25seUFycmF5PFRvcG9sb2d5RWRnZT47XG4gIC8qKiBDdXJyZW50bHktYWN0aXZlIHN1YmZsb3cgKHRvcCBvZiB0aGUgc3ViZmxvdyBzdGFjaykuIEZvcmstYnJhbmNoIGFuZFxuICAgKiAgZGVjaXNpb24tYnJhbmNoIG5vZGVzIGFyZSBpbnN0YW50YW5lb3VzIOKAlCB0aGV5IGRvbid0IGFmZmVjdCBhY3RpdmVOb2RlSWQuICovXG4gIHJlYWRvbmx5IGFjdGl2ZU5vZGVJZDogc3RyaW5nIHwgbnVsbDtcbiAgLyoqIEZpcnN0IG5vZGUgaW5zZXJ0ZWQuIG51bGwgYmVmb3JlIGFueSBjb21wb3NpdGlvbiBldmVudCBmaXJlcy4gKi9cbiAgcmVhZG9ubHkgcm9vdElkOiBzdHJpbmcgfCBudWxsO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRvcG9sb2d5UmVjb3JkZXJPcHRpb25zIHtcbiAgLyoqIFJlY29yZGVyIGlkLiBEZWZhdWx0cyB0byBgdG9wb2xvZ3ktTmAgKGF1dG8taW5jcmVtZW50ZWQpLiAqL1xuICBpZD86IHN0cmluZztcbn1cblxuLy8gQ29ycmVsYXRpb24gc3RhdGU6IG1hcHMgYSBwZW5kaW5nIGZvcmsvZGVjaXNpb24gY2hpbGQgbmFtZSB0byBpdHMgc3ludGhldGljXG4vLyBub2RlIGlkLCBzbyBhIHN1YnNlcXVlbnQgb25TdWJmbG93RW50cnkgbWF0Y2hpbmcgdGhhdCBuYW1lIGNhbiBiZSBuZXN0ZWRcbi8vIHVuZGVyIHRoZSBzeW50aGV0aWMgbm9kZSAocmF0aGVyIHRoYW4gY3JlYXRpbmcgYSBwZWVyKS5cbmludGVyZmFjZSBQZW5kaW5nQ2hpbGQge1xuICBub2RlSWQ6IHN0cmluZztcbiAgYXQ6IHN0cmluZztcbn1cblxubGV0IF9jb3VudGVyID0gMDtcblxuLyoqXG4gKiBGYWN0b3J5IOKAlCBtYXRjaGVzIHRoZSBgbmFycmF0aXZlKClgIC8gYG1ldHJpY3MoKWAgc3R5bGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b3BvbG9neVJlY29yZGVyKG9wdGlvbnM6IFRvcG9sb2d5UmVjb3JkZXJPcHRpb25zID0ge30pOiBUb3BvbG9neVJlY29yZGVyIHtcbiAgcmV0dXJuIG5ldyBUb3BvbG9neVJlY29yZGVyKG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFN0YXRlZnVsIGFjY3VtdWxhdG9yIHRoYXQgd2F0Y2hlcyBGbG93UmVjb3JkZXIgZXZlbnRzIGFuZCBtYWludGFpbnMgYSBsaXZlXG4gKiBjb21wb3NpdGlvbiBncmFwaC4gQXR0YWNoIHZpYSBgZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcihyZWNvcmRlcilgIOKAlFxuICogZm9vdHByaW50anMgZGV0ZWN0cyB0aGUgYEZsb3dSZWNvcmRlcmAgbWV0aG9kIHNoYXBlIGFuZCByb3V0ZXMgZXZlbnRzLlxuICovXG5leHBvcnQgY2xhc3MgVG9wb2xvZ3lSZWNvcmRlciBpbXBsZW1lbnRzIEZsb3dSZWNvcmRlciB7XG4gIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBub2Rlc0J5SWQgPSBuZXcgTWFwPHN0cmluZywgVG9wb2xvZ3lOb2RlPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IG5vZGVPcmRlcjogc3RyaW5nW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBlZGdlczogVG9wb2xvZ3lFZGdlW10gPSBbXTtcbiAgLyoqIFN0YWNrIG9mIGFjdGl2ZSBTVUJGTE9XIG5vZGUgaWRzLiBGb3JrL2RlY2lzaW9uLWJyYW5jaCBub2RlcyBuZXZlciBwdXNoLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHN1YmZsb3dTdGFjazogc3RyaW5nW10gPSBbXTtcblxuICAvKiogTWFwIG9mIGNoaWxkTmFtZSDihpIgcGVuZGluZyBmb3JrLWJyYW5jaCBzeW50aGV0aWMgbm9kZSwgY29uc3VtZWQgYnlcbiAgICogIHRoZSBuZXh0IG1hdGNoaW5nIGBvblN1YmZsb3dFbnRyeWAuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgcGVuZGluZ0ZvcmtCeU5hbWUgPSBuZXcgTWFwPHN0cmluZywgUGVuZGluZ0NoaWxkPigpO1xuICAvKiogUGVuZGluZyBkZWNpc2lvbi1icmFuY2ggc3ludGhldGljIG5vZGUsIGNvbnN1bWVkIGJ5IGEgbWF0Y2hpbmcgZW50cnkuICovXG4gIHByaXZhdGUgcGVuZGluZ0RlY2lzaW9uPzogeyBuYW1lOiBzdHJpbmcgfSAmIFBlbmRpbmdDaGlsZDtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBUb3BvbG9neVJlY29yZGVyT3B0aW9ucyA9IHt9KSB7XG4gICAgdGhpcy5pZCA9IG9wdGlvbnMuaWQgPz8gYHRvcG9sb2d5LSR7KytfY291bnRlcn1gO1xuICB9XG5cbiAgLy8g4pSA4pSAIEZsb3dSZWNvcmRlciBob29rcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBvblN1YmZsb3dFbnRyeShldmVudDogRmxvd1N1YmZsb3dFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHN1YmZsb3dJZCA9IGV2ZW50LnN1YmZsb3dJZDtcbiAgICBpZiAoIXN1YmZsb3dJZCkgcmV0dXJuOyAvLyBOZWVkIGEgc3RhYmxlIGlkIHRvIHRyYWNrLlxuXG4gICAgY29uc3QgZW50ZXJlZEF0ID0gZXZlbnQudHJhdmVyc2FsQ29udGV4dD8ucnVudGltZVN0YWdlSWQgPz8gJyc7XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIHBhcmVudDogcHJlZmVyIGEgcGVuZGluZyBmb3JrL2RlY2lzaW9uIG1hdGNoIGJ5IG5hbWUsXG4gICAgLy8gb3RoZXJ3aXNlIHRoZSBjdXJyZW50IHRvcC1vZi1zdWJmbG93LXN0YWNrLlxuICAgIGxldCBwYXJlbnRJZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGxldCBpbmNvbWluZ0tpbmQ6IFRvcG9sb2d5SW5jb21pbmdLaW5kO1xuXG4gICAgY29uc3QgcGVuZGluZ0ZvcmsgPSB0aGlzLnBlbmRpbmdGb3JrQnlOYW1lLmdldChldmVudC5uYW1lKTtcbiAgICBpZiAocGVuZGluZ0ZvcmspIHtcbiAgICAgIHBhcmVudElkID0gcGVuZGluZ0Zvcmsubm9kZUlkO1xuICAgICAgaW5jb21pbmdLaW5kID0gJ25leHQnOyAvLyBDaGlsZCBPRiBhIGZvcmstYnJhbmNoIG5vZGU7IHRoZSBmb3JrIHNlbWFudGljXG4gICAgICAvLyBpcyBjYXB0dXJlZCBieSB0aGUgZm9yay1icmFuY2gncyBvd24gaW5jb21pbmdLaW5kLlxuICAgICAgdGhpcy5wZW5kaW5nRm9ya0J5TmFtZS5kZWxldGUoZXZlbnQubmFtZSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLnBlbmRpbmdEZWNpc2lvbiAmJiB0aGlzLnBlbmRpbmdEZWNpc2lvbi5uYW1lID09PSBldmVudC5uYW1lKSB7XG4gICAgICBwYXJlbnRJZCA9IHRoaXMucGVuZGluZ0RlY2lzaW9uLm5vZGVJZDtcbiAgICAgIGluY29taW5nS2luZCA9ICduZXh0JztcbiAgICAgIHRoaXMucGVuZGluZ0RlY2lzaW9uID0gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSB7XG4gICAgICBwYXJlbnRJZCA9IHRoaXMuc3ViZmxvd1N0YWNrW3RoaXMuc3ViZmxvd1N0YWNrLmxlbmd0aCAtIDFdO1xuICAgICAgaW5jb21pbmdLaW5kID0gcGFyZW50SWQgPyAnbmV4dCcgOiAncm9vdCc7XG4gICAgfVxuXG4gICAgLy8gRGlzYW1iaWd1YXRlIHJlLWVudHJ5IChlLmcuLCBsb29wIGJvZHkgcmUtZW50ZXJzIHRoZSBzYW1lIHN1YmZsb3cpLlxuICAgIGxldCBub2RlSWQgPSBzdWJmbG93SWQ7XG4gICAgaWYgKHRoaXMubm9kZXNCeUlkLmhhcyhub2RlSWQpKSB7XG4gICAgICBsZXQgbiA9IDE7XG4gICAgICB3aGlsZSAodGhpcy5ub2Rlc0J5SWQuaGFzKGAke3N1YmZsb3dJZH0jJHtufWApKSBuKys7XG4gICAgICBub2RlSWQgPSBgJHtzdWJmbG93SWR9IyR7bn1gO1xuICAgIH1cblxuICAgIGNvbnN0IGRlcHRoID0gcGFyZW50SWQgPyB0aGlzLm5vZGVzQnlJZC5nZXQocGFyZW50SWQpIS5kZXB0aCArIDEgOiAwO1xuICAgIGNvbnN0IG1ldGFkYXRhID0gZXZlbnQuZGVzY3JpcHRpb24gPyB7IGRlc2NyaXB0aW9uOiBldmVudC5kZXNjcmlwdGlvbiB9IDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgbm9kZTogVG9wb2xvZ3lOb2RlID0ge1xuICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgIGtpbmQ6ICdzdWJmbG93JyxcbiAgICAgIG5hbWU6IGV2ZW50Lm5hbWUsXG4gICAgICBwYXJlbnRJZCxcbiAgICAgIGRlcHRoLFxuICAgICAgaW5jb21pbmdLaW5kLFxuICAgICAgZW50ZXJlZEF0LFxuICAgICAgbWV0YWRhdGEsXG4gICAgfTtcbiAgICB0aGlzLm5vZGVzQnlJZC5zZXQobm9kZUlkLCBub2RlKTtcbiAgICB0aGlzLm5vZGVPcmRlci5wdXNoKG5vZGVJZCk7XG5cbiAgICBpZiAocGFyZW50SWQgJiYgaW5jb21pbmdLaW5kICE9PSAncm9vdCcpIHtcbiAgICAgIHRoaXMuZWRnZXMucHVzaCh7XG4gICAgICAgIGZyb206IHBhcmVudElkLFxuICAgICAgICB0bzogbm9kZUlkLFxuICAgICAgICBraW5kOiBpbmNvbWluZ0tpbmQsXG4gICAgICAgIGF0OiBlbnRlcmVkQXQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLnN1YmZsb3dTdGFjay5wdXNoKG5vZGVJZCk7XG4gIH1cblxuICBvblN1YmZsb3dFeGl0KGV2ZW50OiBGbG93U3ViZmxvd0V2ZW50KTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZUlkID0gdGhpcy5zdWJmbG93U3RhY2sucG9wKCk7XG4gICAgaWYgKCFub2RlSWQpIHJldHVybjtcbiAgICBjb25zdCBub2RlID0gdGhpcy5ub2Rlc0J5SWQuZ2V0KG5vZGVJZCk7XG4gICAgaWYgKG5vZGUpIHtcbiAgICAgIG5vZGUuZXhpdGVkQXQgPSBldmVudC50cmF2ZXJzYWxDb250ZXh0Py5ydW50aW1lU3RhZ2VJZCA/PyAnJztcbiAgICB9XG4gICAgLy8gQSBzdWJmbG93IGV4aXQgaW1wbGllcyBubyBtb3JlIGNoaWxkcmVuIGFyZSBwZW5kaW5nIGZvciB0aGlzIHNjb3BlIOKAlFxuICAgIC8vIGNsZWFyIHN0YWxlIHBlbmRpbmcgc3RhdGUgdGhhdCBiZWxvbmdlZCB0byB0aGUgc2NvcGUgd2UganVzdCBsZWZ0LlxuICAgIHRoaXMucGVuZGluZ0ZvcmtCeU5hbWUuY2xlYXIoKTtcbiAgICB0aGlzLnBlbmRpbmdEZWNpc2lvbiA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIG9uRm9yayhldmVudDogRmxvd0ZvcmtFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGFjdGl2ZUlkID0gdGhpcy5zdWJmbG93U3RhY2tbdGhpcy5zdWJmbG93U3RhY2subGVuZ3RoIC0gMV07XG4gICAgY29uc3QgYXQgPSBldmVudC50cmF2ZXJzYWxDb250ZXh0Py5ydW50aW1lU3RhZ2VJZCA/PyAnJztcbiAgICBjb25zdCBkZXB0aCA9IGFjdGl2ZUlkID8gdGhpcy5ub2Rlc0J5SWQuZ2V0KGFjdGl2ZUlkKSEuZGVwdGggKyAxIDogMDtcblxuICAgIC8vIFJlc2V0IGFueSBwcmlvciBwZW5kaW5nIGZvcmsgc3RhdGUg4oCUIGEgbmV3IGZvcmsgc3RhcnRzIGZyZXNoLlxuICAgIHRoaXMucGVuZGluZ0ZvcmtCeU5hbWUuY2xlYXIoKTtcblxuICAgIGV2ZW50LmNoaWxkcmVuLmZvckVhY2goKGNoaWxkTmFtZSwgaSkgPT4ge1xuICAgICAgY29uc3Qgbm9kZUlkID0gYGZvcmstJHthdCB8fCBldmVudC5wYXJlbnR9LSR7aX0tJHtjaGlsZE5hbWV9YDtcbiAgICAgIGNvbnN0IG5vZGU6IFRvcG9sb2d5Tm9kZSA9IHtcbiAgICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgICAga2luZDogJ2ZvcmstYnJhbmNoJyxcbiAgICAgICAgbmFtZTogY2hpbGROYW1lLFxuICAgICAgICBwYXJlbnRJZDogYWN0aXZlSWQsXG4gICAgICAgIGRlcHRoLFxuICAgICAgICBpbmNvbWluZ0tpbmQ6ICdmb3JrLWJyYW5jaCcsXG4gICAgICAgIGVudGVyZWRBdDogYXQsXG4gICAgICAgIG1ldGFkYXRhOiB7IGZvcmtQYXJlbnQ6IGV2ZW50LnBhcmVudCB9LFxuICAgICAgfTtcbiAgICAgIHRoaXMubm9kZXNCeUlkLnNldChub2RlSWQsIG5vZGUpO1xuICAgICAgdGhpcy5ub2RlT3JkZXIucHVzaChub2RlSWQpO1xuICAgICAgaWYgKGFjdGl2ZUlkKSB7XG4gICAgICAgIHRoaXMuZWRnZXMucHVzaCh7IGZyb206IGFjdGl2ZUlkLCB0bzogbm9kZUlkLCBraW5kOiAnZm9yay1icmFuY2gnLCBhdCB9KTtcbiAgICAgIH1cbiAgICAgIHRoaXMucGVuZGluZ0ZvcmtCeU5hbWUuc2V0KGNoaWxkTmFtZSwgeyBub2RlSWQsIGF0IH0pO1xuICAgIH0pO1xuICB9XG5cbiAgb25EZWNpc2lvbihldmVudDogRmxvd0RlY2lzaW9uRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBhY3RpdmVJZCA9IHRoaXMuc3ViZmxvd1N0YWNrW3RoaXMuc3ViZmxvd1N0YWNrLmxlbmd0aCAtIDFdO1xuICAgIGNvbnN0IGF0ID0gZXZlbnQudHJhdmVyc2FsQ29udGV4dD8ucnVudGltZVN0YWdlSWQgPz8gJyc7XG4gICAgY29uc3QgZGVwdGggPSBhY3RpdmVJZCA/IHRoaXMubm9kZXNCeUlkLmdldChhY3RpdmVJZCkhLmRlcHRoICsgMSA6IDA7XG5cbiAgICAvLyBBIG5ldyBkZWNpc2lvbiBzdXBlcnNlZGVzIGFueSBwcmlvciB1bnJlc29sdmVkIHBlbmRpbmcgb25lLlxuICAgIHRoaXMucGVuZGluZ0RlY2lzaW9uID0gdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgbm9kZUlkID0gYGRlY2lzaW9uLSR7YXQgfHwgZXZlbnQuZGVjaWRlcn0tJHtldmVudC5jaG9zZW59YDtcbiAgICBjb25zdCBtZXRhZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7IGRlY2lkZXI6IGV2ZW50LmRlY2lkZXIgfTtcbiAgICBpZiAoZXZlbnQucmF0aW9uYWxlKSBtZXRhZGF0YS5yYXRpb25hbGUgPSBldmVudC5yYXRpb25hbGU7XG4gICAgaWYgKGV2ZW50LmRlc2NyaXB0aW9uKSBtZXRhZGF0YS5kZXNjcmlwdGlvbiA9IGV2ZW50LmRlc2NyaXB0aW9uO1xuXG4gICAgY29uc3Qgbm9kZTogVG9wb2xvZ3lOb2RlID0ge1xuICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgIGtpbmQ6ICdkZWNpc2lvbi1icmFuY2gnLFxuICAgICAgbmFtZTogZXZlbnQuY2hvc2VuLFxuICAgICAgcGFyZW50SWQ6IGFjdGl2ZUlkLFxuICAgICAgZGVwdGgsXG4gICAgICBpbmNvbWluZ0tpbmQ6ICdkZWNpc2lvbi1icmFuY2gnLFxuICAgICAgZW50ZXJlZEF0OiBhdCxcbiAgICAgIG1ldGFkYXRhLFxuICAgIH07XG4gICAgdGhpcy5ub2Rlc0J5SWQuc2V0KG5vZGVJZCwgbm9kZSk7XG4gICAgdGhpcy5ub2RlT3JkZXIucHVzaChub2RlSWQpO1xuICAgIGlmIChhY3RpdmVJZCkge1xuICAgICAgdGhpcy5lZGdlcy5wdXNoKHsgZnJvbTogYWN0aXZlSWQsIHRvOiBub2RlSWQsIGtpbmQ6ICdkZWNpc2lvbi1icmFuY2gnLCBhdCB9KTtcbiAgICB9XG4gICAgdGhpcy5wZW5kaW5nRGVjaXNpb24gPSB7IG5hbWU6IGV2ZW50LmNob3Nlbiwgbm9kZUlkLCBhdCB9O1xuICB9XG5cbiAgb25Mb29wKGV2ZW50OiBGbG93TG9vcEV2ZW50KTogdm9pZCB7XG4gICAgLy8gbG9vcFRvIGp1bXBzIGJhY2sgaW5zaWRlIHRoZSBDVVJSRU5UIHN1YmZsb3cuIFJlY29yZCBhIHNlbGYtZWRnZSBvbiB0aGVcbiAgICAvLyBhY3RpdmUgc3ViZmxvdyDigJQgc3ludGhldGljIGZvcmsvZGVjaXNpb24gbm9kZXMgZG9uJ3QgcGFydGljaXBhdGUgaW4gbG9vcHMuXG4gICAgY29uc3QgYWN0aXZlSWQgPSB0aGlzLnN1YmZsb3dTdGFja1t0aGlzLnN1YmZsb3dTdGFjay5sZW5ndGggLSAxXTtcbiAgICBpZiAoIWFjdGl2ZUlkKSByZXR1cm47XG4gICAgdGhpcy5lZGdlcy5wdXNoKHtcbiAgICAgIGZyb206IGFjdGl2ZUlkLFxuICAgICAgdG86IGFjdGl2ZUlkLFxuICAgICAga2luZDogJ2xvb3AtaXRlcmF0aW9uJyxcbiAgICAgIGF0OiBldmVudC50cmF2ZXJzYWxDb250ZXh0Py5ydW50aW1lU3RhZ2VJZCA/PyAnJyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBDYWxsZWQgYnkgdGhlIGV4ZWN1dG9yIGJlZm9yZSBlYWNoIGBydW4oKWAg4oCUIHJlc2V0cyBhbGwgc3RhdGUuICovXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMubm9kZXNCeUlkLmNsZWFyKCk7XG4gICAgdGhpcy5ub2RlT3JkZXIubGVuZ3RoID0gMDtcbiAgICB0aGlzLmVkZ2VzLmxlbmd0aCA9IDA7XG4gICAgdGhpcy5zdWJmbG93U3RhY2subGVuZ3RoID0gMDtcbiAgICB0aGlzLnBlbmRpbmdGb3JrQnlOYW1lLmNsZWFyKCk7XG4gICAgdGhpcy5wZW5kaW5nRGVjaXNpb24gPSB1bmRlZmluZWQ7XG4gIH1cblxuICAvLyDilIDilIAgUXVlcnkgQVBJIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBMaXZlIHNuYXBzaG90IG9mIHRoZSBjb21wb3NpdGlvbiBncmFwaC4gU2FmZSBkdXJpbmcgb3IgYWZ0ZXIgYSBydW4uICovXG4gIGdldFRvcG9sb2d5KCk6IFRvcG9sb2d5IHtcbiAgICBjb25zdCBub2RlcyA9IHRoaXMubm9kZU9yZGVyLm1hcCgoaWQpID0+IHRoaXMubm9kZXNCeUlkLmdldChpZCkhKTtcbiAgICByZXR1cm4ge1xuICAgICAgbm9kZXMsXG4gICAgICBlZGdlczogWy4uLnRoaXMuZWRnZXNdLFxuICAgICAgYWN0aXZlTm9kZUlkOiB0aGlzLnN1YmZsb3dTdGFja1t0aGlzLnN1YmZsb3dTdGFjay5sZW5ndGggLSAxXSA/PyBudWxsLFxuICAgICAgcm9vdElkOiB0aGlzLm5vZGVPcmRlclswXSA/PyBudWxsLFxuICAgIH07XG4gIH1cblxuICAvKiogRGlyZWN0IGNoaWxkcmVuIG9mIGEgbm9kZSDigJQgaW5zZXJ0aW9uLW9yZGVyZWQuICovXG4gIGdldENoaWxkcmVuKG5vZGVJZDogc3RyaW5nKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLm5vZGVPcmRlci5tYXAoKGlkKSA9PiB0aGlzLm5vZGVzQnlJZC5nZXQoaWQpISkuZmlsdGVyKChuKSA9PiBuLnBhcmVudElkID09PSBub2RlSWQpO1xuICB9XG5cbiAgLyoqIEFsbCBub2RlcyBvZiBhIGdpdmVuIGtpbmQuICovXG4gIGdldEJ5S2luZChraW5kOiBUb3BvbG9neU5vZGVLaW5kKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLm5vZGVPcmRlci5tYXAoKGlkKSA9PiB0aGlzLm5vZGVzQnlJZC5nZXQoaWQpISkuZmlsdGVyKChuKSA9PiBuLmtpbmQgPT09IGtpbmQpO1xuICB9XG5cbiAgLyoqIEFsbCBtb3VudGVkIHN1YmZsb3cgbm9kZXMuIENvbnZlbmllbmNlIGZvciBhZ2VudC1jZW50cmljIHZpZXdzLiAqL1xuICBnZXRTdWJmbG93Tm9kZXMoKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLmdldEJ5S2luZCgnc3ViZmxvdycpO1xuICB9XG5cbiAgLyoqIEFsbCBmb3JrLWJyYW5jaCBub2RlcyBzaGFyaW5nIHRoZSBzYW1lIHBhcmVudCBhcyBgbm9kZUlkYCDigJQgaS5lLixcbiAgICogIHBhcmFsbGVsIHNpYmxpbmdzIG9mIGEgcGFyYWxsZWwgYnJhbmNoLiBFbXB0eSBpZiBgbm9kZUlkYCBpc24ndCBhXG4gICAqICBmb3JrLWJyYW5jaCBvciBoYXMgbm8gcGFyZW50LiAqL1xuICBnZXRQYXJhbGxlbFNpYmxpbmdzKG5vZGVJZDogc3RyaW5nKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIGNvbnN0IG5vZGUgPSB0aGlzLm5vZGVzQnlJZC5nZXQobm9kZUlkKTtcbiAgICBpZiAoIW5vZGUgfHwgbm9kZS5raW5kICE9PSAnZm9yay1icmFuY2gnIHx8ICFub2RlLnBhcmVudElkKSByZXR1cm4gW107XG4gICAgcmV0dXJuIHRoaXMuZ2V0Q2hpbGRyZW4obm9kZS5wYXJlbnRJZCkuZmlsdGVyKChuKSA9PiBuLmtpbmQgPT09ICdmb3JrLWJyYW5jaCcpO1xuICB9XG5cbiAgLyoqIEVtaXQgYSBzbmFwc2hvdCBidW5kbGUgZm9yIGluY2x1c2lvbiBpbiBgZXhlY3V0b3IuZ2V0U25hcHNob3QoKWAuICovXG4gIHRvU25hcHNob3QoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6ICdUb3BvbG9neScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0NvbXBvc2l0aW9uIGdyYXBoOiBzdWJmbG93IGJvdW5kYXJpZXMsIGZvcmsgYnJhbmNoZXMsIGRlY2lzaW9uIGJyYW5jaGVzJyxcbiAgICAgIHByZWZlcnJlZE9wZXJhdGlvbjogJ3RyYW5zbGF0ZScgYXMgY29uc3QsXG4gICAgICBkYXRhOiB0aGlzLmdldFRvcG9sb2d5KCksXG4gICAgfTtcbiAgfVxufVxuIl19
package/dist/esm/trace.js CHANGED
@@ -28,6 +28,7 @@ export { causalChain, flattenCausalDAG, formatCausalChain } from './lib/memory/b
28
28
  export { KeyedRecorder } from './lib/recorder/KeyedRecorder.js';
29
29
  // SequenceRecorder — base class for 1:N ordered sequence recorders with keyed index
30
30
  export { SequenceRecorder } from './lib/recorder/SequenceRecorder.js';
31
+ export { TopologyRecorder, topologyRecorder } from './lib/recorder/TopologyRecorder.js';
31
32
  export { QualityRecorder } from './lib/recorder/QualityRecorder.js';
32
33
  export { formatQualityTrace, qualityTrace } from './lib/recorder/qualityTrace.js';
33
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUlILE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWxILHdEQUF3RDtBQUN4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RixPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0YseURBQXlEO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVoRSxvRkFBb0Y7QUFDcEYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFJdEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBSXBFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxZQUFZLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZm9vdHByaW50anMvdHJhY2Ug4oCUIEV4ZWN1dGlvbiB0cmFjaW5nLCBkZWJ1Z2dpbmcsIGFuZCBiYWNrdHJhY2tpbmcgdXRpbGl0aWVzLlxuICpcbiAqIFJ1bnRpbWUgc3RhZ2UgSURzLCBjb21taXQgbG9nIHF1ZXJpZXMsIGFuZCByZWNvcmRlciBiYXNlIGNsYXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHBhcnNlUnVudGltZVN0YWdlSWQsIGZpbmRMYXN0V3JpdGVyLCBLZXllZFJlY29yZGVyLCBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIC8vIFBhcnNlIGEgcnVudGltZVN0YWdlSWRcbiAqIGNvbnN0IHsgc3RhZ2VJZCwgZXhlY3V0aW9uSW5kZXggfSA9IHBhcnNlUnVudGltZVN0YWdlSWQoJ2NhbGwtbGxtIzUnKTtcbiAqXG4gKiAvLyBCYWNrdHJhY2s6IHdobyB3cm90ZSAnc3lzdGVtUHJvbXB0JyBiZWZvcmUgc3RhZ2UgYXQgaWR4IDg/XG4gKiBjb25zdCB3cml0ZXIgPSBmaW5kTGFzdFdyaXRlcihjb21taXRMb2csICdzeXN0ZW1Qcm9tcHQnLCA4KTtcbiAqXG4gKiAvLyBCdWlsZCBhIGtleWVkIHJlY29yZGVyICgxOjEg4oCUIG9uZSBlbnRyeSBwZXIgc3RlcClcbiAqIGNsYXNzIE15UmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPE15RW50cnk+IHsgLi4uIH1cbiAqXG4gKiAvLyBCdWlsZCBhIHNlcXVlbmNlIHJlY29yZGVyICgxOk4g4oCUIG11bHRpcGxlIGVudHJpZXMgcGVyIHN0ZXAsIG9yZGVyaW5nIG1hdHRlcnMpXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBSdW50aW1lIHN0YWdlIElEIOKAlCB1bmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllcnNcbmV4cG9ydCB0eXBlIHsgRXhlY3V0aW9uQ291bnRlciB9IGZyb20gJy4vbGliL2VuZ2luZS9ydW50aW1lU3RhZ2VJZC5qcyc7XG5leHBvcnQgeyBidWlsZFJ1bnRpbWVTdGFnZUlkLCBjcmVhdGVFeGVjdXRpb25Db3VudGVyLCBwYXJzZVJ1bnRpbWVTdGFnZUlkIH0gZnJvbSAnLi9saWIvZW5naW5lL3J1bnRpbWVTdGFnZUlkLmpzJztcblxuLy8gQ29tbWl0IGxvZyBxdWVyaWVzIOKAlCB0eXBlZCB1dGlsaXRpZXMgZm9yIGJhY2t0cmFja2luZ1xuZXhwb3J0IHsgZmluZENvbW1pdCwgZmluZENvbW1pdHMsIGZpbmRMYXN0V3JpdGVyIH0gZnJvbSAnLi9saWIvbWVtb3J5L2NvbW1pdExvZ1V0aWxzLmpzJztcblxuLy8gQ2F1c2FsIGNoYWluIOKAlCBiYWNrd2FyZCBwcm9ncmFtIHNsaWNpbmcgb24gY29tbWl0IGxvZyAoREFHKVxuZXhwb3J0IHR5cGUgeyBDYXVzYWxDaGFpbk9wdGlvbnMsIENhdXNhbE5vZGUsIEtleXNSZWFkTG9va3VwIH0gZnJvbSAnLi9saWIvbWVtb3J5L2JhY2t0cmFjay5qcyc7XG5leHBvcnQgeyBjYXVzYWxDaGFpbiwgZmxhdHRlbkNhdXNhbERBRywgZm9ybWF0Q2F1c2FsQ2hhaW4gfSBmcm9tICcuL2xpYi9tZW1vcnkvYmFja3RyYWNrLmpzJztcblxuLy8gS2V5ZWRSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMToxIE1hcC1iYXNlZCByZWNvcmRlcnNcbmV4cG9ydCB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9LZXllZFJlY29yZGVyLmpzJztcblxuLy8gU2VxdWVuY2VSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMTpOIG9yZGVyZWQgc2VxdWVuY2UgcmVjb3JkZXJzIHdpdGgga2V5ZWQgaW5kZXhcbmV4cG9ydCB7IFNlcXVlbmNlUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9TZXF1ZW5jZVJlY29yZGVyLmpzJztcblxuLy8gUXVhbGl0eVJlY29yZGVyIOKAlCBwZXItc3RlcCBxdWFsaXR5IHNjb3Jpbmcgd2l0aCBiYWNrdHJhY2tpbmdcbmV4cG9ydCB0eXBlIHsgUXVhbGl0eUVudHJ5LCBRdWFsaXR5UmVjb3JkZXJPcHRpb25zLCBRdWFsaXR5U2NvcmluZ0ZuIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvUXVhbGl0eVJlY29yZGVyLmpzJztcbmV4cG9ydCB7IFF1YWxpdHlSZWNvcmRlciB9IGZyb20gJy4vbGliL3JlY29yZGVyL1F1YWxpdHlSZWNvcmRlci5qcyc7XG5cbi8vIHF1YWxpdHlUcmFjZSDigJQgUXVhbGl0eSBTdGFjayBUcmFjZSAoYmFja3RyYWNrIGZyb20gbG93LXNjb3Jpbmcgc3RlcHMpXG5leHBvcnQgdHlwZSB7IFF1YWxpdHlGcmFtZSwgUXVhbGl0eVN0YWNrVHJhY2UgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UuanMnO1xuZXhwb3J0IHsgZm9ybWF0UXVhbGl0eVRyYWNlLCBxdWFsaXR5VHJhY2UgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UuanMnO1xuIl19
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUlILE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWxILHdEQUF3RDtBQUN4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RixPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0YseURBQXlEO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVoRSxvRkFBb0Y7QUFDcEYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFVdEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFJeEYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBSXBFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxZQUFZLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZm9vdHByaW50anMvdHJhY2Ug4oCUIEV4ZWN1dGlvbiB0cmFjaW5nLCBkZWJ1Z2dpbmcsIGFuZCBiYWNrdHJhY2tpbmcgdXRpbGl0aWVzLlxuICpcbiAqIFJ1bnRpbWUgc3RhZ2UgSURzLCBjb21taXQgbG9nIHF1ZXJpZXMsIGFuZCByZWNvcmRlciBiYXNlIGNsYXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHBhcnNlUnVudGltZVN0YWdlSWQsIGZpbmRMYXN0V3JpdGVyLCBLZXllZFJlY29yZGVyLCBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIC8vIFBhcnNlIGEgcnVudGltZVN0YWdlSWRcbiAqIGNvbnN0IHsgc3RhZ2VJZCwgZXhlY3V0aW9uSW5kZXggfSA9IHBhcnNlUnVudGltZVN0YWdlSWQoJ2NhbGwtbGxtIzUnKTtcbiAqXG4gKiAvLyBCYWNrdHJhY2s6IHdobyB3cm90ZSAnc3lzdGVtUHJvbXB0JyBiZWZvcmUgc3RhZ2UgYXQgaWR4IDg/XG4gKiBjb25zdCB3cml0ZXIgPSBmaW5kTGFzdFdyaXRlcihjb21taXRMb2csICdzeXN0ZW1Qcm9tcHQnLCA4KTtcbiAqXG4gKiAvLyBCdWlsZCBhIGtleWVkIHJlY29yZGVyICgxOjEg4oCUIG9uZSBlbnRyeSBwZXIgc3RlcClcbiAqIGNsYXNzIE15UmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPE15RW50cnk+IHsgLi4uIH1cbiAqXG4gKiAvLyBCdWlsZCBhIHNlcXVlbmNlIHJlY29yZGVyICgxOk4g4oCUIG11bHRpcGxlIGVudHJpZXMgcGVyIHN0ZXAsIG9yZGVyaW5nIG1hdHRlcnMpXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBSdW50aW1lIHN0YWdlIElEIOKAlCB1bmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllcnNcbmV4cG9ydCB0eXBlIHsgRXhlY3V0aW9uQ291bnRlciB9IGZyb20gJy4vbGliL2VuZ2luZS9ydW50aW1lU3RhZ2VJZC5qcyc7XG5leHBvcnQgeyBidWlsZFJ1bnRpbWVTdGFnZUlkLCBjcmVhdGVFeGVjdXRpb25Db3VudGVyLCBwYXJzZVJ1bnRpbWVTdGFnZUlkIH0gZnJvbSAnLi9saWIvZW5naW5lL3J1bnRpbWVTdGFnZUlkLmpzJztcblxuLy8gQ29tbWl0IGxvZyBxdWVyaWVzIOKAlCB0eXBlZCB1dGlsaXRpZXMgZm9yIGJhY2t0cmFja2luZ1xuZXhwb3J0IHsgZmluZENvbW1pdCwgZmluZENvbW1pdHMsIGZpbmRMYXN0V3JpdGVyIH0gZnJvbSAnLi9saWIvbWVtb3J5L2NvbW1pdExvZ1V0aWxzLmpzJztcblxuLy8gQ2F1c2FsIGNoYWluIOKAlCBiYWNrd2FyZCBwcm9ncmFtIHNsaWNpbmcgb24gY29tbWl0IGxvZyAoREFHKVxuZXhwb3J0IHR5cGUgeyBDYXVzYWxDaGFpbk9wdGlvbnMsIENhdXNhbE5vZGUsIEtleXNSZWFkTG9va3VwIH0gZnJvbSAnLi9saWIvbWVtb3J5L2JhY2t0cmFjay5qcyc7XG5leHBvcnQgeyBjYXVzYWxDaGFpbiwgZmxhdHRlbkNhdXNhbERBRywgZm9ybWF0Q2F1c2FsQ2hhaW4gfSBmcm9tICcuL2xpYi9tZW1vcnkvYmFja3RyYWNrLmpzJztcblxuLy8gS2V5ZWRSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMToxIE1hcC1iYXNlZCByZWNvcmRlcnNcbmV4cG9ydCB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9LZXllZFJlY29yZGVyLmpzJztcblxuLy8gU2VxdWVuY2VSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMTpOIG9yZGVyZWQgc2VxdWVuY2UgcmVjb3JkZXJzIHdpdGgga2V5ZWQgaW5kZXhcbmV4cG9ydCB7IFNlcXVlbmNlUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9TZXF1ZW5jZVJlY29yZGVyLmpzJztcblxuLy8gVG9wb2xvZ3lSZWNvcmRlciDigJQgY29tcG9zaXRpb24gZ3JhcGggYWNjdW11bGF0b3IgKHN1YmZsb3dzICsgY29udHJvbC1mbG93IGVkZ2VzKVxuZXhwb3J0IHR5cGUge1xuICBUb3BvbG9neSxcbiAgVG9wb2xvZ3lFZGdlLFxuICBUb3BvbG9neUluY29taW5nS2luZCxcbiAgVG9wb2xvZ3lOb2RlLFxuICBUb3BvbG9neVJlY29yZGVyT3B0aW9ucyxcbn0gZnJvbSAnLi9saWIvcmVjb3JkZXIvVG9wb2xvZ3lSZWNvcmRlci5qcyc7XG5leHBvcnQgeyBUb3BvbG9neVJlY29yZGVyLCB0b3BvbG9neVJlY29yZGVyIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvVG9wb2xvZ3lSZWNvcmRlci5qcyc7XG5cbi8vIFF1YWxpdHlSZWNvcmRlciDigJQgcGVyLXN0ZXAgcXVhbGl0eSBzY29yaW5nIHdpdGggYmFja3RyYWNraW5nXG5leHBvcnQgdHlwZSB7IFF1YWxpdHlFbnRyeSwgUXVhbGl0eVJlY29yZGVyT3B0aW9ucywgUXVhbGl0eVNjb3JpbmdGbiB9IGZyb20gJy4vbGliL3JlY29yZGVyL1F1YWxpdHlSZWNvcmRlci5qcyc7XG5leHBvcnQgeyBRdWFsaXR5UmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9RdWFsaXR5UmVjb3JkZXIuanMnO1xuXG4vLyBxdWFsaXR5VHJhY2Ug4oCUIFF1YWxpdHkgU3RhY2sgVHJhY2UgKGJhY2t0cmFjayBmcm9tIGxvdy1zY29yaW5nIHN0ZXBzKVxuZXhwb3J0IHR5cGUgeyBRdWFsaXR5RnJhbWUsIFF1YWxpdHlTdGFja1RyYWNlIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvcXVhbGl0eVRyYWNlLmpzJztcbmV4cG9ydCB7IGZvcm1hdFF1YWxpdHlUcmFjZSwgcXVhbGl0eVRyYWNlIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvcXVhbGl0eVRyYWNlLmpzJztcbiJdfQ==
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ /**
3
+ * TopologyRecorder — composition graph built during traversal.
4
+ *
5
+ * The gap this fills:
6
+ * footprintjs fires atomic flow events (onSubflowEntry, onFork, onDecision,
7
+ * onLoop) but the accumulated *shape* of a run — who nests inside whom,
8
+ * which nodes are parallel siblings vs branches of a decision — is only
9
+ * visible post-run via `executor.getSnapshot()` tree-walking.
10
+ *
11
+ * Streaming consumers (live UIs, in-flight debuggers) see only the event
12
+ * stream. Every such consumer has to rebuild subflow-stack + fork-map +
13
+ * decision-tracker from scratch, usually slightly wrong in different ways.
14
+ *
15
+ * TopologyRecorder is the standard accumulator: one subscription to the
16
+ * three primitive channels, one live graph, queryable at any moment during
17
+ * or after a run.
18
+ *
19
+ * What it records — THREE node kinds for complete composition coverage:
20
+ * 1. 'subflow' — via onSubflowEntry (a mounted subflow boundary)
21
+ * 2. 'fork-branch' — via onFork (one node per child, synthesized)
22
+ * 3. 'decision-branch' — via onDecision (the chosen branch, synthesized)
23
+ *
24
+ * When a fork-branch or decision-branch target IS ALSO a subflow, the
25
+ * subsequent onSubflowEntry creates a subflow CHILD of the synthetic node.
26
+ * The layered shape preserves both "who branched" and "what the branch ran."
27
+ *
28
+ * Plain sequential stages are NOT nodes — that's StageContext's job.
29
+ * Topology is a graph of control-flow branching, not a full execution tree.
30
+ *
31
+ * Edges:
32
+ * One edge per traversal transition — `kind` matches the child's
33
+ * `incomingKind`. A consumer rendering "parallel columns" filters edges
34
+ * where `kind === 'fork-branch'` sharing the same `from`.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * import { topologyRecorder } from 'footprintjs/trace';
39
+ *
40
+ * const topo = topologyRecorder();
41
+ * executor.attachCombinedRecorder(topo); // auto-routes to FlowRecorder channel
42
+ *
43
+ * await executor.run();
44
+ *
45
+ * const { nodes, edges, activeNodeId, rootId } = topo.getTopology();
46
+ * // Consumer queries:
47
+ * topo.getChildren('sf-parent'); // direct children (any kind)
48
+ * topo.getByKind('fork-branch'); // all parallel branches
49
+ * topo.getSubflowNodes(); // only mounted subflows
50
+ * ```
51
+ */
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.TopologyRecorder = exports.topologyRecorder = void 0;
54
+ let _counter = 0;
55
+ /**
56
+ * Factory — matches the `narrative()` / `metrics()` style.
57
+ */
58
+ function topologyRecorder(options = {}) {
59
+ return new TopologyRecorder(options);
60
+ }
61
+ exports.topologyRecorder = topologyRecorder;
62
+ /**
63
+ * Stateful accumulator that watches FlowRecorder events and maintains a live
64
+ * composition graph. Attach via `executor.attachCombinedRecorder(recorder)` —
65
+ * footprintjs detects the `FlowRecorder` method shape and routes events.
66
+ */
67
+ class TopologyRecorder {
68
+ constructor(options = {}) {
69
+ var _a;
70
+ this.nodesById = new Map();
71
+ this.nodeOrder = [];
72
+ this.edges = [];
73
+ /** Stack of active SUBFLOW node ids. Fork/decision-branch nodes never push. */
74
+ this.subflowStack = [];
75
+ /** Map of childName → pending fork-branch synthetic node, consumed by
76
+ * the next matching `onSubflowEntry`. */
77
+ this.pendingForkByName = new Map();
78
+ this.id = (_a = options.id) !== null && _a !== void 0 ? _a : `topology-${++_counter}`;
79
+ }
80
+ // ── FlowRecorder hooks ────────────────────────────────────────────────
81
+ onSubflowEntry(event) {
82
+ var _a, _b;
83
+ const subflowId = event.subflowId;
84
+ if (!subflowId)
85
+ return; // Need a stable id to track.
86
+ const enteredAt = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
87
+ // Determine the parent: prefer a pending fork/decision match by name,
88
+ // otherwise the current top-of-subflow-stack.
89
+ let parentId;
90
+ let incomingKind;
91
+ const pendingFork = this.pendingForkByName.get(event.name);
92
+ if (pendingFork) {
93
+ parentId = pendingFork.nodeId;
94
+ incomingKind = 'next'; // Child OF a fork-branch node; the fork semantic
95
+ // is captured by the fork-branch's own incomingKind.
96
+ this.pendingForkByName.delete(event.name);
97
+ }
98
+ else if (this.pendingDecision && this.pendingDecision.name === event.name) {
99
+ parentId = this.pendingDecision.nodeId;
100
+ incomingKind = 'next';
101
+ this.pendingDecision = undefined;
102
+ }
103
+ else {
104
+ parentId = this.subflowStack[this.subflowStack.length - 1];
105
+ incomingKind = parentId ? 'next' : 'root';
106
+ }
107
+ // Disambiguate re-entry (e.g., loop body re-enters the same subflow).
108
+ let nodeId = subflowId;
109
+ if (this.nodesById.has(nodeId)) {
110
+ let n = 1;
111
+ while (this.nodesById.has(`${subflowId}#${n}`))
112
+ n++;
113
+ nodeId = `${subflowId}#${n}`;
114
+ }
115
+ const depth = parentId ? this.nodesById.get(parentId).depth + 1 : 0;
116
+ const metadata = event.description ? { description: event.description } : undefined;
117
+ const node = {
118
+ id: nodeId,
119
+ kind: 'subflow',
120
+ name: event.name,
121
+ parentId,
122
+ depth,
123
+ incomingKind,
124
+ enteredAt,
125
+ metadata,
126
+ };
127
+ this.nodesById.set(nodeId, node);
128
+ this.nodeOrder.push(nodeId);
129
+ if (parentId && incomingKind !== 'root') {
130
+ this.edges.push({
131
+ from: parentId,
132
+ to: nodeId,
133
+ kind: incomingKind,
134
+ at: enteredAt,
135
+ });
136
+ }
137
+ this.subflowStack.push(nodeId);
138
+ }
139
+ onSubflowExit(event) {
140
+ var _a, _b;
141
+ const nodeId = this.subflowStack.pop();
142
+ if (!nodeId)
143
+ return;
144
+ const node = this.nodesById.get(nodeId);
145
+ if (node) {
146
+ node.exitedAt = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
147
+ }
148
+ // A subflow exit implies no more children are pending for this scope —
149
+ // clear stale pending state that belonged to the scope we just left.
150
+ this.pendingForkByName.clear();
151
+ this.pendingDecision = undefined;
152
+ }
153
+ onFork(event) {
154
+ var _a, _b;
155
+ const activeId = this.subflowStack[this.subflowStack.length - 1];
156
+ const at = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
157
+ const depth = activeId ? this.nodesById.get(activeId).depth + 1 : 0;
158
+ // Reset any prior pending fork state — a new fork starts fresh.
159
+ this.pendingForkByName.clear();
160
+ event.children.forEach((childName, i) => {
161
+ const nodeId = `fork-${at || event.parent}-${i}-${childName}`;
162
+ const node = {
163
+ id: nodeId,
164
+ kind: 'fork-branch',
165
+ name: childName,
166
+ parentId: activeId,
167
+ depth,
168
+ incomingKind: 'fork-branch',
169
+ enteredAt: at,
170
+ metadata: { forkParent: event.parent },
171
+ };
172
+ this.nodesById.set(nodeId, node);
173
+ this.nodeOrder.push(nodeId);
174
+ if (activeId) {
175
+ this.edges.push({ from: activeId, to: nodeId, kind: 'fork-branch', at });
176
+ }
177
+ this.pendingForkByName.set(childName, { nodeId, at });
178
+ });
179
+ }
180
+ onDecision(event) {
181
+ var _a, _b;
182
+ const activeId = this.subflowStack[this.subflowStack.length - 1];
183
+ const at = (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '';
184
+ const depth = activeId ? this.nodesById.get(activeId).depth + 1 : 0;
185
+ // A new decision supersedes any prior unresolved pending one.
186
+ this.pendingDecision = undefined;
187
+ const nodeId = `decision-${at || event.decider}-${event.chosen}`;
188
+ const metadata = { decider: event.decider };
189
+ if (event.rationale)
190
+ metadata.rationale = event.rationale;
191
+ if (event.description)
192
+ metadata.description = event.description;
193
+ const node = {
194
+ id: nodeId,
195
+ kind: 'decision-branch',
196
+ name: event.chosen,
197
+ parentId: activeId,
198
+ depth,
199
+ incomingKind: 'decision-branch',
200
+ enteredAt: at,
201
+ metadata,
202
+ };
203
+ this.nodesById.set(nodeId, node);
204
+ this.nodeOrder.push(nodeId);
205
+ if (activeId) {
206
+ this.edges.push({ from: activeId, to: nodeId, kind: 'decision-branch', at });
207
+ }
208
+ this.pendingDecision = { name: event.chosen, nodeId, at };
209
+ }
210
+ onLoop(event) {
211
+ var _a, _b;
212
+ // loopTo jumps back inside the CURRENT subflow. Record a self-edge on the
213
+ // active subflow — synthetic fork/decision nodes don't participate in loops.
214
+ const activeId = this.subflowStack[this.subflowStack.length - 1];
215
+ if (!activeId)
216
+ return;
217
+ this.edges.push({
218
+ from: activeId,
219
+ to: activeId,
220
+ kind: 'loop-iteration',
221
+ at: (_b = (_a = event.traversalContext) === null || _a === void 0 ? void 0 : _a.runtimeStageId) !== null && _b !== void 0 ? _b : '',
222
+ });
223
+ }
224
+ /** Called by the executor before each `run()` — resets all state. */
225
+ clear() {
226
+ this.nodesById.clear();
227
+ this.nodeOrder.length = 0;
228
+ this.edges.length = 0;
229
+ this.subflowStack.length = 0;
230
+ this.pendingForkByName.clear();
231
+ this.pendingDecision = undefined;
232
+ }
233
+ // ── Query API ─────────────────────────────────────────────────────────
234
+ /** Live snapshot of the composition graph. Safe during or after a run. */
235
+ getTopology() {
236
+ var _a, _b;
237
+ const nodes = this.nodeOrder.map((id) => this.nodesById.get(id));
238
+ return {
239
+ nodes,
240
+ edges: [...this.edges],
241
+ activeNodeId: (_a = this.subflowStack[this.subflowStack.length - 1]) !== null && _a !== void 0 ? _a : null,
242
+ rootId: (_b = this.nodeOrder[0]) !== null && _b !== void 0 ? _b : null,
243
+ };
244
+ }
245
+ /** Direct children of a node — insertion-ordered. */
246
+ getChildren(nodeId) {
247
+ return this.nodeOrder.map((id) => this.nodesById.get(id)).filter((n) => n.parentId === nodeId);
248
+ }
249
+ /** All nodes of a given kind. */
250
+ getByKind(kind) {
251
+ return this.nodeOrder.map((id) => this.nodesById.get(id)).filter((n) => n.kind === kind);
252
+ }
253
+ /** All mounted subflow nodes. Convenience for agent-centric views. */
254
+ getSubflowNodes() {
255
+ return this.getByKind('subflow');
256
+ }
257
+ /** All fork-branch nodes sharing the same parent as `nodeId` — i.e.,
258
+ * parallel siblings of a parallel branch. Empty if `nodeId` isn't a
259
+ * fork-branch or has no parent. */
260
+ getParallelSiblings(nodeId) {
261
+ const node = this.nodesById.get(nodeId);
262
+ if (!node || node.kind !== 'fork-branch' || !node.parentId)
263
+ return [];
264
+ return this.getChildren(node.parentId).filter((n) => n.kind === 'fork-branch');
265
+ }
266
+ /** Emit a snapshot bundle for inclusion in `executor.getSnapshot()`. */
267
+ toSnapshot() {
268
+ return {
269
+ name: 'Topology',
270
+ description: 'Composition graph: subflow boundaries, fork branches, decision branches',
271
+ preferredOperation: 'translate',
272
+ data: this.getTopology(),
273
+ };
274
+ }
275
+ }
276
+ exports.TopologyRecorder = TopologyRecorder;
277
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9wb2xvZ3lSZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvcmVjb3JkZXIvVG9wb2xvZ3lSZWNvcmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpREc7OztBQTJFSCxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7QUFFakI7O0dBRUc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxVQUFtQyxFQUFFO0lBQ3BFLE9BQU8sSUFBSSxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUN2QyxDQUFDO0FBRkQsNENBRUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBYSxnQkFBZ0I7SUFlM0IsWUFBWSxVQUFtQyxFQUFFOztRQVpoQyxjQUFTLEdBQUcsSUFBSSxHQUFHLEVBQXdCLENBQUM7UUFDNUMsY0FBUyxHQUFhLEVBQUUsQ0FBQztRQUN6QixVQUFLLEdBQW1CLEVBQUUsQ0FBQztRQUM1QywrRUFBK0U7UUFDOUQsaUJBQVksR0FBYSxFQUFFLENBQUM7UUFFN0M7a0RBQzBDO1FBQ3pCLHNCQUFpQixHQUFHLElBQUksR0FBRyxFQUF3QixDQUFDO1FBS25FLElBQUksQ0FBQyxFQUFFLEdBQUcsTUFBQSxPQUFPLENBQUMsRUFBRSxtQ0FBSSxZQUFZLEVBQUUsUUFBUSxFQUFFLENBQUM7SUFDbkQsQ0FBQztJQUVELHlFQUF5RTtJQUV6RSxjQUFjLENBQUMsS0FBdUI7O1FBQ3BDLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7UUFDbEMsSUFBSSxDQUFDLFNBQVM7WUFBRSxPQUFPLENBQUMsNkJBQTZCO1FBRXJELE1BQU0sU0FBUyxHQUFHLE1BQUEsTUFBQSxLQUFLLENBQUMsZ0JBQWdCLDBDQUFFLGNBQWMsbUNBQUksRUFBRSxDQUFDO1FBRS9ELHNFQUFzRTtRQUN0RSw4Q0FBOEM7UUFDOUMsSUFBSSxR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RSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssYUFBYSxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUVELHdFQUF3RTtJQUN4RSxVQUFVO1FBQ1IsT0FBTztZQUNMLElBQUksRUFBRSxVQUFVO1lBQ2hCLFdBQVcsRUFBRSx5RUFBeUU7WUFDdEYsa0JBQWtCLEVBQUUsV0FBb0I7WUFDeEMsSUFBSSxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUU7U0FDekIsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQWpPRCw0Q0FpT0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRvcG9sb2d5UmVjb3JkZXIg4oCUIGNvbXBvc2l0aW9uIGdyYXBoIGJ1aWx0IGR1cmluZyB0cmF2ZXJzYWwuXG4gKlxuICogVGhlIGdhcCB0aGlzIGZpbGxzOlxuICogICBmb290cHJpbnRqcyBmaXJlcyBhdG9taWMgZmxvdyBldmVudHMgKG9uU3ViZmxvd0VudHJ5LCBvbkZvcmssIG9uRGVjaXNpb24sXG4gKiAgIG9uTG9vcCkgYnV0IHRoZSBhY2N1bXVsYXRlZCAqc2hhcGUqIG9mIGEgcnVuIOKAlCB3aG8gbmVzdHMgaW5zaWRlIHdob20sXG4gKiAgIHdoaWNoIG5vZGVzIGFyZSBwYXJhbGxlbCBzaWJsaW5ncyB2cyBicmFuY2hlcyBvZiBhIGRlY2lzaW9uIOKAlCBpcyBvbmx5XG4gKiAgIHZpc2libGUgcG9zdC1ydW4gdmlhIGBleGVjdXRvci5nZXRTbmFwc2hvdCgpYCB0cmVlLXdhbGtpbmcuXG4gKlxuICogICBTdHJlYW1pbmcgY29uc3VtZXJzIChsaXZlIFVJcywgaW4tZmxpZ2h0IGRlYnVnZ2Vycykgc2VlIG9ubHkgdGhlIGV2ZW50XG4gKiAgIHN0cmVhbS4gRXZlcnkgc3VjaCBjb25zdW1lciBoYXMgdG8gcmVidWlsZCBzdWJmbG93LXN0YWNrICsgZm9yay1tYXAgK1xuICogICBkZWNpc2lvbi10cmFja2VyIGZyb20gc2NyYXRjaCwgdXN1YWxseSBzbGlnaHRseSB3cm9uZyBpbiBkaWZmZXJlbnQgd2F5cy5cbiAqXG4gKiAgIFRvcG9sb2d5UmVjb3JkZXIgaXMgdGhlIHN0YW5kYXJkIGFjY3VtdWxhdG9yOiBvbmUgc3Vic2NyaXB0aW9uIHRvIHRoZVxuICogICB0aHJlZSBwcmltaXRpdmUgY2hhbm5lbHMsIG9uZSBsaXZlIGdyYXBoLCBxdWVyeWFibGUgYXQgYW55IG1vbWVudCBkdXJpbmdcbiAqICAgb3IgYWZ0ZXIgYSBydW4uXG4gKlxuICogV2hhdCBpdCByZWNvcmRzIOKAlCBUSFJFRSBub2RlIGtpbmRzIGZvciBjb21wbGV0ZSBjb21wb3NpdGlvbiBjb3ZlcmFnZTpcbiAqICAgMS4gJ3N1YmZsb3cnICAgICAgICAgIOKAlCB2aWEgb25TdWJmbG93RW50cnkgKGEgbW91bnRlZCBzdWJmbG93IGJvdW5kYXJ5KVxuICogICAyLiAnZm9yay1icmFuY2gnICAgICAg4oCUIHZpYSBvbkZvcmsgKG9uZSBub2RlIHBlciBjaGlsZCwgc3ludGhlc2l6ZWQpXG4gKiAgIDMuICdkZWNpc2lvbi1icmFuY2gnICDigJQgdmlhIG9uRGVjaXNpb24gKHRoZSBjaG9zZW4gYnJhbmNoLCBzeW50aGVzaXplZClcbiAqXG4gKiAgIFdoZW4gYSBmb3JrLWJyYW5jaCBvciBkZWNpc2lvbi1icmFuY2ggdGFyZ2V0IElTIEFMU08gYSBzdWJmbG93LCB0aGVcbiAqICAgc3Vic2VxdWVudCBvblN1YmZsb3dFbnRyeSBjcmVhdGVzIGEgc3ViZmxvdyBDSElMRCBvZiB0aGUgc3ludGhldGljIG5vZGUuXG4gKiAgIFRoZSBsYXllcmVkIHNoYXBlIHByZXNlcnZlcyBib3RoIFwid2hvIGJyYW5jaGVkXCIgYW5kIFwid2hhdCB0aGUgYnJhbmNoIHJhbi5cIlxuICpcbiAqICAgUGxhaW4gc2VxdWVudGlhbCBzdGFnZXMgYXJlIE5PVCBub2RlcyDigJQgdGhhdCdzIFN0YWdlQ29udGV4dCdzIGpvYi5cbiAqICAgVG9wb2xvZ3kgaXMgYSBncmFwaCBvZiBjb250cm9sLWZsb3cgYnJhbmNoaW5nLCBub3QgYSBmdWxsIGV4ZWN1dGlvbiB0cmVlLlxuICpcbiAqIEVkZ2VzOlxuICogICBPbmUgZWRnZSBwZXIgdHJhdmVyc2FsIHRyYW5zaXRpb24g4oCUIGBraW5kYCBtYXRjaGVzIHRoZSBjaGlsZCdzXG4gKiAgIGBpbmNvbWluZ0tpbmRgLiBBIGNvbnN1bWVyIHJlbmRlcmluZyBcInBhcmFsbGVsIGNvbHVtbnNcIiBmaWx0ZXJzIGVkZ2VzXG4gKiAgIHdoZXJlIGBraW5kID09PSAnZm9yay1icmFuY2gnYCBzaGFyaW5nIHRoZSBzYW1lIGBmcm9tYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgdG9wb2xvZ3lSZWNvcmRlciB9IGZyb20gJ2Zvb3RwcmludGpzL3RyYWNlJztcbiAqXG4gKiBjb25zdCB0b3BvID0gdG9wb2xvZ3lSZWNvcmRlcigpO1xuICogZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcih0b3BvKTsgIC8vIGF1dG8tcm91dGVzIHRvIEZsb3dSZWNvcmRlciBjaGFubmVsXG4gKlxuICogYXdhaXQgZXhlY3V0b3IucnVuKCk7XG4gKlxuICogY29uc3QgeyBub2RlcywgZWRnZXMsIGFjdGl2ZU5vZGVJZCwgcm9vdElkIH0gPSB0b3BvLmdldFRvcG9sb2d5KCk7XG4gKiAvLyBDb25zdW1lciBxdWVyaWVzOlxuICogdG9wby5nZXRDaGlsZHJlbignc2YtcGFyZW50Jyk7ICAgICAgICAgICAgICAvLyBkaXJlY3QgY2hpbGRyZW4gKGFueSBraW5kKVxuICogdG9wby5nZXRCeUtpbmQoJ2ZvcmstYnJhbmNoJyk7ICAgICAgICAgICAgICAvLyBhbGwgcGFyYWxsZWwgYnJhbmNoZXNcbiAqIHRvcG8uZ2V0U3ViZmxvd05vZGVzKCk7ICAgICAgICAgICAgICAgICAgICAgLy8gb25seSBtb3VudGVkIHN1YmZsb3dzXG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIEZsb3dEZWNpc2lvbkV2ZW50LFxuICBGbG93Rm9ya0V2ZW50LFxuICBGbG93TG9vcEV2ZW50LFxuICBGbG93UmVjb3JkZXIsXG4gIEZsb3dTdWJmbG93RXZlbnQsXG59IGZyb20gJy4uL2VuZ2luZS9uYXJyYXRpdmUvdHlwZXMuanMnO1xuXG4vKiogVGhlIGtpbmQgb2YgY29tcG9zaXRpb24gdW5pdCBhIG5vZGUgcmVwcmVzZW50cy4gKi9cbmV4cG9ydCB0eXBlIFRvcG9sb2d5Tm9kZUtpbmQgPSAnc3ViZmxvdycgfCAnZm9yay1icmFuY2gnIHwgJ2RlY2lzaW9uLWJyYW5jaCc7XG5cbi8qKiBIb3cgdGhlIHRyYXZlcnNhbCByZWFjaGVkIHRoaXMgbm9kZSDigJQgZHJpdmVzIGNvbnN1bWVyIGxheW91dCBkZWNpc2lvbnMuICovXG5leHBvcnQgdHlwZSBUb3BvbG9neUluY29taW5nS2luZCA9ICdyb290JyB8ICduZXh0JyB8ICdmb3JrLWJyYW5jaCcgfCAnZGVjaXNpb24tYnJhbmNoJyB8ICdsb29wLWl0ZXJhdGlvbic7XG5cbi8qKiBBIGNvbXBvc2l0aW9uLXNpZ25pZmljYW50IHBvaW50IGluIHRoZSBncmFwaC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9wb2xvZ3lOb2RlIHtcbiAgLyoqIFVuaXF1ZSBpZC4gU3ViZmxvd3MgdXNlIHRoZWlyIHN1YmZsb3dJZCAod2l0aCBgI25gIHN1ZmZpeCBvbiByZS1lbnRyeSkuXG4gICAqICBTeW50aGV0aWMgbm9kZXMgKGZvcmstYnJhbmNoIC8gZGVjaXNpb24tYnJhbmNoKSB1c2VcbiAgICogIGBmb3JrLSR7cnVudGltZVN0YWdlSWR9LSR7aX1gIC8gYGRlY2lzaW9uLSR7cnVudGltZVN0YWdlSWR9YCBmb3JtLiAqL1xuICByZWFkb25seSBpZDogc3RyaW5nO1xuICAvKiogV2hhdCB0aGlzIG5vZGUgcmVwcmVzZW50cy4gKi9cbiAgcmVhZG9ubHkga2luZDogVG9wb2xvZ3lOb2RlS2luZDtcbiAgLyoqIERpc3BsYXkgbmFtZS4gRm9yIHN1YmZsb3dzOiBgRmxvd1N1YmZsb3dFdmVudC5uYW1lYC4gRm9yIGZvcmstYnJhbmNoZXM6XG4gICAqICB0aGUgY2hpbGQgbmFtZSBmcm9tIGBGbG93Rm9ya0V2ZW50LmNoaWxkcmVuYC4gRm9yIGRlY2lzaW9uLWJyYW5jaGVzOlxuICAgKiAgdGhlIGNob3NlbiBuYW1lIGZyb20gYEZsb3dEZWNpc2lvbkV2ZW50LmNob3NlbmAuICovXG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgLyoqIFBhcmVudCBub2RlIGlkLiBVbmRlZmluZWQgd2hlbiB0aGlzIG5vZGUgc2l0cyBhdCB0aGUgcnVuJ3MgdG9wIGxldmVsLiAqL1xuICByZWFkb25seSBwYXJlbnRJZD86IHN0cmluZztcbiAgLyoqIERlcHRoIGluIHRoZSB0b3BvbG9neSB0cmVlICgwID0gdG9wLWxldmVsKS4gKi9cbiAgcmVhZG9ubHkgZGVwdGg6IG51bWJlcjtcbiAgLyoqIEhvdyB0aGUgdHJhdmVyc2FsIHJlYWNoZWQgdGhpcyBub2RlLiAqL1xuICByZWFkb25seSBpbmNvbWluZ0tpbmQ6IFRvcG9sb2d5SW5jb21pbmdLaW5kO1xuICAvKiogcnVudGltZVN0YWdlSWQgYXQgdGhlIG1vbWVudCB0aGUgbm9kZSB3YXMgY3JlYXRlZC4gKi9cbiAgcmVhZG9ubHkgZW50ZXJlZEF0OiBzdHJpbmc7XG4gIC8qKiBydW50aW1lU3RhZ2VJZCB3aGVuIHRoZSBjb3JyZXNwb25kaW5nIHN1YmZsb3cgZXhpdGVkLiBPbmx5IG1lYW5pbmdmdWxcbiAgICogIGZvciBraW5kPSdzdWJmbG93JzsgZm9yay9kZWNpc2lvbi1icmFuY2ggbm9kZXMgYXJlIGluc3RhbnRhbmVvdXMuICovXG4gIGV4aXRlZEF0Pzogc3RyaW5nO1xuICAvKiogS2luZC1zcGVjaWZpYyBleHRyYXM6IGZvcmtQYXJlbnQsIGRlY2lkZXIsIHJhdGlvbmFsZSwgZGVzY3JpcHRpb24uICovXG4gIHJlYWRvbmx5IG1ldGFkYXRhPzogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+O1xufVxuXG4vKiogQSB0cmF2ZXJzYWwgdHJhbnNpdGlvbiBiZXR3ZWVuIHR3byBub2Rlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9wb2xvZ3lFZGdlIHtcbiAgcmVhZG9ubHkgZnJvbTogc3RyaW5nO1xuICByZWFkb25seSB0bzogc3RyaW5nO1xuICByZWFkb25seSBraW5kOiBFeGNsdWRlPFRvcG9sb2d5SW5jb21pbmdLaW5kLCAncm9vdCc+O1xuICByZWFkb25seSBhdDogc3RyaW5nO1xufVxuXG4vKiogU25hcHNob3Qgb2YgdGhlIGNvbXBvc2l0aW9uIGdyYXBoLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb3BvbG9neSB7XG4gIHJlYWRvbmx5IG5vZGVzOiBSZWFkb25seUFycmF5PFRvcG9sb2d5Tm9kZT47XG4gIHJlYWRvbmx5IGVkZ2VzOiBSZWFkb25seUFycmF5PFRvcG9sb2d5RWRnZT47XG4gIC8qKiBDdXJyZW50bHktYWN0aXZlIHN1YmZsb3cgKHRvcCBvZiB0aGUgc3ViZmxvdyBzdGFjaykuIEZvcmstYnJhbmNoIGFuZFxuICAgKiAgZGVjaXNpb24tYnJhbmNoIG5vZGVzIGFyZSBpbnN0YW50YW5lb3VzIOKAlCB0aGV5IGRvbid0IGFmZmVjdCBhY3RpdmVOb2RlSWQuICovXG4gIHJlYWRvbmx5IGFjdGl2ZU5vZGVJZDogc3RyaW5nIHwgbnVsbDtcbiAgLyoqIEZpcnN0IG5vZGUgaW5zZXJ0ZWQuIG51bGwgYmVmb3JlIGFueSBjb21wb3NpdGlvbiBldmVudCBmaXJlcy4gKi9cbiAgcmVhZG9ubHkgcm9vdElkOiBzdHJpbmcgfCBudWxsO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRvcG9sb2d5UmVjb3JkZXJPcHRpb25zIHtcbiAgLyoqIFJlY29yZGVyIGlkLiBEZWZhdWx0cyB0byBgdG9wb2xvZ3ktTmAgKGF1dG8taW5jcmVtZW50ZWQpLiAqL1xuICBpZD86IHN0cmluZztcbn1cblxuLy8gQ29ycmVsYXRpb24gc3RhdGU6IG1hcHMgYSBwZW5kaW5nIGZvcmsvZGVjaXNpb24gY2hpbGQgbmFtZSB0byBpdHMgc3ludGhldGljXG4vLyBub2RlIGlkLCBzbyBhIHN1YnNlcXVlbnQgb25TdWJmbG93RW50cnkgbWF0Y2hpbmcgdGhhdCBuYW1lIGNhbiBiZSBuZXN0ZWRcbi8vIHVuZGVyIHRoZSBzeW50aGV0aWMgbm9kZSAocmF0aGVyIHRoYW4gY3JlYXRpbmcgYSBwZWVyKS5cbmludGVyZmFjZSBQZW5kaW5nQ2hpbGQge1xuICBub2RlSWQ6IHN0cmluZztcbiAgYXQ6IHN0cmluZztcbn1cblxubGV0IF9jb3VudGVyID0gMDtcblxuLyoqXG4gKiBGYWN0b3J5IOKAlCBtYXRjaGVzIHRoZSBgbmFycmF0aXZlKClgIC8gYG1ldHJpY3MoKWAgc3R5bGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b3BvbG9neVJlY29yZGVyKG9wdGlvbnM6IFRvcG9sb2d5UmVjb3JkZXJPcHRpb25zID0ge30pOiBUb3BvbG9neVJlY29yZGVyIHtcbiAgcmV0dXJuIG5ldyBUb3BvbG9neVJlY29yZGVyKG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFN0YXRlZnVsIGFjY3VtdWxhdG9yIHRoYXQgd2F0Y2hlcyBGbG93UmVjb3JkZXIgZXZlbnRzIGFuZCBtYWludGFpbnMgYSBsaXZlXG4gKiBjb21wb3NpdGlvbiBncmFwaC4gQXR0YWNoIHZpYSBgZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcihyZWNvcmRlcilgIOKAlFxuICogZm9vdHByaW50anMgZGV0ZWN0cyB0aGUgYEZsb3dSZWNvcmRlcmAgbWV0aG9kIHNoYXBlIGFuZCByb3V0ZXMgZXZlbnRzLlxuICovXG5leHBvcnQgY2xhc3MgVG9wb2xvZ3lSZWNvcmRlciBpbXBsZW1lbnRzIEZsb3dSZWNvcmRlciB7XG4gIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBub2Rlc0J5SWQgPSBuZXcgTWFwPHN0cmluZywgVG9wb2xvZ3lOb2RlPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IG5vZGVPcmRlcjogc3RyaW5nW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBlZGdlczogVG9wb2xvZ3lFZGdlW10gPSBbXTtcbiAgLyoqIFN0YWNrIG9mIGFjdGl2ZSBTVUJGTE9XIG5vZGUgaWRzLiBGb3JrL2RlY2lzaW9uLWJyYW5jaCBub2RlcyBuZXZlciBwdXNoLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHN1YmZsb3dTdGFjazogc3RyaW5nW10gPSBbXTtcblxuICAvKiogTWFwIG9mIGNoaWxkTmFtZSDihpIgcGVuZGluZyBmb3JrLWJyYW5jaCBzeW50aGV0aWMgbm9kZSwgY29uc3VtZWQgYnlcbiAgICogIHRoZSBuZXh0IG1hdGNoaW5nIGBvblN1YmZsb3dFbnRyeWAuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgcGVuZGluZ0ZvcmtCeU5hbWUgPSBuZXcgTWFwPHN0cmluZywgUGVuZGluZ0NoaWxkPigpO1xuICAvKiogUGVuZGluZyBkZWNpc2lvbi1icmFuY2ggc3ludGhldGljIG5vZGUsIGNvbnN1bWVkIGJ5IGEgbWF0Y2hpbmcgZW50cnkuICovXG4gIHByaXZhdGUgcGVuZGluZ0RlY2lzaW9uPzogeyBuYW1lOiBzdHJpbmcgfSAmIFBlbmRpbmdDaGlsZDtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBUb3BvbG9neVJlY29yZGVyT3B0aW9ucyA9IHt9KSB7XG4gICAgdGhpcy5pZCA9IG9wdGlvbnMuaWQgPz8gYHRvcG9sb2d5LSR7KytfY291bnRlcn1gO1xuICB9XG5cbiAgLy8g4pSA4pSAIEZsb3dSZWNvcmRlciBob29rcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBvblN1YmZsb3dFbnRyeShldmVudDogRmxvd1N1YmZsb3dFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHN1YmZsb3dJZCA9IGV2ZW50LnN1YmZsb3dJZDtcbiAgICBpZiAoIXN1YmZsb3dJZCkgcmV0dXJuOyAvLyBOZWVkIGEgc3RhYmxlIGlkIHRvIHRyYWNrLlxuXG4gICAgY29uc3QgZW50ZXJlZEF0ID0gZXZlbnQudHJhdmVyc2FsQ29udGV4dD8ucnVudGltZVN0YWdlSWQgPz8gJyc7XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIHBhcmVudDogcHJlZmVyIGEgcGVuZGluZyBmb3JrL2RlY2lzaW9uIG1hdGNoIGJ5IG5hbWUsXG4gICAgLy8gb3RoZXJ3aXNlIHRoZSBjdXJyZW50IHRvcC1vZi1zdWJmbG93LXN0YWNrLlxuICAgIGxldCBwYXJlbnRJZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGxldCBpbmNvbWluZ0tpbmQ6IFRvcG9sb2d5SW5jb21pbmdLaW5kO1xuXG4gICAgY29uc3QgcGVuZGluZ0ZvcmsgPSB0aGlzLnBlbmRpbmdGb3JrQnlOYW1lLmdldChldmVudC5uYW1lKTtcbiAgICBpZiAocGVuZGluZ0ZvcmspIHtcbiAgICAgIHBhcmVudElkID0gcGVuZGluZ0Zvcmsubm9kZUlkO1xuICAgICAgaW5jb21pbmdLaW5kID0gJ25leHQnOyAvLyBDaGlsZCBPRiBhIGZvcmstYnJhbmNoIG5vZGU7IHRoZSBmb3JrIHNlbWFudGljXG4gICAgICAvLyBpcyBjYXB0dXJlZCBieSB0aGUgZm9yay1icmFuY2gncyBvd24gaW5jb21pbmdLaW5kLlxuICAgICAgdGhpcy5wZW5kaW5nRm9ya0J5TmFtZS5kZWxldGUoZXZlbnQubmFtZSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLnBlbmRpbmdEZWNpc2lvbiAmJiB0aGlzLnBlbmRpbmdEZWNpc2lvbi5uYW1lID09PSBldmVudC5uYW1lKSB7XG4gICAgICBwYXJlbnRJZCA9IHRoaXMucGVuZGluZ0RlY2lzaW9uLm5vZGVJZDtcbiAgICAgIGluY29taW5nS2luZCA9ICduZXh0JztcbiAgICAgIHRoaXMucGVuZGluZ0RlY2lzaW9uID0gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSB7XG4gICAgICBwYXJlbnRJZCA9IHRoaXMuc3ViZmxvd1N0YWNrW3RoaXMuc3ViZmxvd1N0YWNrLmxlbmd0aCAtIDFdO1xuICAgICAgaW5jb21pbmdLaW5kID0gcGFyZW50SWQgPyAnbmV4dCcgOiAncm9vdCc7XG4gICAgfVxuXG4gICAgLy8gRGlzYW1iaWd1YXRlIHJlLWVudHJ5IChlLmcuLCBsb29wIGJvZHkgcmUtZW50ZXJzIHRoZSBzYW1lIHN1YmZsb3cpLlxuICAgIGxldCBub2RlSWQgPSBzdWJmbG93SWQ7XG4gICAgaWYgKHRoaXMubm9kZXNCeUlkLmhhcyhub2RlSWQpKSB7XG4gICAgICBsZXQgbiA9IDE7XG4gICAgICB3aGlsZSAodGhpcy5ub2Rlc0J5SWQuaGFzKGAke3N1YmZsb3dJZH0jJHtufWApKSBuKys7XG4gICAgICBub2RlSWQgPSBgJHtzdWJmbG93SWR9IyR7bn1gO1xuICAgIH1cblxuICAgIGNvbnN0IGRlcHRoID0gcGFyZW50SWQgPyB0aGlzLm5vZGVzQnlJZC5nZXQocGFyZW50SWQpIS5kZXB0aCArIDEgOiAwO1xuICAgIGNvbnN0IG1ldGFkYXRhID0gZXZlbnQuZGVzY3JpcHRpb24gPyB7IGRlc2NyaXB0aW9uOiBldmVudC5kZXNjcmlwdGlvbiB9IDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgbm9kZTogVG9wb2xvZ3lOb2RlID0ge1xuICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgIGtpbmQ6ICdzdWJmbG93JyxcbiAgICAgIG5hbWU6IGV2ZW50Lm5hbWUsXG4gICAgICBwYXJlbnRJZCxcbiAgICAgIGRlcHRoLFxuICAgICAgaW5jb21pbmdLaW5kLFxuICAgICAgZW50ZXJlZEF0LFxuICAgICAgbWV0YWRhdGEsXG4gICAgfTtcbiAgICB0aGlzLm5vZGVzQnlJZC5zZXQobm9kZUlkLCBub2RlKTtcbiAgICB0aGlzLm5vZGVPcmRlci5wdXNoKG5vZGVJZCk7XG5cbiAgICBpZiAocGFyZW50SWQgJiYgaW5jb21pbmdLaW5kICE9PSAncm9vdCcpIHtcbiAgICAgIHRoaXMuZWRnZXMucHVzaCh7XG4gICAgICAgIGZyb206IHBhcmVudElkLFxuICAgICAgICB0bzogbm9kZUlkLFxuICAgICAgICBraW5kOiBpbmNvbWluZ0tpbmQsXG4gICAgICAgIGF0OiBlbnRlcmVkQXQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLnN1YmZsb3dTdGFjay5wdXNoKG5vZGVJZCk7XG4gIH1cblxuICBvblN1YmZsb3dFeGl0KGV2ZW50OiBGbG93U3ViZmxvd0V2ZW50KTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZUlkID0gdGhpcy5zdWJmbG93U3RhY2sucG9wKCk7XG4gICAgaWYgKCFub2RlSWQpIHJldHVybjtcbiAgICBjb25zdCBub2RlID0gdGhpcy5ub2Rlc0J5SWQuZ2V0KG5vZGVJZCk7XG4gICAgaWYgKG5vZGUpIHtcbiAgICAgIG5vZGUuZXhpdGVkQXQgPSBldmVudC50cmF2ZXJzYWxDb250ZXh0Py5ydW50aW1lU3RhZ2VJZCA/PyAnJztcbiAgICB9XG4gICAgLy8gQSBzdWJmbG93IGV4aXQgaW1wbGllcyBubyBtb3JlIGNoaWxkcmVuIGFyZSBwZW5kaW5nIGZvciB0aGlzIHNjb3BlIOKAlFxuICAgIC8vIGNsZWFyIHN0YWxlIHBlbmRpbmcgc3RhdGUgdGhhdCBiZWxvbmdlZCB0byB0aGUgc2NvcGUgd2UganVzdCBsZWZ0LlxuICAgIHRoaXMucGVuZGluZ0ZvcmtCeU5hbWUuY2xlYXIoKTtcbiAgICB0aGlzLnBlbmRpbmdEZWNpc2lvbiA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIG9uRm9yayhldmVudDogRmxvd0ZvcmtFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGFjdGl2ZUlkID0gdGhpcy5zdWJmbG93U3RhY2tbdGhpcy5zdWJmbG93U3RhY2subGVuZ3RoIC0gMV07XG4gICAgY29uc3QgYXQgPSBldmVudC50cmF2ZXJzYWxDb250ZXh0Py5ydW50aW1lU3RhZ2VJZCA/PyAnJztcbiAgICBjb25zdCBkZXB0aCA9IGFjdGl2ZUlkID8gdGhpcy5ub2Rlc0J5SWQuZ2V0KGFjdGl2ZUlkKSEuZGVwdGggKyAxIDogMDtcblxuICAgIC8vIFJlc2V0IGFueSBwcmlvciBwZW5kaW5nIGZvcmsgc3RhdGUg4oCUIGEgbmV3IGZvcmsgc3RhcnRzIGZyZXNoLlxuICAgIHRoaXMucGVuZGluZ0ZvcmtCeU5hbWUuY2xlYXIoKTtcblxuICAgIGV2ZW50LmNoaWxkcmVuLmZvckVhY2goKGNoaWxkTmFtZSwgaSkgPT4ge1xuICAgICAgY29uc3Qgbm9kZUlkID0gYGZvcmstJHthdCB8fCBldmVudC5wYXJlbnR9LSR7aX0tJHtjaGlsZE5hbWV9YDtcbiAgICAgIGNvbnN0IG5vZGU6IFRvcG9sb2d5Tm9kZSA9IHtcbiAgICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgICAga2luZDogJ2ZvcmstYnJhbmNoJyxcbiAgICAgICAgbmFtZTogY2hpbGROYW1lLFxuICAgICAgICBwYXJlbnRJZDogYWN0aXZlSWQsXG4gICAgICAgIGRlcHRoLFxuICAgICAgICBpbmNvbWluZ0tpbmQ6ICdmb3JrLWJyYW5jaCcsXG4gICAgICAgIGVudGVyZWRBdDogYXQsXG4gICAgICAgIG1ldGFkYXRhOiB7IGZvcmtQYXJlbnQ6IGV2ZW50LnBhcmVudCB9LFxuICAgICAgfTtcbiAgICAgIHRoaXMubm9kZXNCeUlkLnNldChub2RlSWQsIG5vZGUpO1xuICAgICAgdGhpcy5ub2RlT3JkZXIucHVzaChub2RlSWQpO1xuICAgICAgaWYgKGFjdGl2ZUlkKSB7XG4gICAgICAgIHRoaXMuZWRnZXMucHVzaCh7IGZyb206IGFjdGl2ZUlkLCB0bzogbm9kZUlkLCBraW5kOiAnZm9yay1icmFuY2gnLCBhdCB9KTtcbiAgICAgIH1cbiAgICAgIHRoaXMucGVuZGluZ0ZvcmtCeU5hbWUuc2V0KGNoaWxkTmFtZSwgeyBub2RlSWQsIGF0IH0pO1xuICAgIH0pO1xuICB9XG5cbiAgb25EZWNpc2lvbihldmVudDogRmxvd0RlY2lzaW9uRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBhY3RpdmVJZCA9IHRoaXMuc3ViZmxvd1N0YWNrW3RoaXMuc3ViZmxvd1N0YWNrLmxlbmd0aCAtIDFdO1xuICAgIGNvbnN0IGF0ID0gZXZlbnQudHJhdmVyc2FsQ29udGV4dD8ucnVudGltZVN0YWdlSWQgPz8gJyc7XG4gICAgY29uc3QgZGVwdGggPSBhY3RpdmVJZCA/IHRoaXMubm9kZXNCeUlkLmdldChhY3RpdmVJZCkhLmRlcHRoICsgMSA6IDA7XG5cbiAgICAvLyBBIG5ldyBkZWNpc2lvbiBzdXBlcnNlZGVzIGFueSBwcmlvciB1bnJlc29sdmVkIHBlbmRpbmcgb25lLlxuICAgIHRoaXMucGVuZGluZ0RlY2lzaW9uID0gdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgbm9kZUlkID0gYGRlY2lzaW9uLSR7YXQgfHwgZXZlbnQuZGVjaWRlcn0tJHtldmVudC5jaG9zZW59YDtcbiAgICBjb25zdCBtZXRhZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7IGRlY2lkZXI6IGV2ZW50LmRlY2lkZXIgfTtcbiAgICBpZiAoZXZlbnQucmF0aW9uYWxlKSBtZXRhZGF0YS5yYXRpb25hbGUgPSBldmVudC5yYXRpb25hbGU7XG4gICAgaWYgKGV2ZW50LmRlc2NyaXB0aW9uKSBtZXRhZGF0YS5kZXNjcmlwdGlvbiA9IGV2ZW50LmRlc2NyaXB0aW9uO1xuXG4gICAgY29uc3Qgbm9kZTogVG9wb2xvZ3lOb2RlID0ge1xuICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgIGtpbmQ6ICdkZWNpc2lvbi1icmFuY2gnLFxuICAgICAgbmFtZTogZXZlbnQuY2hvc2VuLFxuICAgICAgcGFyZW50SWQ6IGFjdGl2ZUlkLFxuICAgICAgZGVwdGgsXG4gICAgICBpbmNvbWluZ0tpbmQ6ICdkZWNpc2lvbi1icmFuY2gnLFxuICAgICAgZW50ZXJlZEF0OiBhdCxcbiAgICAgIG1ldGFkYXRhLFxuICAgIH07XG4gICAgdGhpcy5ub2Rlc0J5SWQuc2V0KG5vZGVJZCwgbm9kZSk7XG4gICAgdGhpcy5ub2RlT3JkZXIucHVzaChub2RlSWQpO1xuICAgIGlmIChhY3RpdmVJZCkge1xuICAgICAgdGhpcy5lZGdlcy5wdXNoKHsgZnJvbTogYWN0aXZlSWQsIHRvOiBub2RlSWQsIGtpbmQ6ICdkZWNpc2lvbi1icmFuY2gnLCBhdCB9KTtcbiAgICB9XG4gICAgdGhpcy5wZW5kaW5nRGVjaXNpb24gPSB7IG5hbWU6IGV2ZW50LmNob3Nlbiwgbm9kZUlkLCBhdCB9O1xuICB9XG5cbiAgb25Mb29wKGV2ZW50OiBGbG93TG9vcEV2ZW50KTogdm9pZCB7XG4gICAgLy8gbG9vcFRvIGp1bXBzIGJhY2sgaW5zaWRlIHRoZSBDVVJSRU5UIHN1YmZsb3cuIFJlY29yZCBhIHNlbGYtZWRnZSBvbiB0aGVcbiAgICAvLyBhY3RpdmUgc3ViZmxvdyDigJQgc3ludGhldGljIGZvcmsvZGVjaXNpb24gbm9kZXMgZG9uJ3QgcGFydGljaXBhdGUgaW4gbG9vcHMuXG4gICAgY29uc3QgYWN0aXZlSWQgPSB0aGlzLnN1YmZsb3dTdGFja1t0aGlzLnN1YmZsb3dTdGFjay5sZW5ndGggLSAxXTtcbiAgICBpZiAoIWFjdGl2ZUlkKSByZXR1cm47XG4gICAgdGhpcy5lZGdlcy5wdXNoKHtcbiAgICAgIGZyb206IGFjdGl2ZUlkLFxuICAgICAgdG86IGFjdGl2ZUlkLFxuICAgICAga2luZDogJ2xvb3AtaXRlcmF0aW9uJyxcbiAgICAgIGF0OiBldmVudC50cmF2ZXJzYWxDb250ZXh0Py5ydW50aW1lU3RhZ2VJZCA/PyAnJyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBDYWxsZWQgYnkgdGhlIGV4ZWN1dG9yIGJlZm9yZSBlYWNoIGBydW4oKWAg4oCUIHJlc2V0cyBhbGwgc3RhdGUuICovXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMubm9kZXNCeUlkLmNsZWFyKCk7XG4gICAgdGhpcy5ub2RlT3JkZXIubGVuZ3RoID0gMDtcbiAgICB0aGlzLmVkZ2VzLmxlbmd0aCA9IDA7XG4gICAgdGhpcy5zdWJmbG93U3RhY2subGVuZ3RoID0gMDtcbiAgICB0aGlzLnBlbmRpbmdGb3JrQnlOYW1lLmNsZWFyKCk7XG4gICAgdGhpcy5wZW5kaW5nRGVjaXNpb24gPSB1bmRlZmluZWQ7XG4gIH1cblxuICAvLyDilIDilIAgUXVlcnkgQVBJIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBMaXZlIHNuYXBzaG90IG9mIHRoZSBjb21wb3NpdGlvbiBncmFwaC4gU2FmZSBkdXJpbmcgb3IgYWZ0ZXIgYSBydW4uICovXG4gIGdldFRvcG9sb2d5KCk6IFRvcG9sb2d5IHtcbiAgICBjb25zdCBub2RlcyA9IHRoaXMubm9kZU9yZGVyLm1hcCgoaWQpID0+IHRoaXMubm9kZXNCeUlkLmdldChpZCkhKTtcbiAgICByZXR1cm4ge1xuICAgICAgbm9kZXMsXG4gICAgICBlZGdlczogWy4uLnRoaXMuZWRnZXNdLFxuICAgICAgYWN0aXZlTm9kZUlkOiB0aGlzLnN1YmZsb3dTdGFja1t0aGlzLnN1YmZsb3dTdGFjay5sZW5ndGggLSAxXSA/PyBudWxsLFxuICAgICAgcm9vdElkOiB0aGlzLm5vZGVPcmRlclswXSA/PyBudWxsLFxuICAgIH07XG4gIH1cblxuICAvKiogRGlyZWN0IGNoaWxkcmVuIG9mIGEgbm9kZSDigJQgaW5zZXJ0aW9uLW9yZGVyZWQuICovXG4gIGdldENoaWxkcmVuKG5vZGVJZDogc3RyaW5nKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLm5vZGVPcmRlci5tYXAoKGlkKSA9PiB0aGlzLm5vZGVzQnlJZC5nZXQoaWQpISkuZmlsdGVyKChuKSA9PiBuLnBhcmVudElkID09PSBub2RlSWQpO1xuICB9XG5cbiAgLyoqIEFsbCBub2RlcyBvZiBhIGdpdmVuIGtpbmQuICovXG4gIGdldEJ5S2luZChraW5kOiBUb3BvbG9neU5vZGVLaW5kKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLm5vZGVPcmRlci5tYXAoKGlkKSA9PiB0aGlzLm5vZGVzQnlJZC5nZXQoaWQpISkuZmlsdGVyKChuKSA9PiBuLmtpbmQgPT09IGtpbmQpO1xuICB9XG5cbiAgLyoqIEFsbCBtb3VudGVkIHN1YmZsb3cgbm9kZXMuIENvbnZlbmllbmNlIGZvciBhZ2VudC1jZW50cmljIHZpZXdzLiAqL1xuICBnZXRTdWJmbG93Tm9kZXMoKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLmdldEJ5S2luZCgnc3ViZmxvdycpO1xuICB9XG5cbiAgLyoqIEFsbCBmb3JrLWJyYW5jaCBub2RlcyBzaGFyaW5nIHRoZSBzYW1lIHBhcmVudCBhcyBgbm9kZUlkYCDigJQgaS5lLixcbiAgICogIHBhcmFsbGVsIHNpYmxpbmdzIG9mIGEgcGFyYWxsZWwgYnJhbmNoLiBFbXB0eSBpZiBgbm9kZUlkYCBpc24ndCBhXG4gICAqICBmb3JrLWJyYW5jaCBvciBoYXMgbm8gcGFyZW50LiAqL1xuICBnZXRQYXJhbGxlbFNpYmxpbmdzKG5vZGVJZDogc3RyaW5nKTogVG9wb2xvZ3lOb2RlW10ge1xuICAgIGNvbnN0IG5vZGUgPSB0aGlzLm5vZGVzQnlJZC5nZXQobm9kZUlkKTtcbiAgICBpZiAoIW5vZGUgfHwgbm9kZS5raW5kICE9PSAnZm9yay1icmFuY2gnIHx8ICFub2RlLnBhcmVudElkKSByZXR1cm4gW107XG4gICAgcmV0dXJuIHRoaXMuZ2V0Q2hpbGRyZW4obm9kZS5wYXJlbnRJZCkuZmlsdGVyKChuKSA9PiBuLmtpbmQgPT09ICdmb3JrLWJyYW5jaCcpO1xuICB9XG5cbiAgLyoqIEVtaXQgYSBzbmFwc2hvdCBidW5kbGUgZm9yIGluY2x1c2lvbiBpbiBgZXhlY3V0b3IuZ2V0U25hcHNob3QoKWAuICovXG4gIHRvU25hcHNob3QoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6ICdUb3BvbG9neScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0NvbXBvc2l0aW9uIGdyYXBoOiBzdWJmbG93IGJvdW5kYXJpZXMsIGZvcmsgYnJhbmNoZXMsIGRlY2lzaW9uIGJyYW5jaGVzJyxcbiAgICAgIHByZWZlcnJlZE9wZXJhdGlvbjogJ3RyYW5zbGF0ZScgYXMgY29uc3QsXG4gICAgICBkYXRhOiB0aGlzLmdldFRvcG9sb2d5KCksXG4gICAgfTtcbiAgfVxufVxuIl19
package/dist/trace.js CHANGED
@@ -22,7 +22,7 @@
22
22
  * ```
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.qualityTrace = exports.formatQualityTrace = exports.QualityRecorder = exports.SequenceRecorder = exports.KeyedRecorder = exports.formatCausalChain = exports.flattenCausalDAG = exports.causalChain = exports.findLastWriter = exports.findCommits = exports.findCommit = exports.parseRuntimeStageId = exports.createExecutionCounter = exports.buildRuntimeStageId = void 0;
25
+ exports.qualityTrace = exports.formatQualityTrace = exports.QualityRecorder = exports.topologyRecorder = exports.TopologyRecorder = exports.SequenceRecorder = exports.KeyedRecorder = exports.formatCausalChain = exports.flattenCausalDAG = exports.causalChain = exports.findLastWriter = exports.findCommits = exports.findCommit = exports.parseRuntimeStageId = exports.createExecutionCounter = exports.buildRuntimeStageId = void 0;
26
26
  var runtimeStageId_js_1 = require("./lib/engine/runtimeStageId.js");
27
27
  Object.defineProperty(exports, "buildRuntimeStageId", { enumerable: true, get: function () { return runtimeStageId_js_1.buildRuntimeStageId; } });
28
28
  Object.defineProperty(exports, "createExecutionCounter", { enumerable: true, get: function () { return runtimeStageId_js_1.createExecutionCounter; } });
@@ -42,9 +42,12 @@ Object.defineProperty(exports, "KeyedRecorder", { enumerable: true, get: functio
42
42
  // SequenceRecorder — base class for 1:N ordered sequence recorders with keyed index
43
43
  var SequenceRecorder_js_1 = require("./lib/recorder/SequenceRecorder.js");
44
44
  Object.defineProperty(exports, "SequenceRecorder", { enumerable: true, get: function () { return SequenceRecorder_js_1.SequenceRecorder; } });
45
+ var TopologyRecorder_js_1 = require("./lib/recorder/TopologyRecorder.js");
46
+ Object.defineProperty(exports, "TopologyRecorder", { enumerable: true, get: function () { return TopologyRecorder_js_1.TopologyRecorder; } });
47
+ Object.defineProperty(exports, "topologyRecorder", { enumerable: true, get: function () { return TopologyRecorder_js_1.topologyRecorder; } });
45
48
  var QualityRecorder_js_1 = require("./lib/recorder/QualityRecorder.js");
46
49
  Object.defineProperty(exports, "QualityRecorder", { enumerable: true, get: function () { return QualityRecorder_js_1.QualityRecorder; } });
47
50
  var qualityTrace_js_1 = require("./lib/recorder/qualityTrace.js");
48
51
  Object.defineProperty(exports, "formatQualityTrace", { enumerable: true, get: function () { return qualityTrace_js_1.formatQualityTrace; } });
49
52
  Object.defineProperty(exports, "qualityTrace", { enumerable: true, get: function () { return qualityTrace_js_1.qualityTrace; } });
50
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7OztBQUlILG9FQUFrSDtBQUF6Ryx3SEFBQSxtQkFBbUIsT0FBQTtBQUFFLDJIQUFBLHNCQUFzQixPQUFBO0FBQUUsd0hBQUEsbUJBQW1CLE9BQUE7QUFFekUsd0RBQXdEO0FBQ3hELG9FQUF5RjtBQUFoRiwrR0FBQSxVQUFVLE9BQUE7QUFBRSxnSEFBQSxXQUFXLE9BQUE7QUFBRSxtSEFBQSxjQUFjLE9BQUE7QUFJaEQsMERBQTZGO0FBQXBGLDJHQUFBLFdBQVcsT0FBQTtBQUFFLGdIQUFBLGdCQUFnQixPQUFBO0FBQUUsaUhBQUEsaUJBQWlCLE9BQUE7QUFFekQseURBQXlEO0FBQ3pELG9FQUFnRTtBQUF2RCxpSEFBQSxhQUFhLE9BQUE7QUFFdEIsb0ZBQW9GO0FBQ3BGLDBFQUFzRTtBQUE3RCx1SEFBQSxnQkFBZ0IsT0FBQTtBQUl6Qix3RUFBb0U7QUFBM0QscUhBQUEsZUFBZSxPQUFBO0FBSXhCLGtFQUFrRjtBQUF6RSxxSEFBQSxrQkFBa0IsT0FBQTtBQUFFLCtHQUFBLFlBQVksT0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZm9vdHByaW50anMvdHJhY2Ug4oCUIEV4ZWN1dGlvbiB0cmFjaW5nLCBkZWJ1Z2dpbmcsIGFuZCBiYWNrdHJhY2tpbmcgdXRpbGl0aWVzLlxuICpcbiAqIFJ1bnRpbWUgc3RhZ2UgSURzLCBjb21taXQgbG9nIHF1ZXJpZXMsIGFuZCByZWNvcmRlciBiYXNlIGNsYXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHBhcnNlUnVudGltZVN0YWdlSWQsIGZpbmRMYXN0V3JpdGVyLCBLZXllZFJlY29yZGVyLCBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIC8vIFBhcnNlIGEgcnVudGltZVN0YWdlSWRcbiAqIGNvbnN0IHsgc3RhZ2VJZCwgZXhlY3V0aW9uSW5kZXggfSA9IHBhcnNlUnVudGltZVN0YWdlSWQoJ2NhbGwtbGxtIzUnKTtcbiAqXG4gKiAvLyBCYWNrdHJhY2s6IHdobyB3cm90ZSAnc3lzdGVtUHJvbXB0JyBiZWZvcmUgc3RhZ2UgYXQgaWR4IDg/XG4gKiBjb25zdCB3cml0ZXIgPSBmaW5kTGFzdFdyaXRlcihjb21taXRMb2csICdzeXN0ZW1Qcm9tcHQnLCA4KTtcbiAqXG4gKiAvLyBCdWlsZCBhIGtleWVkIHJlY29yZGVyICgxOjEg4oCUIG9uZSBlbnRyeSBwZXIgc3RlcClcbiAqIGNsYXNzIE15UmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPE15RW50cnk+IHsgLi4uIH1cbiAqXG4gKiAvLyBCdWlsZCBhIHNlcXVlbmNlIHJlY29yZGVyICgxOk4g4oCUIG11bHRpcGxlIGVudHJpZXMgcGVyIHN0ZXAsIG9yZGVyaW5nIG1hdHRlcnMpXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBSdW50aW1lIHN0YWdlIElEIOKAlCB1bmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllcnNcbmV4cG9ydCB0eXBlIHsgRXhlY3V0aW9uQ291bnRlciB9IGZyb20gJy4vbGliL2VuZ2luZS9ydW50aW1lU3RhZ2VJZC5qcyc7XG5leHBvcnQgeyBidWlsZFJ1bnRpbWVTdGFnZUlkLCBjcmVhdGVFeGVjdXRpb25Db3VudGVyLCBwYXJzZVJ1bnRpbWVTdGFnZUlkIH0gZnJvbSAnLi9saWIvZW5naW5lL3J1bnRpbWVTdGFnZUlkLmpzJztcblxuLy8gQ29tbWl0IGxvZyBxdWVyaWVzIOKAlCB0eXBlZCB1dGlsaXRpZXMgZm9yIGJhY2t0cmFja2luZ1xuZXhwb3J0IHsgZmluZENvbW1pdCwgZmluZENvbW1pdHMsIGZpbmRMYXN0V3JpdGVyIH0gZnJvbSAnLi9saWIvbWVtb3J5L2NvbW1pdExvZ1V0aWxzLmpzJztcblxuLy8gQ2F1c2FsIGNoYWluIOKAlCBiYWNrd2FyZCBwcm9ncmFtIHNsaWNpbmcgb24gY29tbWl0IGxvZyAoREFHKVxuZXhwb3J0IHR5cGUgeyBDYXVzYWxDaGFpbk9wdGlvbnMsIENhdXNhbE5vZGUsIEtleXNSZWFkTG9va3VwIH0gZnJvbSAnLi9saWIvbWVtb3J5L2JhY2t0cmFjay5qcyc7XG5leHBvcnQgeyBjYXVzYWxDaGFpbiwgZmxhdHRlbkNhdXNhbERBRywgZm9ybWF0Q2F1c2FsQ2hhaW4gfSBmcm9tICcuL2xpYi9tZW1vcnkvYmFja3RyYWNrLmpzJztcblxuLy8gS2V5ZWRSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMToxIE1hcC1iYXNlZCByZWNvcmRlcnNcbmV4cG9ydCB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9LZXllZFJlY29yZGVyLmpzJztcblxuLy8gU2VxdWVuY2VSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMTpOIG9yZGVyZWQgc2VxdWVuY2UgcmVjb3JkZXJzIHdpdGgga2V5ZWQgaW5kZXhcbmV4cG9ydCB7IFNlcXVlbmNlUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9TZXF1ZW5jZVJlY29yZGVyLmpzJztcblxuLy8gUXVhbGl0eVJlY29yZGVyIOKAlCBwZXItc3RlcCBxdWFsaXR5IHNjb3Jpbmcgd2l0aCBiYWNrdHJhY2tpbmdcbmV4cG9ydCB0eXBlIHsgUXVhbGl0eUVudHJ5LCBRdWFsaXR5UmVjb3JkZXJPcHRpb25zLCBRdWFsaXR5U2NvcmluZ0ZuIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvUXVhbGl0eVJlY29yZGVyLmpzJztcbmV4cG9ydCB7IFF1YWxpdHlSZWNvcmRlciB9IGZyb20gJy4vbGliL3JlY29yZGVyL1F1YWxpdHlSZWNvcmRlci5qcyc7XG5cbi8vIHF1YWxpdHlUcmFjZSDigJQgUXVhbGl0eSBTdGFjayBUcmFjZSAoYmFja3RyYWNrIGZyb20gbG93LXNjb3Jpbmcgc3RlcHMpXG5leHBvcnQgdHlwZSB7IFF1YWxpdHlGcmFtZSwgUXVhbGl0eVN0YWNrVHJhY2UgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UuanMnO1xuZXhwb3J0IHsgZm9ybWF0UXVhbGl0eVRyYWNlLCBxdWFsaXR5VHJhY2UgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UuanMnO1xuIl19
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7OztBQUlILG9FQUFrSDtBQUF6Ryx3SEFBQSxtQkFBbUIsT0FBQTtBQUFFLDJIQUFBLHNCQUFzQixPQUFBO0FBQUUsd0hBQUEsbUJBQW1CLE9BQUE7QUFFekUsd0RBQXdEO0FBQ3hELG9FQUF5RjtBQUFoRiwrR0FBQSxVQUFVLE9BQUE7QUFBRSxnSEFBQSxXQUFXLE9BQUE7QUFBRSxtSEFBQSxjQUFjLE9BQUE7QUFJaEQsMERBQTZGO0FBQXBGLDJHQUFBLFdBQVcsT0FBQTtBQUFFLGdIQUFBLGdCQUFnQixPQUFBO0FBQUUsaUhBQUEsaUJBQWlCLE9BQUE7QUFFekQseURBQXlEO0FBQ3pELG9FQUFnRTtBQUF2RCxpSEFBQSxhQUFhLE9BQUE7QUFFdEIsb0ZBQW9GO0FBQ3BGLDBFQUFzRTtBQUE3RCx1SEFBQSxnQkFBZ0IsT0FBQTtBQVV6QiwwRUFBd0Y7QUFBL0UsdUhBQUEsZ0JBQWdCLE9BQUE7QUFBRSx1SEFBQSxnQkFBZ0IsT0FBQTtBQUkzQyx3RUFBb0U7QUFBM0QscUhBQUEsZUFBZSxPQUFBO0FBSXhCLGtFQUFrRjtBQUF6RSxxSEFBQSxrQkFBa0IsT0FBQTtBQUFFLCtHQUFBLFlBQVksT0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZm9vdHByaW50anMvdHJhY2Ug4oCUIEV4ZWN1dGlvbiB0cmFjaW5nLCBkZWJ1Z2dpbmcsIGFuZCBiYWNrdHJhY2tpbmcgdXRpbGl0aWVzLlxuICpcbiAqIFJ1bnRpbWUgc3RhZ2UgSURzLCBjb21taXQgbG9nIHF1ZXJpZXMsIGFuZCByZWNvcmRlciBiYXNlIGNsYXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHBhcnNlUnVudGltZVN0YWdlSWQsIGZpbmRMYXN0V3JpdGVyLCBLZXllZFJlY29yZGVyLCBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIC8vIFBhcnNlIGEgcnVudGltZVN0YWdlSWRcbiAqIGNvbnN0IHsgc3RhZ2VJZCwgZXhlY3V0aW9uSW5kZXggfSA9IHBhcnNlUnVudGltZVN0YWdlSWQoJ2NhbGwtbGxtIzUnKTtcbiAqXG4gKiAvLyBCYWNrdHJhY2s6IHdobyB3cm90ZSAnc3lzdGVtUHJvbXB0JyBiZWZvcmUgc3RhZ2UgYXQgaWR4IDg/XG4gKiBjb25zdCB3cml0ZXIgPSBmaW5kTGFzdFdyaXRlcihjb21taXRMb2csICdzeXN0ZW1Qcm9tcHQnLCA4KTtcbiAqXG4gKiAvLyBCdWlsZCBhIGtleWVkIHJlY29yZGVyICgxOjEg4oCUIG9uZSBlbnRyeSBwZXIgc3RlcClcbiAqIGNsYXNzIE15UmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPE15RW50cnk+IHsgLi4uIH1cbiAqXG4gKiAvLyBCdWlsZCBhIHNlcXVlbmNlIHJlY29yZGVyICgxOk4g4oCUIG11bHRpcGxlIGVudHJpZXMgcGVyIHN0ZXAsIG9yZGVyaW5nIG1hdHRlcnMpXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBSdW50aW1lIHN0YWdlIElEIOKAlCB1bmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllcnNcbmV4cG9ydCB0eXBlIHsgRXhlY3V0aW9uQ291bnRlciB9IGZyb20gJy4vbGliL2VuZ2luZS9ydW50aW1lU3RhZ2VJZC5qcyc7XG5leHBvcnQgeyBidWlsZFJ1bnRpbWVTdGFnZUlkLCBjcmVhdGVFeGVjdXRpb25Db3VudGVyLCBwYXJzZVJ1bnRpbWVTdGFnZUlkIH0gZnJvbSAnLi9saWIvZW5naW5lL3J1bnRpbWVTdGFnZUlkLmpzJztcblxuLy8gQ29tbWl0IGxvZyBxdWVyaWVzIOKAlCB0eXBlZCB1dGlsaXRpZXMgZm9yIGJhY2t0cmFja2luZ1xuZXhwb3J0IHsgZmluZENvbW1pdCwgZmluZENvbW1pdHMsIGZpbmRMYXN0V3JpdGVyIH0gZnJvbSAnLi9saWIvbWVtb3J5L2NvbW1pdExvZ1V0aWxzLmpzJztcblxuLy8gQ2F1c2FsIGNoYWluIOKAlCBiYWNrd2FyZCBwcm9ncmFtIHNsaWNpbmcgb24gY29tbWl0IGxvZyAoREFHKVxuZXhwb3J0IHR5cGUgeyBDYXVzYWxDaGFpbk9wdGlvbnMsIENhdXNhbE5vZGUsIEtleXNSZWFkTG9va3VwIH0gZnJvbSAnLi9saWIvbWVtb3J5L2JhY2t0cmFjay5qcyc7XG5leHBvcnQgeyBjYXVzYWxDaGFpbiwgZmxhdHRlbkNhdXNhbERBRywgZm9ybWF0Q2F1c2FsQ2hhaW4gfSBmcm9tICcuL2xpYi9tZW1vcnkvYmFja3RyYWNrLmpzJztcblxuLy8gS2V5ZWRSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMToxIE1hcC1iYXNlZCByZWNvcmRlcnNcbmV4cG9ydCB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9LZXllZFJlY29yZGVyLmpzJztcblxuLy8gU2VxdWVuY2VSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMTpOIG9yZGVyZWQgc2VxdWVuY2UgcmVjb3JkZXJzIHdpdGgga2V5ZWQgaW5kZXhcbmV4cG9ydCB7IFNlcXVlbmNlUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9TZXF1ZW5jZVJlY29yZGVyLmpzJztcblxuLy8gVG9wb2xvZ3lSZWNvcmRlciDigJQgY29tcG9zaXRpb24gZ3JhcGggYWNjdW11bGF0b3IgKHN1YmZsb3dzICsgY29udHJvbC1mbG93IGVkZ2VzKVxuZXhwb3J0IHR5cGUge1xuICBUb3BvbG9neSxcbiAgVG9wb2xvZ3lFZGdlLFxuICBUb3BvbG9neUluY29taW5nS2luZCxcbiAgVG9wb2xvZ3lOb2RlLFxuICBUb3BvbG9neVJlY29yZGVyT3B0aW9ucyxcbn0gZnJvbSAnLi9saWIvcmVjb3JkZXIvVG9wb2xvZ3lSZWNvcmRlci5qcyc7XG5leHBvcnQgeyBUb3BvbG9neVJlY29yZGVyLCB0b3BvbG9neVJlY29yZGVyIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvVG9wb2xvZ3lSZWNvcmRlci5qcyc7XG5cbi8vIFF1YWxpdHlSZWNvcmRlciDigJQgcGVyLXN0ZXAgcXVhbGl0eSBzY29yaW5nIHdpdGggYmFja3RyYWNraW5nXG5leHBvcnQgdHlwZSB7IFF1YWxpdHlFbnRyeSwgUXVhbGl0eVJlY29yZGVyT3B0aW9ucywgUXVhbGl0eVNjb3JpbmdGbiB9IGZyb20gJy4vbGliL3JlY29yZGVyL1F1YWxpdHlSZWNvcmRlci5qcyc7XG5leHBvcnQgeyBRdWFsaXR5UmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9RdWFsaXR5UmVjb3JkZXIuanMnO1xuXG4vLyBxdWFsaXR5VHJhY2Ug4oCUIFF1YWxpdHkgU3RhY2sgVHJhY2UgKGJhY2t0cmFjayBmcm9tIGxvdy1zY29yaW5nIHN0ZXBzKVxuZXhwb3J0IHR5cGUgeyBRdWFsaXR5RnJhbWUsIFF1YWxpdHlTdGFja1RyYWNlIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvcXVhbGl0eVRyYWNlLmpzJztcbmV4cG9ydCB7IGZvcm1hdFF1YWxpdHlUcmFjZSwgcXVhbGl0eVRyYWNlIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvcXVhbGl0eVRyYWNlLmpzJztcbiJdfQ==
@@ -0,0 +1,151 @@
1
+ /**
2
+ * TopologyRecorder — composition graph built during traversal.
3
+ *
4
+ * The gap this fills:
5
+ * footprintjs fires atomic flow events (onSubflowEntry, onFork, onDecision,
6
+ * onLoop) but the accumulated *shape* of a run — who nests inside whom,
7
+ * which nodes are parallel siblings vs branches of a decision — is only
8
+ * visible post-run via `executor.getSnapshot()` tree-walking.
9
+ *
10
+ * Streaming consumers (live UIs, in-flight debuggers) see only the event
11
+ * stream. Every such consumer has to rebuild subflow-stack + fork-map +
12
+ * decision-tracker from scratch, usually slightly wrong in different ways.
13
+ *
14
+ * TopologyRecorder is the standard accumulator: one subscription to the
15
+ * three primitive channels, one live graph, queryable at any moment during
16
+ * or after a run.
17
+ *
18
+ * What it records — THREE node kinds for complete composition coverage:
19
+ * 1. 'subflow' — via onSubflowEntry (a mounted subflow boundary)
20
+ * 2. 'fork-branch' — via onFork (one node per child, synthesized)
21
+ * 3. 'decision-branch' — via onDecision (the chosen branch, synthesized)
22
+ *
23
+ * When a fork-branch or decision-branch target IS ALSO a subflow, the
24
+ * subsequent onSubflowEntry creates a subflow CHILD of the synthetic node.
25
+ * The layered shape preserves both "who branched" and "what the branch ran."
26
+ *
27
+ * Plain sequential stages are NOT nodes — that's StageContext's job.
28
+ * Topology is a graph of control-flow branching, not a full execution tree.
29
+ *
30
+ * Edges:
31
+ * One edge per traversal transition — `kind` matches the child's
32
+ * `incomingKind`. A consumer rendering "parallel columns" filters edges
33
+ * where `kind === 'fork-branch'` sharing the same `from`.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * import { topologyRecorder } from 'footprintjs/trace';
38
+ *
39
+ * const topo = topologyRecorder();
40
+ * executor.attachCombinedRecorder(topo); // auto-routes to FlowRecorder channel
41
+ *
42
+ * await executor.run();
43
+ *
44
+ * const { nodes, edges, activeNodeId, rootId } = topo.getTopology();
45
+ * // Consumer queries:
46
+ * topo.getChildren('sf-parent'); // direct children (any kind)
47
+ * topo.getByKind('fork-branch'); // all parallel branches
48
+ * topo.getSubflowNodes(); // only mounted subflows
49
+ * ```
50
+ */
51
+ import type { FlowDecisionEvent, FlowForkEvent, FlowLoopEvent, FlowRecorder, FlowSubflowEvent } from '../engine/narrative/types.js';
52
+ /** The kind of composition unit a node represents. */
53
+ export type TopologyNodeKind = 'subflow' | 'fork-branch' | 'decision-branch';
54
+ /** How the traversal reached this node — drives consumer layout decisions. */
55
+ export type TopologyIncomingKind = 'root' | 'next' | 'fork-branch' | 'decision-branch' | 'loop-iteration';
56
+ /** A composition-significant point in the graph. */
57
+ export interface TopologyNode {
58
+ /** Unique id. Subflows use their subflowId (with `#n` suffix on re-entry).
59
+ * Synthetic nodes (fork-branch / decision-branch) use
60
+ * `fork-${runtimeStageId}-${i}` / `decision-${runtimeStageId}` form. */
61
+ readonly id: string;
62
+ /** What this node represents. */
63
+ readonly kind: TopologyNodeKind;
64
+ /** Display name. For subflows: `FlowSubflowEvent.name`. For fork-branches:
65
+ * the child name from `FlowForkEvent.children`. For decision-branches:
66
+ * the chosen name from `FlowDecisionEvent.chosen`. */
67
+ readonly name: string;
68
+ /** Parent node id. Undefined when this node sits at the run's top level. */
69
+ readonly parentId?: string;
70
+ /** Depth in the topology tree (0 = top-level). */
71
+ readonly depth: number;
72
+ /** How the traversal reached this node. */
73
+ readonly incomingKind: TopologyIncomingKind;
74
+ /** runtimeStageId at the moment the node was created. */
75
+ readonly enteredAt: string;
76
+ /** runtimeStageId when the corresponding subflow exited. Only meaningful
77
+ * for kind='subflow'; fork/decision-branch nodes are instantaneous. */
78
+ exitedAt?: string;
79
+ /** Kind-specific extras: forkParent, decider, rationale, description. */
80
+ readonly metadata?: Readonly<Record<string, unknown>>;
81
+ }
82
+ /** A traversal transition between two nodes. */
83
+ export interface TopologyEdge {
84
+ readonly from: string;
85
+ readonly to: string;
86
+ readonly kind: Exclude<TopologyIncomingKind, 'root'>;
87
+ readonly at: string;
88
+ }
89
+ /** Snapshot of the composition graph. */
90
+ export interface Topology {
91
+ readonly nodes: ReadonlyArray<TopologyNode>;
92
+ readonly edges: ReadonlyArray<TopologyEdge>;
93
+ /** Currently-active subflow (top of the subflow stack). Fork-branch and
94
+ * decision-branch nodes are instantaneous — they don't affect activeNodeId. */
95
+ readonly activeNodeId: string | null;
96
+ /** First node inserted. null before any composition event fires. */
97
+ readonly rootId: string | null;
98
+ }
99
+ export interface TopologyRecorderOptions {
100
+ /** Recorder id. Defaults to `topology-N` (auto-incremented). */
101
+ id?: string;
102
+ }
103
+ /**
104
+ * Factory — matches the `narrative()` / `metrics()` style.
105
+ */
106
+ export declare function topologyRecorder(options?: TopologyRecorderOptions): TopologyRecorder;
107
+ /**
108
+ * Stateful accumulator that watches FlowRecorder events and maintains a live
109
+ * composition graph. Attach via `executor.attachCombinedRecorder(recorder)` —
110
+ * footprintjs detects the `FlowRecorder` method shape and routes events.
111
+ */
112
+ export declare class TopologyRecorder implements FlowRecorder {
113
+ readonly id: string;
114
+ private readonly nodesById;
115
+ private readonly nodeOrder;
116
+ private readonly edges;
117
+ /** Stack of active SUBFLOW node ids. Fork/decision-branch nodes never push. */
118
+ private readonly subflowStack;
119
+ /** Map of childName → pending fork-branch synthetic node, consumed by
120
+ * the next matching `onSubflowEntry`. */
121
+ private readonly pendingForkByName;
122
+ /** Pending decision-branch synthetic node, consumed by a matching entry. */
123
+ private pendingDecision?;
124
+ constructor(options?: TopologyRecorderOptions);
125
+ onSubflowEntry(event: FlowSubflowEvent): void;
126
+ onSubflowExit(event: FlowSubflowEvent): void;
127
+ onFork(event: FlowForkEvent): void;
128
+ onDecision(event: FlowDecisionEvent): void;
129
+ onLoop(event: FlowLoopEvent): void;
130
+ /** Called by the executor before each `run()` — resets all state. */
131
+ clear(): void;
132
+ /** Live snapshot of the composition graph. Safe during or after a run. */
133
+ getTopology(): Topology;
134
+ /** Direct children of a node — insertion-ordered. */
135
+ getChildren(nodeId: string): TopologyNode[];
136
+ /** All nodes of a given kind. */
137
+ getByKind(kind: TopologyNodeKind): TopologyNode[];
138
+ /** All mounted subflow nodes. Convenience for agent-centric views. */
139
+ getSubflowNodes(): TopologyNode[];
140
+ /** All fork-branch nodes sharing the same parent as `nodeId` — i.e.,
141
+ * parallel siblings of a parallel branch. Empty if `nodeId` isn't a
142
+ * fork-branch or has no parent. */
143
+ getParallelSiblings(nodeId: string): TopologyNode[];
144
+ /** Emit a snapshot bundle for inclusion in `executor.getSnapshot()`. */
145
+ toSnapshot(): {
146
+ name: string;
147
+ description: string;
148
+ preferredOperation: "translate";
149
+ data: Topology;
150
+ };
151
+ }
@@ -27,6 +27,8 @@ export type { CausalChainOptions, CausalNode, KeysReadLookup } from './lib/memor
27
27
  export { causalChain, flattenCausalDAG, formatCausalChain } from './lib/memory/backtrack.js';
28
28
  export { KeyedRecorder } from './lib/recorder/KeyedRecorder.js';
29
29
  export { SequenceRecorder } from './lib/recorder/SequenceRecorder.js';
30
+ export type { Topology, TopologyEdge, TopologyIncomingKind, TopologyNode, TopologyRecorderOptions, } from './lib/recorder/TopologyRecorder.js';
31
+ export { TopologyRecorder, topologyRecorder } from './lib/recorder/TopologyRecorder.js';
30
32
  export type { QualityEntry, QualityRecorderOptions, QualityScoringFn } from './lib/recorder/QualityRecorder.js';
31
33
  export { QualityRecorder } from './lib/recorder/QualityRecorder.js';
32
34
  export type { QualityFrame, QualityStackTrace } from './lib/recorder/qualityTrace.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "footprintjs",
3
- "version": "4.14.0",
3
+ "version": "4.15.0",
4
4
  "description": "Explainable backend flows — automatic causal traces, decision evidence, and MCP tool generation for AI agents",
5
5
  "license": "MIT",
6
6
  "author": "Sanjay Krishna Anbalagan",