footprintjs 4.17.2 → 6.0.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.
Files changed (167) hide show
  1. package/CLAUDE.md +71 -9
  2. package/dist/advanced.js +2 -3
  3. package/dist/esm/advanced.js +2 -2
  4. package/dist/esm/index.js +3 -3
  5. package/dist/esm/lib/builder/FlowChartBuilder.js +359 -70
  6. package/dist/esm/lib/builder/index.js +1 -1
  7. package/dist/esm/lib/builder/structure/StructureRecorder.js +158 -0
  8. package/dist/esm/lib/builder/structure/StructureRecorderDispatcher.js +171 -0
  9. package/dist/esm/lib/builder/types.js +1 -1
  10. package/dist/esm/lib/decide/decide.js +9 -9
  11. package/dist/esm/lib/decide/evidence.js +2 -2
  12. package/dist/esm/lib/engine/errors/errorInfo.js +4 -3
  13. package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +11 -2
  14. package/dist/esm/lib/engine/handlers/DeciderHandler.js +5 -7
  15. package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +2 -2
  16. package/dist/esm/lib/engine/handlers/SelectorHandler.js +9 -7
  17. package/dist/esm/lib/engine/handlers/SubflowExecutor.js +7 -1
  18. package/dist/esm/lib/engine/handlers/index.js +1 -3
  19. package/dist/esm/lib/engine/handlers/types.js +2 -2
  20. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +14 -4
  21. package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +5 -5
  22. package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +8 -1
  23. package/dist/esm/lib/engine/narrative/types.js +1 -1
  24. package/dist/esm/lib/engine/runtimeStageId.js +64 -2
  25. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +30 -56
  26. package/dist/esm/lib/engine/types.js +1 -1
  27. package/dist/esm/lib/engine/walkSubflowSpec.js +144 -0
  28. package/dist/esm/lib/memory/StageContext.js +3 -3
  29. package/dist/esm/lib/memory/backtrack.js +1 -1
  30. package/dist/esm/lib/reactive/createTypedScope.js +5 -5
  31. package/dist/esm/lib/reactive/types.js +7 -7
  32. package/dist/esm/lib/recorder/BoundaryStateStore.js +167 -0
  33. package/dist/esm/lib/recorder/BoundaryStateTracker.js +4 -4
  34. package/dist/esm/lib/recorder/CombinedRecorder.js +9 -9
  35. package/dist/esm/lib/recorder/CommitRangeIndex.js +207 -0
  36. package/dist/esm/lib/recorder/CompositeRecorder.js +6 -6
  37. package/dist/esm/lib/recorder/EmitRecorder.js +3 -3
  38. package/dist/esm/lib/recorder/InOutRecorder.js +1 -1
  39. package/dist/esm/lib/recorder/KeyedStore.js +113 -0
  40. package/dist/esm/lib/recorder/QualityRecorder.js +2 -2
  41. package/dist/esm/lib/recorder/SequenceRecorder.js +2 -2
  42. package/dist/esm/lib/recorder/SequenceStore.js +195 -0
  43. package/dist/esm/lib/recorder/TopologyRecorder.js +1 -1
  44. package/dist/esm/lib/recorder/index.js +13 -3
  45. package/dist/esm/lib/runner/ExecutionRuntime.js +1 -1
  46. package/dist/esm/lib/runner/FlowChartExecutor.js +75 -44
  47. package/dist/esm/lib/runner/RunContext.js +2 -2
  48. package/dist/esm/lib/runner/RunnableChart.js +1 -1
  49. package/dist/esm/lib/runner/getSubtreeSnapshot.js +3 -2
  50. package/dist/esm/lib/runner/runId.js +65 -0
  51. package/dist/esm/lib/scope/ScopeFacade.js +6 -6
  52. package/dist/esm/lib/scope/index.js +1 -1
  53. package/dist/esm/lib/scope/recorders/DebugRecorder.js +4 -4
  54. package/dist/esm/lib/scope/recorders/MetricRecorder.js +2 -2
  55. package/dist/esm/lib/scope/recorders/index.js +1 -1
  56. package/dist/esm/lib/scope/types.js +1 -1
  57. package/dist/esm/recorders.js +1 -1
  58. package/dist/esm/trace.js +15 -2
  59. package/dist/index.js +3 -3
  60. package/dist/lib/builder/FlowChartBuilder.js +359 -70
  61. package/dist/lib/builder/index.js +1 -1
  62. package/dist/lib/builder/structure/StructureRecorder.js +159 -0
  63. package/dist/lib/builder/structure/StructureRecorderDispatcher.js +175 -0
  64. package/dist/lib/builder/types.js +1 -1
  65. package/dist/lib/decide/decide.js +9 -9
  66. package/dist/lib/decide/evidence.js +2 -2
  67. package/dist/lib/engine/errors/errorInfo.js +4 -3
  68. package/dist/lib/engine/handlers/ChildrenExecutor.js +11 -2
  69. package/dist/lib/engine/handlers/DeciderHandler.js +5 -7
  70. package/dist/lib/engine/handlers/RuntimeStructureManager.js +2 -2
  71. package/dist/lib/engine/handlers/SelectorHandler.js +9 -7
  72. package/dist/lib/engine/handlers/SubflowExecutor.js +7 -1
  73. package/dist/lib/engine/handlers/index.js +2 -5
  74. package/dist/lib/engine/handlers/types.js +2 -2
  75. package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +14 -4
  76. package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +5 -5
  77. package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +8 -1
  78. package/dist/lib/engine/narrative/types.js +1 -1
  79. package/dist/lib/engine/runtimeStageId.js +66 -3
  80. package/dist/lib/engine/traversal/FlowchartTraverser.js +30 -56
  81. package/dist/lib/engine/types.js +1 -1
  82. package/dist/lib/engine/walkSubflowSpec.js +148 -0
  83. package/dist/lib/memory/StageContext.js +3 -3
  84. package/dist/lib/memory/backtrack.js +1 -1
  85. package/dist/lib/reactive/createTypedScope.js +5 -5
  86. package/dist/lib/reactive/types.js +7 -7
  87. package/dist/lib/recorder/BoundaryStateStore.js +171 -0
  88. package/dist/lib/recorder/BoundaryStateTracker.js +4 -4
  89. package/dist/lib/recorder/CombinedRecorder.js +9 -9
  90. package/dist/lib/recorder/CommitRangeIndex.js +211 -0
  91. package/dist/lib/recorder/CompositeRecorder.js +6 -6
  92. package/dist/lib/recorder/EmitRecorder.js +3 -3
  93. package/dist/lib/recorder/InOutRecorder.js +1 -1
  94. package/dist/lib/recorder/KeyedStore.js +117 -0
  95. package/dist/lib/recorder/QualityRecorder.js +2 -2
  96. package/dist/lib/recorder/SequenceRecorder.js +2 -2
  97. package/dist/lib/recorder/SequenceStore.js +199 -0
  98. package/dist/lib/recorder/TopologyRecorder.js +1 -1
  99. package/dist/lib/recorder/index.js +19 -6
  100. package/dist/lib/runner/ExecutionRuntime.js +1 -1
  101. package/dist/lib/runner/FlowChartExecutor.js +75 -44
  102. package/dist/lib/runner/RunContext.js +2 -2
  103. package/dist/lib/runner/RunnableChart.js +1 -1
  104. package/dist/lib/runner/getSubtreeSnapshot.js +3 -2
  105. package/dist/lib/runner/runId.js +70 -0
  106. package/dist/lib/scope/ScopeFacade.js +6 -6
  107. package/dist/lib/scope/index.js +1 -1
  108. package/dist/lib/scope/recorders/DebugRecorder.js +4 -4
  109. package/dist/lib/scope/recorders/MetricRecorder.js +2 -2
  110. package/dist/lib/scope/recorders/index.js +1 -1
  111. package/dist/lib/scope/types.js +1 -1
  112. package/dist/recorders.js +1 -1
  113. package/dist/trace.js +21 -2
  114. package/dist/types/advanced.d.ts +4 -4
  115. package/dist/types/index.d.ts +6 -4
  116. package/dist/types/lib/builder/FlowChartBuilder.d.ts +110 -14
  117. package/dist/types/lib/builder/index.d.ts +2 -1
  118. package/dist/types/lib/builder/structure/StructureRecorder.d.ts +349 -0
  119. package/dist/types/lib/builder/structure/StructureRecorderDispatcher.d.ts +77 -0
  120. package/dist/types/lib/builder/types.d.ts +20 -6
  121. package/dist/types/lib/decide/evidence.d.ts +3 -3
  122. package/dist/types/lib/engine/errors/errorInfo.d.ts +3 -2
  123. package/dist/types/lib/engine/handlers/DeciderHandler.d.ts +3 -3
  124. package/dist/types/lib/engine/handlers/RuntimeStructureManager.d.ts +1 -1
  125. package/dist/types/lib/engine/handlers/SelectorHandler.d.ts +2 -2
  126. package/dist/types/lib/engine/handlers/index.d.ts +1 -2
  127. package/dist/types/lib/engine/handlers/types.d.ts +2 -9
  128. package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +1 -1
  129. package/dist/types/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -4
  130. package/dist/types/lib/engine/narrative/types.d.ts +43 -4
  131. package/dist/types/lib/engine/runtimeStageId.d.ts +57 -1
  132. package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +12 -6
  133. package/dist/types/lib/engine/types.d.ts +0 -26
  134. package/dist/types/lib/engine/walkSubflowSpec.d.ts +95 -0
  135. package/dist/types/lib/memory/StageContext.d.ts +2 -2
  136. package/dist/types/lib/memory/backtrack.d.ts +1 -1
  137. package/dist/types/lib/reactive/types.d.ts +7 -7
  138. package/dist/types/lib/recorder/BoundaryStateStore.d.ts +115 -0
  139. package/dist/types/lib/recorder/BoundaryStateTracker.d.ts +3 -3
  140. package/dist/types/lib/recorder/CombinedRecorder.d.ts +11 -11
  141. package/dist/types/lib/recorder/CommitRangeIndex.d.ts +147 -0
  142. package/dist/types/lib/recorder/CompositeRecorder.d.ts +8 -8
  143. package/dist/types/lib/recorder/EmitRecorder.d.ts +2 -2
  144. package/dist/types/lib/recorder/InOutRecorder.d.ts +1 -1
  145. package/dist/types/lib/recorder/KeyedStore.d.ts +70 -0
  146. package/dist/types/lib/recorder/QualityRecorder.d.ts +4 -4
  147. package/dist/types/lib/recorder/SequenceRecorder.d.ts +1 -1
  148. package/dist/types/lib/recorder/SequenceStore.d.ts +120 -0
  149. package/dist/types/lib/recorder/TopologyRecorder.d.ts +1 -1
  150. package/dist/types/lib/recorder/index.d.ts +5 -2
  151. package/dist/types/lib/runner/ExecutionRuntime.d.ts +1 -1
  152. package/dist/types/lib/runner/FlowChartExecutor.d.ts +40 -30
  153. package/dist/types/lib/runner/RunContext.d.ts +2 -2
  154. package/dist/types/lib/runner/RunnableChart.d.ts +2 -2
  155. package/dist/types/lib/runner/runId.d.ts +45 -0
  156. package/dist/types/lib/scope/ScopeFacade.d.ts +4 -4
  157. package/dist/types/lib/scope/index.d.ts +1 -1
  158. package/dist/types/lib/scope/recorders/DebugRecorder.d.ts +4 -4
  159. package/dist/types/lib/scope/recorders/MetricRecorder.d.ts +4 -4
  160. package/dist/types/lib/scope/recorders/index.d.ts +1 -1
  161. package/dist/types/lib/scope/types.d.ts +1 -1
  162. package/dist/types/recorders.d.ts +1 -1
  163. package/dist/types/trace.d.ts +8 -1
  164. package/package.json +1 -1
  165. package/dist/esm/lib/engine/handlers/ExtractorRunner.js +0 -122
  166. package/dist/lib/engine/handlers/ExtractorRunner.js +0 -126
  167. package/dist/types/lib/engine/handlers/ExtractorRunner.d.ts +0 -41
@@ -9,7 +9,7 @@
9
9
  * const executor = new FlowChartExecutor(chart);
10
10
  *
11
11
  * // Options-object form (preferred when you need to customize behavior):
12
- * const executor = new FlowChartExecutor(chart, { scopeFactory: myFactory, enrichSnapshots: true });
12
+ * const executor = new FlowChartExecutor(chart, { scopeFactory: myFactory });
13
13
  *
14
14
  * // 2-param form (accepts a ScopeFactory directly, for backward compatibility):
15
15
  * const executor = new FlowChartExecutor(chart, myFactory);
@@ -21,12 +21,12 @@ import type { CombinedNarrativeRecorderOptions } from '../engine/narrative/Combi
21
21
  import type { CombinedNarrativeEntry } from '../engine/narrative/narrativeTypes.js';
22
22
  import type { ManifestEntry } from '../engine/narrative/recorders/ManifestFlowRecorder.js';
23
23
  import type { FlowRecorder } from '../engine/narrative/types.js';
24
- import { type ExecutorResult, type ExtractorError, type RunOptions, type ScopeFactory, type SerializedPipelineStructure, type StageNode, type StreamHandlers, type SubflowResult } from '../engine/types.js';
24
+ import { type ExecutorResult, type RunOptions, type ScopeFactory, type SerializedPipelineStructure, type StageNode, type StreamHandlers, type SubflowResult } from '../engine/types.js';
25
25
  import type { FlowchartCheckpoint } from '../pause/types.js';
26
26
  import type { CombinedRecorder } from '../recorder/CombinedRecorder.js';
27
27
  import type { EmitRecorder } from '../recorder/EmitRecorder.js';
28
28
  import type { ScopeProtectionMode } from '../scope/protection/types.js';
29
- import type { Recorder, RedactionPolicy, RedactionReport } from '../scope/types.js';
29
+ import type { RedactionPolicy, RedactionReport, ScopeRecorder } from '../scope/types.js';
30
30
  import { type RuntimeSnapshot } from './ExecutionRuntime.js';
31
31
  /**
32
32
  * Options object for `FlowChartExecutor` — preferred over positional params.
@@ -34,7 +34,7 @@ import { type RuntimeSnapshot } from './ExecutionRuntime.js';
34
34
  * ```typescript
35
35
  * const ex = new FlowChartExecutor(chart, {
36
36
  * scopeFactory: myFactory,
37
- * enrichSnapshots: true,
37
+ * defaultValuesForContext: { ... },
38
38
  * });
39
39
  * ```
40
40
  *
@@ -50,14 +50,6 @@ import { type RuntimeSnapshot } from './ExecutionRuntime.js';
50
50
  export interface FlowChartExecutorOptions<TScope = any> {
51
51
  /** Custom scope factory. Defaults to TypedScope or ScopeFacade auto-detection. */
52
52
  scopeFactory?: ScopeFactory<TScope>;
53
- /**
54
- * Attach a per-stage scope snapshot to each extractor result. When `true`, the
55
- * extraction callback receives the full shared state at the point that stage
56
- * committed — useful for debugging multi-stage state transitions. Defaults to
57
- * `false` (no scope snapshot attached). Can also be set on the chart via
58
- * `flowChart(...).enrichSnapshots(true)`.
59
- */
60
- enrichSnapshots?: boolean;
61
53
  /**
62
54
  * Default values pre-populated into the shared context before **each** stage
63
55
  * (re-applied every stage, acting as baseline defaults).
@@ -86,6 +78,10 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
86
78
  private traverser;
87
79
  /** Shared execution counter — survives pause/resume. Reset on fresh run(). */
88
80
  private _executionCounter;
81
+ /** Per-`run()` identifier — generated fresh per run + per resume. Threaded
82
+ * through every TraversalContext so recorders can scope state to a single
83
+ * run. See `runId.ts`. */
84
+ private _currentRunId;
89
85
  private narrativeEnabled;
90
86
  private narrativeOptions?;
91
87
  private combinedRecorder;
@@ -117,7 +113,7 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
117
113
  *
118
114
  * **Options object form** (preferred):
119
115
  * ```typescript
120
- * new FlowChartExecutor(chart, { scopeFactory, enrichSnapshots: true })
116
+ * new FlowChartExecutor(chart, { scopeFactory, defaultValuesForContext })
121
117
  * ```
122
118
  *
123
119
  * **2-param form** (also supported):
@@ -159,6 +155,24 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
159
155
  getCheckpoint(): FlowchartCheckpoint | undefined;
160
156
  /** Returns `true` if the most recent run() was paused (checkpoint available). */
161
157
  isPaused(): boolean;
158
+ /**
159
+ * Number of commits in the run's commit log. O(1) — direct length
160
+ * read, no snapshot materialization. Use this to stamp commit
161
+ * indices on observer events (e.g., `BoundaryRecorder` storing
162
+ * `commitIdxBefore` / `commitIdxAfter` per domain event for
163
+ * `CommitRangeIndex` queries — see `footprintjs/trace`).
164
+ *
165
+ * Returns 0 before any run; after, returns the cumulative commit
166
+ * count across the executor's lifetime (including resumes).
167
+ *
168
+ * IMPLEMENTATION NOTE: this returns `runtime.executionHistory.length`,
169
+ * which is the same value as `getSnapshot().commitLog.length`. The
170
+ * naming asymmetry is historical — the underlying `EventLog` field
171
+ * is named `executionHistory` but stores the `CommitBundle[]` that
172
+ * `commitLog` exposes. They are the SAME array (verified by the
173
+ * "matches commitLog.length" integration test).
174
+ */
175
+ getCommitCount(): number;
162
176
  /**
163
177
  * Resume a paused flowchart from a checkpoint.
164
178
  *
@@ -201,7 +215,7 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
201
215
  /** DFS search for a node by ID in the StageNode graph. Cycle-safe via visited set. */
202
216
  private dfsFind;
203
217
  /**
204
- * Attach a scope Recorder to observe data operations (reads, writes, commits).
218
+ * Attach a scope ScopeRecorder to observe data operations (reads, writes, commits).
205
219
  * Automatically attached to every ScopeFacade created during traversal.
206
220
  * Must be called before run().
207
221
  *
@@ -216,18 +230,18 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
216
230
  * @example
217
231
  * ```typescript
218
232
  * // Multiple recorders with different configs — each gets a unique ID
219
- * executor.attachRecorder(new MetricRecorder());
220
- * executor.attachRecorder(new DebugRecorder({ verbosity: 'minimal' }));
233
+ * executor.attachScopeRecorder(new MetricRecorder());
234
+ * executor.attachScopeRecorder(new DebugRecorder({ verbosity: 'minimal' }));
221
235
  *
222
236
  * // Override a framework-attached recorder by passing its well-known ID
223
- * executor.attachRecorder(new MetricRecorder('metrics'));
237
+ * executor.attachScopeRecorder(new MetricRecorder('metrics'));
224
238
  *
225
239
  * // Attaching twice with same ID replaces (no double-counting)
226
- * executor.attachRecorder(new MetricRecorder('my-metrics'));
227
- * executor.attachRecorder(new MetricRecorder('my-metrics')); // replaces previous
240
+ * executor.attachScopeRecorder(new MetricRecorder('my-metrics'));
241
+ * executor.attachScopeRecorder(new MetricRecorder('my-metrics')); // replaces previous
228
242
  * ```
229
243
  */
230
- attachRecorder(recorder: Recorder): void;
244
+ attachScopeRecorder(recorder: ScopeRecorder): void;
231
245
  /**
232
246
  * Detach a child flowchart on the given driver and return a `DetachHandle`
233
247
  * the caller can `wait()` on (Promise) or read `.status` from (sync).
@@ -257,9 +271,9 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
257
271
  */
258
272
  detachAndForget(driver: import('../detach/types.js').DetachDriver, child: import('../builder/types.js').FlowChart, input?: unknown): void;
259
273
  /** Detach all scope Recorders with the given ID. */
260
- detachRecorder(id: string): void;
274
+ detachScopeRecorder(id: string): void;
261
275
  /** Returns a defensive copy of attached scope Recorders. */
262
- getRecorders(): Recorder[];
276
+ getScopeRecorders(): ScopeRecorder[];
263
277
  /**
264
278
  * Attach a FlowRecorder to observe control flow events.
265
279
  * Automatically enables narrative if not already enabled.
@@ -277,7 +291,7 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
277
291
  * data-flow, control-flow, or both). Detects at runtime which streams the
278
292
  * recorder has methods for and routes it to the correct internal channels.
279
293
  *
280
- * Preferred over calling `attachRecorder` and `attachFlowRecorder`
294
+ * Preferred over calling `attachScopeRecorder` and `attachFlowRecorder`
281
295
  * separately, because forgetting one of the two is a silent foot-gun —
282
296
  * half your events never fire and there is no runtime warning. With
283
297
  * `attachCombinedRecorder` the library guarantees the recorder's declared
@@ -287,7 +301,7 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
287
301
  *
288
302
  * Idempotent by `id` across ALL channels — re-attaching with the same `id`
289
303
  * replaces the previous instance everywhere it was registered. Mixing
290
- * `attachCombinedRecorder(x)` with a prior `attachRecorder(y)` or
304
+ * `attachCombinedRecorder(x)` with a prior `attachScopeRecorder(y)` or
291
305
  * `attachFlowRecorder(y)` that share `x.id === y.id` is also safe: the
292
306
  * combined attach replaces the single-channel registration on whichever
293
307
  * channel(s) `x` has methods for. No duplicate firings occur.
@@ -330,8 +344,8 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
330
344
  * Internally, emit recorders share the scope-recorder channel because
331
345
  * emit events fire from inside `ScopeFacade` during stage execution,
332
346
  * same timing as `onRead`/`onWrite`. This method is a convenience that
333
- * delegates to `attachRecorder` — consumers can also use
334
- * `attachRecorder` directly for a recorder that implements BOTH
347
+ * delegates to `attachScopeRecorder` — consumers can also use
348
+ * `attachScopeRecorder` directly for a recorder that implements BOTH
335
349
  * `onWrite` and `onEmit`. Either approach places the recorder on the
336
350
  * same underlying list, so `onEmit` fires exactly once per event.
337
351
  *
@@ -397,10 +411,6 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
397
411
  getRuntimeStructure(): SerializedPipelineStructure | undefined;
398
412
  /** @internal */
399
413
  getSubflowResults(): Map<string, SubflowResult>;
400
- /** @internal */
401
- getExtractedResults<TResult = unknown>(): Map<string, TResult>;
402
- /** @internal */
403
- getExtractorErrors(): ExtractorError[];
404
414
  /**
405
415
  * Returns the subflow manifest from an attached ManifestFlowRecorder.
406
416
  * Returns empty array if no ManifestFlowRecorder is attached.
@@ -10,7 +10,7 @@
10
10
  import type { FlowChart } from '../builder/types.js';
11
11
  import type { FlowRecorder } from '../engine/narrative/types.js';
12
12
  import type { RunOptions } from '../engine/types.js';
13
- import type { Recorder, RedactionPolicy } from '../scope/types.js';
13
+ import type { RedactionPolicy, ScopeRecorder } from '../scope/types.js';
14
14
  /** Result from RunContext.run() — owns state and output. */
15
15
  export interface RunResult {
16
16
  /** Raw scope state after execution. */
@@ -29,7 +29,7 @@ export declare class RunContext<TOut = any, TScope = any> {
29
29
  private redactionPolicy?;
30
30
  constructor(chart: FlowChart<TOut, TScope>);
31
31
  /** Attach a recorder. Auto-detects scope vs flow recorder. Chainable. */
32
- recorder(r: Recorder | FlowRecorder): RunContext<TOut, TScope>;
32
+ recorder(r: ScopeRecorder | FlowRecorder): RunContext<TOut, TScope>;
33
33
  /** Set redaction policy for this run. Chainable. */
34
34
  redact(policy: RedactionPolicy): RunContext<TOut, TScope>;
35
35
  /** Execute the chart with accumulated config. Returns RunResult. */
@@ -9,7 +9,7 @@ import type { FlowChart } from '../builder/types.js';
9
9
  import type { JsonSchema } from '../contract/types.js';
10
10
  import type { FlowRecorder } from '../engine/narrative/types.js';
11
11
  import type { RunOptions } from '../engine/types.js';
12
- import type { Recorder, RedactionPolicy } from '../scope/types.js';
12
+ import type { RedactionPolicy, ScopeRecorder } from '../scope/types.js';
13
13
  import { type RunResult, RunContext } from './RunContext.js';
14
14
  /** OpenAPI generation options. */
15
15
  export interface ChartOpenAPIOptions {
@@ -38,7 +38,7 @@ export interface MCPToolDescription {
38
38
  */
39
39
  export interface RunnableFlowChart<TOut = any, TScope = any> extends FlowChart<TOut, TScope> {
40
40
  /** Attach a recorder for the next run. Returns a chainable RunContext. */
41
- recorder(r: Recorder | FlowRecorder): RunContext<TOut, TScope>;
41
+ recorder(r: ScopeRecorder | FlowRecorder): RunContext<TOut, TScope>;
42
42
  /** Set redaction policy for the next run. Returns a chainable RunContext. */
43
43
  redact(policy: RedactionPolicy): RunContext<TOut, TScope>;
44
44
  /** Execute the chart directly (bare run, no recorders). */
@@ -0,0 +1,45 @@
1
+ /**
2
+ * runId — per-`executor.run()` identifier generator.
3
+ *
4
+ * Pattern: monotonic counter + clock-guarded timestamp. One id per
5
+ * call to `executor.run()` (or `executor.resume()`). Stable
6
+ * for the duration of that run; unique across consecutive
7
+ * runs.
8
+ * Role: primitive that solves the "two consecutive runs of the
9
+ * same executor produce identical runtimeStageIds" class of
10
+ * bugs. Recorders that accumulate state across runs detect
11
+ * "new run" via `runId` change and reset transient
12
+ * bookkeeping.
13
+ *
14
+ * Format: `${timestamp}-${counter}`.
15
+ * - `timestamp` is `Date.now()` clamped to a monotonic-clock guard
16
+ * (never decreases — protects against NTP / system-clock
17
+ * adjustments).
18
+ * - `counter` is a process-local incrementing integer, ZERO-PADDED
19
+ * to 10 digits so lexicographic sort matches numeric order
20
+ * (`"...001"` < `"...010"` < `"...100"`). 10 digits = 10 billion
21
+ * runs in a single process — sufficient for any real workload.
22
+ *
23
+ * Lexicographic ordering of `runId` strings matches chronological
24
+ * ordering for runs that are at least 1ms apart, AND for runs that
25
+ * happen within the same millisecond (because the padded counter
26
+ * tie-breaks). The counter NEVER resets — it is process-global.
27
+ *
28
+ * Process-local only. Cross-process correlation uses
29
+ * `getEnv().traceId` (consumer-supplied), not `runId`. Documented
30
+ * in `docs/design/v5-recorder-redesign.md` Section 8.1.
31
+ */
32
+ /**
33
+ * Generate a fresh runId. Called once per `executor.run()` and once
34
+ * per `executor.resume()`. Pure (deterministic for a given clock +
35
+ * counter state); no side effects beyond advancing the counter and
36
+ * monotonic-clock guard.
37
+ */
38
+ export declare function generateRunId(): string;
39
+ /**
40
+ * Reset the runId state. Test-only. NEVER call from production code —
41
+ * runIds must be process-globally monotonic.
42
+ *
43
+ * @internal
44
+ */
45
+ export declare function _resetRunIdStateForTesting(): void;
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import type { ExecutionEnv } from '../engine/types.js';
17
17
  import { StageContext } from '../memory/StageContext.js';
18
- import type { CommitEvent, Recorder, RedactionPolicy, RedactionReport } from './types.js';
18
+ import type { CommitEvent, RedactionPolicy, RedactionReport, ScopeRecorder } from './types.js';
19
19
  export declare class ScopeFacade {
20
20
  static readonly BRAND: unique symbol;
21
21
  /**
@@ -60,9 +60,9 @@ export declare class ScopeFacade {
60
60
  * Never includes actual values — only key names, field names, and patterns.
61
61
  */
62
62
  getRedactionReport(): RedactionReport;
63
- attachRecorder(recorder: Recorder): void;
64
- detachRecorder(recorderId: string): void;
65
- getRecorders(): Recorder[];
63
+ attachScopeRecorder(recorder: ScopeRecorder): void;
64
+ detachScopeRecorder(recorderId: string): void;
65
+ getScopeRecorders(): ScopeRecorder[];
66
66
  /** @internal */
67
67
  notifyStageStart(): void;
68
68
  /** @internal */
@@ -5,7 +5,7 @@
5
5
  * providers, protection, and Zod-based scope definitions.
6
6
  */
7
7
  export { ScopeFacade } from './ScopeFacade.js';
8
- export type { CommitEvent, ErrorEvent, ReadEvent, Recorder, RecorderContext, RedactionPolicy, RedactionReport, StageEvent, WriteEvent, } from './types.js';
8
+ export type { CommitEvent, ErrorEvent, ReadEvent, RecorderContext, RedactionPolicy, RedactionReport, ScopeRecorder, StageEvent, WriteEvent, } from './types.js';
9
9
  export type { DebugEntry, DebugRecorderOptions, DebugVerbosity } from './recorders/DebugRecorder.js';
10
10
  export { DebugRecorder } from './recorders/DebugRecorder.js';
11
11
  export type { AggregatedMetrics, StageMetrics } from './recorders/MetricRecorder.js';
@@ -5,7 +5,7 @@
5
5
  * and stage lifecycle events for troubleshooting.
6
6
  */
7
7
  import type { RecorderOperation } from '../../recorder/RecorderOperation.js';
8
- import type { ErrorEvent, PauseEvent, ReadEvent, Recorder, ResumeEvent, StageEvent, WriteEvent } from '../types.js';
8
+ import type { ErrorEvent, PauseEvent, ReadEvent, ResumeEvent, ScopeRecorder, StageEvent, WriteEvent } from '../types.js';
9
9
  export type DebugVerbosity = 'minimal' | 'verbose';
10
10
  export interface DebugEntry {
11
11
  type: 'read' | 'write' | 'error' | 'stageStart' | 'stageEnd' | 'pause' | 'resume';
@@ -26,15 +26,15 @@ export interface DebugRecorderOptions {
26
26
  * @example
27
27
  * ```typescript
28
28
  * // Verbose debug for development
29
- * executor.attachRecorder(new DebugRecorder({ verbosity: 'verbose' }));
29
+ * executor.attachScopeRecorder(new DebugRecorder({ verbosity: 'verbose' }));
30
30
  *
31
31
  * // Minimal debug for production (errors only)
32
- * executor.attachRecorder(new DebugRecorder({ verbosity: 'minimal' }));
32
+ * executor.attachScopeRecorder(new DebugRecorder({ verbosity: 'minimal' }));
33
33
  *
34
34
  * // Both coexist — different auto IDs
35
35
  * ```
36
36
  */
37
- export declare class DebugRecorder implements Recorder {
37
+ export declare class DebugRecorder implements ScopeRecorder {
38
38
  private static _counter;
39
39
  readonly id: string;
40
40
  readonly preferredOperation: RecorderOperation;
@@ -7,7 +7,7 @@
7
7
  * @example
8
8
  * ```typescript
9
9
  * const metric = new MetricRecorder();
10
- * executor.attachRecorder(metric);
10
+ * executor.attachScopeRecorder(metric);
11
11
  * await executor.run();
12
12
  *
13
13
  * // Per-step (time-travel):
@@ -22,7 +22,7 @@
22
22
  */
23
23
  import { KeyedRecorder } from '../../recorder/KeyedRecorder.js';
24
24
  import type { RecorderOperation } from '../../recorder/RecorderOperation.js';
25
- import type { CommitEvent, PauseEvent, ReadEvent, Recorder, StageEvent, WriteEvent } from '../types.js';
25
+ import type { CommitEvent, PauseEvent, ReadEvent, ScopeRecorder, StageEvent, WriteEvent } from '../types.js';
26
26
  /** Per-invocation metrics for a single execution step. */
27
27
  export interface StepMetrics {
28
28
  /** Human-readable stage name. */
@@ -60,14 +60,14 @@ export interface StageMetrics {
60
60
  }
61
61
  /** Options for MetricRecorder. */
62
62
  export interface MetricRecorderOptions {
63
- /** Recorder ID. Defaults to auto-increment (`metrics-1`, `metrics-2`, ...). */
63
+ /** ScopeRecorder ID. Defaults to auto-increment (`metrics-1`, `metrics-2`, ...). */
64
64
  id?: string;
65
65
  /** Filter which stages are recorded. Return `true` to record, `false` to skip. */
66
66
  stageFilter?: (stageName: string) => boolean;
67
67
  /** Preferred UI operation. Defaults to 'aggregate' (dashboard totals). */
68
68
  preferredOperation?: RecorderOperation;
69
69
  }
70
- export declare class MetricRecorder extends KeyedRecorder<StepMetrics> implements Recorder {
70
+ export declare class MetricRecorder extends KeyedRecorder<StepMetrics> implements ScopeRecorder {
71
71
  private static _counter;
72
72
  readonly id: string;
73
73
  readonly preferredOperation: RecorderOperation;
@@ -1,4 +1,4 @@
1
- export type { CommitEvent, ErrorEvent, ReadEvent, Recorder, RecorderContext, StageEvent, WriteEvent, } from '../types.js';
1
+ export type { CommitEvent, ErrorEvent, ReadEvent, RecorderContext, ScopeRecorder, StageEvent, WriteEvent, } from '../types.js';
2
2
  export type { DebugEntry, DebugRecorderOptions, DebugVerbosity } from './DebugRecorder.js';
3
3
  export { DebugRecorder } from './DebugRecorder.js';
4
4
  export type { AggregatedMetrics, StageMetrics, StepMetrics } from './MetricRecorder.js';
@@ -100,7 +100,7 @@ export interface RedactionReport {
100
100
  * If a recorder throws, the error is caught and passed to onError
101
101
  * hooks of other recorders; the scope operation continues normally.
102
102
  */
103
- export interface Recorder {
103
+ export interface ScopeRecorder {
104
104
  readonly id: string;
105
105
  onRead?(event: ReadEvent): void;
106
106
  onWrite?(event: WriteEvent): void;
@@ -37,7 +37,7 @@ import { DebugRecorder } from './lib/scope/recorders/DebugRecorder.js';
37
37
  import type { AggregatedMetrics, MetricRecorderOptions, StageMetrics } from './lib/scope/recorders/MetricRecorder.js';
38
38
  import { MetricRecorder } from './lib/scope/recorders/MetricRecorder.js';
39
39
  /**
40
- * Recorder factory for combined flow+data narrative.
40
+ * ScopeRecorder factory for combined flow+data narrative.
41
41
  *
42
42
  * The returned recorder is a `CombinedNarrativeRecorder` — attach it to a
43
43
  * chart/executor, then read structured entries via `.getEntries()` after
@@ -21,10 +21,17 @@
21
21
  * ```
22
22
  */
23
23
  export type { ExecutionCounter } from './lib/engine/runtimeStageId.js';
24
- export { buildRuntimeStageId, createExecutionCounter, parseRuntimeStageId } from './lib/engine/runtimeStageId.js';
24
+ export { buildRuntimeStageId, createExecutionCounter, parseRuntimeStageId, splitStageId, } from './lib/engine/runtimeStageId.js';
25
+ export type { WalkerItem, WalkerOptions } from './lib/engine/walkSubflowSpec.js';
26
+ export { walkSubflowSpec } from './lib/engine/walkSubflowSpec.js';
25
27
  export { findCommit, findCommits, findLastWriter } from './lib/memory/commitLogUtils.js';
26
28
  export type { CausalChainOptions, CausalNode, KeysReadLookup } from './lib/memory/backtrack.js';
27
29
  export { causalChain, flattenCausalDAG, formatCausalChain } from './lib/memory/backtrack.js';
30
+ export { BoundaryStateStore } from './lib/recorder/BoundaryStateStore.js';
31
+ export { KeyedStore } from './lib/recorder/KeyedStore.js';
32
+ export { SequenceStore } from './lib/recorder/SequenceStore.js';
33
+ export type { RangeEntry, RangeToken } from './lib/recorder/CommitRangeIndex.js';
34
+ export { CommitRangeIndex } from './lib/recorder/CommitRangeIndex.js';
28
35
  export { KeyedRecorder } from './lib/recorder/KeyedRecorder.js';
29
36
  export { SequenceRecorder } from './lib/recorder/SequenceRecorder.js';
30
37
  export { BoundaryStateTracker } from './lib/recorder/BoundaryStateTracker.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "footprintjs",
3
- "version": "4.17.2",
3
+ "version": "6.0.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",
@@ -1,122 +0,0 @@
1
- /**
2
- * ExtractorRunner — Per-stage snapshot extraction.
3
- *
4
- * Coordinates traversal extractor invocations: step counting,
5
- * snapshot enrichment, error collection, and result storage.
6
- */
7
- import { computeNodeType } from './RuntimeStructureManager.js';
8
- export class ExtractorRunner {
9
- extractor;
10
- enrichSnapshots;
11
- executionRuntime;
12
- logger;
13
- extractedResults = new Map();
14
- extractorErrors = [];
15
- stepCounter = 0;
16
- /** Current subflow context for metadata propagation. Set/cleared during subflow execution. */
17
- currentSubflowId;
18
- /** Current fork context for metadata propagation. Set/cleared during parallel children execution. */
19
- currentForkId;
20
- constructor(extractor, enrichSnapshots, executionRuntime, logger) {
21
- this.extractor = extractor;
22
- this.enrichSnapshots = enrichSnapshots;
23
- this.executionRuntime = executionRuntime;
24
- this.logger = logger;
25
- }
26
- /**
27
- * Call the extractor for a stage and store the result.
28
- * Increments stepCounter (1-based) before creating snapshot.
29
- */
30
- callExtractor(node, context, stagePath, stageOutput, errorInfo) {
31
- if (!this.extractor)
32
- return;
33
- this.stepCounter++;
34
- try {
35
- const snapshot = {
36
- node,
37
- context,
38
- stepNumber: this.stepCounter,
39
- structureMetadata: this.buildStructureMetadata(node),
40
- };
41
- if (this.enrichSnapshots) {
42
- try {
43
- snapshot.scopeState = { ...this.executionRuntime.globalStore.getState() };
44
- snapshot.debugInfo = {
45
- logs: { ...context.debug.logContext },
46
- errors: { ...context.debug.errorContext },
47
- metrics: { ...context.debug.metricContext },
48
- evals: { ...context.debug.evalContext },
49
- };
50
- if (context.debug.flowMessages.length > 0) {
51
- snapshot.debugInfo.flowMessages = [...context.debug.flowMessages];
52
- }
53
- snapshot.stageOutput = stageOutput;
54
- if (errorInfo) {
55
- snapshot.errorInfo = errorInfo;
56
- }
57
- snapshot.historyIndex = this.executionRuntime.executionHistory.list().length;
58
- }
59
- catch (enrichError) {
60
- this.logger.warn(`Enrichment error at stage '${stagePath}':`, { error: enrichError });
61
- }
62
- }
63
- const result = this.extractor(snapshot);
64
- if (result !== undefined && result !== null) {
65
- this.extractedResults.set(stagePath, result);
66
- }
67
- }
68
- catch (error) {
69
- this.logger.error(`Extractor error at stage '${stagePath}':`, { error });
70
- this.extractorErrors.push({
71
- stagePath,
72
- message: error?.message ?? String(error),
73
- error,
74
- });
75
- }
76
- }
77
- /**
78
- * Generate the stage path for extractor results.
79
- * Uses node.id combined with branchPath.
80
- */
81
- getStagePath(node, branchPath, contextStageName) {
82
- const baseName = node.id;
83
- const nodeId = contextStageName && contextStageName !== node.name ? contextStageName : baseName;
84
- if (!branchPath)
85
- return nodeId;
86
- return `${branchPath}.${nodeId}`;
87
- }
88
- buildStructureMetadata(node) {
89
- const metadata = {
90
- type: computeNodeType(node),
91
- };
92
- if (node.isSubflowRoot) {
93
- metadata.isSubflowRoot = true;
94
- metadata.subflowId = node.subflowId;
95
- metadata.subflowName = node.subflowName;
96
- }
97
- else if (this.currentSubflowId) {
98
- metadata.subflowId = this.currentSubflowId;
99
- }
100
- if (this.currentForkId) {
101
- metadata.isParallelChild = true;
102
- metadata.parallelGroupId = this.currentForkId;
103
- }
104
- if (node.isStreaming) {
105
- metadata.streamId = node.streamId;
106
- }
107
- const hasDynamicChildren = Boolean(node.children?.length && !node.nextNodeSelector && node.fn);
108
- if (hasDynamicChildren) {
109
- metadata.isDynamic = true;
110
- }
111
- return metadata;
112
- }
113
- /** Returns extracted results collected during execution. */
114
- getExtractedResults() {
115
- return this.extractedResults;
116
- }
117
- /** Returns errors encountered during extraction. */
118
- getExtractorErrors() {
119
- return this.extractorErrors;
120
- }
121
- }
122
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXh0cmFjdG9yUnVubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9lbmdpbmUvaGFuZGxlcnMvRXh0cmFjdG9yUnVubmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBWUgsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRS9ELE1BQU0sT0FBTyxlQUFlO0lBQ1QsU0FBUyxDQUFzQjtJQUMvQixlQUFlLENBQVU7SUFDekIsZ0JBQWdCLENBQW9CO0lBQ3BDLE1BQU0sQ0FBVTtJQUV6QixnQkFBZ0IsR0FBeUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUNuRCxlQUFlLEdBQXFCLEVBQUUsQ0FBQztJQUN2QyxXQUFXLEdBQUcsQ0FBQyxDQUFDO0lBRXhCLDhGQUE4RjtJQUM5RixnQkFBZ0IsQ0FBVTtJQUUxQixxR0FBcUc7SUFDckcsYUFBYSxDQUFVO0lBRXZCLFlBQ0UsU0FBeUMsRUFDekMsZUFBd0IsRUFDeEIsZ0JBQW1DLEVBQ25DLE1BQWU7UUFFZixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztRQUN2QyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUM7UUFDekMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVEOzs7T0FHRztJQUNILGFBQWEsQ0FDWCxJQUFlLEVBQ2YsT0FBcUIsRUFDckIsU0FBaUIsRUFDakIsV0FBcUIsRUFDckIsU0FBNkM7UUFFN0MsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTO1lBQUUsT0FBTztRQUU1QixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFbkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQWtCO2dCQUM5QixJQUFJO2dCQUNKLE9BQU87Z0JBQ1AsVUFBVSxFQUFFLElBQUksQ0FBQyxXQUFX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KiBFeHRyYWN0b3JSdW5uZXIg4oCUIFBlci1zdGFnZSBzbmFwc2hvdCBleHRyYWN0aW9uLlxuICpcbiAqIENvb3JkaW5hdGVzIHRyYXZlcnNhbCBleHRyYWN0b3IgaW52b2NhdGlvbnM6IHN0ZXAgY291bnRpbmcsXG4gKiBzbmFwc2hvdCBlbnJpY2htZW50LCBlcnJvciBjb2xsZWN0aW9uLCBhbmQgcmVzdWx0IHN0b3JhZ2UuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBTdGFnZUNvbnRleHQgfSBmcm9tICcuLi8uLi9tZW1vcnkvU3RhZ2VDb250ZXh0LmpzJztcbmltcG9ydCB0eXBlIHsgU3RhZ2VOb2RlIH0gZnJvbSAnLi4vZ3JhcGgvU3RhZ2VOb2RlLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgRXh0cmFjdG9yRXJyb3IsXG4gIElFeGVjdXRpb25SdW50aW1lLFxuICBJTG9nZ2VyLFxuICBSdW50aW1lU3RydWN0dXJlTWV0YWRhdGEsXG4gIFN0YWdlU25hcHNob3QsXG4gIFRyYXZlcnNhbEV4dHJhY3Rvcixcbn0gZnJvbSAnLi4vdHlwZXMuanMnO1xuaW1wb3J0IHsgY29tcHV0ZU5vZGVUeXBlIH0gZnJvbSAnLi9SdW50aW1lU3RydWN0dXJlTWFuYWdlci5qcyc7XG5cbmV4cG9ydCBjbGFzcyBFeHRyYWN0b3JSdW5uZXI8VE91dCA9IGFueSwgVFNjb3BlID0gYW55PiB7XG4gIHByaXZhdGUgcmVhZG9ubHkgZXh0cmFjdG9yPzogVHJhdmVyc2FsRXh0cmFjdG9yO1xuICBwcml2YXRlIHJlYWRvbmx5IGVucmljaFNuYXBzaG90czogYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSBleGVjdXRpb25SdW50aW1lOiBJRXhlY3V0aW9uUnVudGltZTtcbiAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXI6IElMb2dnZXI7XG5cbiAgcHJpdmF0ZSBleHRyYWN0ZWRSZXN1bHRzOiBNYXA8c3RyaW5nLCB1bmtub3duPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBleHRyYWN0b3JFcnJvcnM6IEV4dHJhY3RvckVycm9yW10gPSBbXTtcbiAgcHJpdmF0ZSBzdGVwQ291bnRlciA9IDA7XG5cbiAgLyoqIEN1cnJlbnQgc3ViZmxvdyBjb250ZXh0IGZvciBtZXRhZGF0YSBwcm9wYWdhdGlvbi4gU2V0L2NsZWFyZWQgZHVyaW5nIHN1YmZsb3cgZXhlY3V0aW9uLiAqL1xuICBjdXJyZW50U3ViZmxvd0lkPzogc3RyaW5nO1xuXG4gIC8qKiBDdXJyZW50IGZvcmsgY29udGV4dCBmb3IgbWV0YWRhdGEgcHJvcGFnYXRpb24uIFNldC9jbGVhcmVkIGR1cmluZyBwYXJhbGxlbCBjaGlsZHJlbiBleGVjdXRpb24uICovXG4gIGN1cnJlbnRGb3JrSWQ/OiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgZXh0cmFjdG9yOiBUcmF2ZXJzYWxFeHRyYWN0b3IgfCB1bmRlZmluZWQsXG4gICAgZW5yaWNoU25hcHNob3RzOiBib29sZWFuLFxuICAgIGV4ZWN1dGlvblJ1bnRpbWU6IElFeGVjdXRpb25SdW50aW1lLFxuICAgIGxvZ2dlcjogSUxvZ2dlcixcbiAgKSB7XG4gICAgdGhpcy5leHRyYWN0b3IgPSBleHRyYWN0b3I7XG4gICAgdGhpcy5lbnJpY2hTbmFwc2hvdHMgPSBlbnJpY2hTbmFwc2hvdHM7XG4gICAgdGhpcy5leGVjdXRpb25SdW50aW1lID0gZXhlY3V0aW9uUnVudGltZTtcbiAgICB0aGlzLmxvZ2dlciA9IGxvZ2dlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsIHRoZSBleHRyYWN0b3IgZm9yIGEgc3RhZ2UgYW5kIHN0b3JlIHRoZSByZXN1bHQuXG4gICAqIEluY3JlbWVudHMgc3RlcENvdW50ZXIgKDEtYmFzZWQpIGJlZm9yZSBjcmVhdGluZyBzbmFwc2hvdC5cbiAgICovXG4gIGNhbGxFeHRyYWN0b3IoXG4gICAgbm9kZTogU3RhZ2VOb2RlLFxuICAgIGNvbnRleHQ6IFN0YWdlQ29udGV4dCxcbiAgICBzdGFnZVBhdGg6IHN0cmluZyxcbiAgICBzdGFnZU91dHB1dD86IHVua25vd24sXG4gICAgZXJyb3JJbmZvPzogeyB0eXBlOiBzdHJpbmc7IG1lc3NhZ2U6IHN0cmluZyB9LFxuICApOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZXh0cmFjdG9yKSByZXR1cm47XG5cbiAgICB0aGlzLnN0ZXBDb3VudGVyKys7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3Qgc25hcHNob3Q6IFN0YWdlU25hcHNob3QgPSB7XG4gICAgICAgIG5vZGUsXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgIHN0ZXBOdW1iZXI6IHRoaXMuc3RlcENvdW50ZXIsXG4gICAgICAgIHN0cnVjdHVyZU1ldGFkYXRhOiB0aGlzLmJ1aWxkU3RydWN0dXJlTWV0YWRhdGEobm9kZSksXG4gICAgICB9O1xuXG4gICAgICBpZiAodGhpcy5lbnJpY2hTbmFwc2hvdHMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBzbmFwc2hvdC5zY29wZVN0YXRlID0geyAuLi50aGlzLmV4ZWN1dGlvblJ1bnRpbWUuZ2xvYmFsU3RvcmUuZ2V0U3RhdGUoKSB9O1xuXG4gICAgICAgICAgc25hcHNob3QuZGVidWdJbmZvID0ge1xuICAgICAgICAgICAgbG9nczogeyAuLi5jb250ZXh0LmRlYnVnLmxvZ0NvbnRleHQgfSxcbiAgICAgICAgICAgIGVycm9yczogeyAuLi5jb250ZXh0LmRlYnVnLmVycm9yQ29udGV4dCB9LFxuICAgICAgICAgICAgbWV0cmljczogeyAuLi5jb250ZXh0LmRlYnVnLm1ldHJpY0NvbnRleHQgfSxcbiAgICAgICAgICAgIGV2YWxzOiB7IC4uLmNvbnRleHQuZGVidWcuZXZhbENvbnRleHQgfSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGlmIChjb250ZXh0LmRlYnVnLmZsb3dNZXNzYWdlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBzbmFwc2hvdC5kZWJ1Z0luZm8uZmxvd01lc3NhZ2VzID0gWy4uLmNvbnRleHQuZGVidWcuZmxvd01lc3NhZ2VzXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzbmFwc2hvdC5zdGFnZU91dHB1dCA9IHN0YWdlT3V0cHV0O1xuXG4gICAgICAgICAgaWYgKGVycm9ySW5mbykge1xuICAgICAgICAgICAgc25hcHNob3QuZXJyb3JJbmZvID0gZXJyb3JJbmZvO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHNuYXBzaG90Lmhpc3RvcnlJbmRleCA9IHRoaXMuZXhlY3V0aW9uUnVudGltZS5leGVjdXRpb25IaXN0b3J5Lmxpc3QoKS5sZW5ndGg7XG4gICAgICAgIH0gY2F0Y2ggKGVucmljaEVycm9yOiBhbnkpIHtcbiAgICAgICAgICB0aGlzLmxvZ2dlci53YXJuKGBFbnJpY2htZW50IGVycm9yIGF0IHN0YWdlICcke3N0YWdlUGF0aH0nOmAsIHsgZXJyb3I6IGVucmljaEVycm9yIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuZXh0cmFjdG9yKHNuYXBzaG90KTtcblxuICAgICAgaWYgKHJlc3VsdCAhPT0gdW5kZWZpbmVkICYmIHJlc3VsdCAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmV4dHJhY3RlZFJlc3VsdHMuc2V0KHN0YWdlUGF0aCwgcmVzdWx0KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihgRXh0cmFjdG9yIGVycm9yIGF0IHN0YWdlICcke3N0YWdlUGF0aH0nOmAsIHsgZXJyb3IgfSk7XG4gICAgICB0aGlzLmV4dHJhY3RvckVycm9ycy5wdXNoKHtcbiAgICAgICAgc3RhZ2VQYXRoLFxuICAgICAgICBtZXNzYWdlOiBlcnJvcj8ubWVzc2FnZSA/PyBTdHJpbmcoZXJyb3IpLFxuICAgICAgICBlcnJvcixcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0aGUgc3RhZ2UgcGF0aCBmb3IgZXh0cmFjdG9yIHJlc3VsdHMuXG4gICAqIFVzZXMgbm9kZS5pZCBjb21iaW5lZCB3aXRoIGJyYW5jaFBhdGguXG4gICAqL1xuICBnZXRTdGFnZVBhdGgobm9kZTogU3RhZ2VOb2RlLCBicmFuY2hQYXRoPzogc3RyaW5nLCBjb250ZXh0U3RhZ2VOYW1lPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBiYXNlTmFtZSA9IG5vZGUuaWQ7XG4gICAgY29uc3Qgbm9kZUlkID0gY29udGV4dFN0YWdlTmFtZSAmJiBjb250ZXh0U3RhZ2VOYW1lICE9PSBub2RlLm5hbWUgPyBjb250ZXh0U3RhZ2VOYW1lIDogYmFzZU5hbWU7XG4gICAgaWYgKCFicmFuY2hQYXRoKSByZXR1cm4gbm9kZUlkO1xuICAgIHJldHVybiBgJHticmFuY2hQYXRofS4ke25vZGVJZH1gO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFN0cnVjdHVyZU1ldGFkYXRhKG5vZGU6IFN0YWdlTm9kZSk6IFJ1bnRpbWVTdHJ1Y3R1cmVNZXRhZGF0YSB7XG4gICAgY29uc3QgbWV0YWRhdGE6IFJ1bnRpbWVTdHJ1Y3R1cmVNZXRhZGF0YSA9IHtcbiAgICAgIHR5cGU6IGNvbXB1dGVOb2RlVHlwZShub2RlKSxcbiAgICB9O1xuXG4gICAgaWYgKG5vZGUuaXNTdWJmbG93Um9vdCkge1xuICAgICAgbWV0YWRhdGEuaXNTdWJmbG93Um9vdCA9IHRydWU7XG4gICAgICBtZXRhZGF0YS5zdWJmbG93SWQgPSBub2RlLnN1YmZsb3dJZDtcbiAgICAgIG1ldGFkYXRhLnN1YmZsb3dOYW1lID0gbm9kZS5zdWJmbG93TmFtZTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuY3VycmVudFN1YmZsb3dJZCkge1xuICAgICAgbWV0YWRhdGEuc3ViZmxvd0lkID0gdGhpcy5jdXJyZW50U3ViZmxvd0lkO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmN1cnJlbnRGb3JrSWQpIHtcbiAgICAgIG1ldGFkYXRhLmlzUGFyYWxsZWxDaGlsZCA9IHRydWU7XG4gICAgICBtZXRhZGF0YS5wYXJhbGxlbEdyb3VwSWQgPSB0aGlzLmN1cnJlbnRGb3JrSWQ7XG4gICAgfVxuXG4gICAgaWYgKG5vZGUuaXNTdHJlYW1pbmcpIHtcbiAgICAgIG1ldGFkYXRhLnN0cmVhbUlkID0gbm9kZS5zdHJlYW1JZDtcbiAgICB9XG5cbiAgICBjb25zdCBoYXNEeW5hbWljQ2hpbGRyZW4gPSBCb29sZWFuKG5vZGUuY2hpbGRyZW4/Lmxlbmd0aCAmJiAhbm9kZS5uZXh0Tm9kZVNlbGVjdG9yICYmIG5vZGUuZm4pO1xuICAgIGlmIChoYXNEeW5hbWljQ2hpbGRyZW4pIHtcbiAgICAgIG1ldGFkYXRhLmlzRHluYW1pYyA9IHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1ldGFkYXRhO1xuICB9XG5cbiAgLyoqIFJldHVybnMgZXh0cmFjdGVkIHJlc3VsdHMgY29sbGVjdGVkIGR1cmluZyBleGVjdXRpb24uICovXG4gIGdldEV4dHJhY3RlZFJlc3VsdHM8VFJlc3VsdCA9IHVua25vd24+KCk6IE1hcDxzdHJpbmcsIFRSZXN1bHQ+IHtcbiAgICByZXR1cm4gdGhpcy5leHRyYWN0ZWRSZXN1bHRzIGFzIE1hcDxzdHJpbmcsIFRSZXN1bHQ+O1xuICB9XG5cbiAgLyoqIFJldHVybnMgZXJyb3JzIGVuY291bnRlcmVkIGR1cmluZyBleHRyYWN0aW9uLiAqL1xuICBnZXRFeHRyYWN0b3JFcnJvcnMoKTogRXh0cmFjdG9yRXJyb3JbXSB7XG4gICAgcmV0dXJuIHRoaXMuZXh0cmFjdG9yRXJyb3JzO1xuICB9XG59XG4iXX0=