footprintjs 10.0.1 → 10.2.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/AGENTS.md +2 -1
- package/CLAUDE.md +61 -7
- package/README.md +136 -312
- package/dist/esm/index.d.ts +62 -2
- package/dist/esm/index.js +13 -6
- package/dist/esm/lib/attempt/anySignal.d.ts +19 -0
- package/dist/esm/lib/attempt/anySignal.js +39 -0
- package/dist/esm/lib/attempt/call.d.ts +88 -0
- package/dist/esm/lib/attempt/call.js +129 -0
- package/dist/esm/lib/attempt/category.d.ts +37 -0
- package/dist/esm/lib/attempt/category.js +131 -0
- package/dist/esm/lib/attempt/correlation.d.ts +95 -0
- package/dist/esm/lib/attempt/correlation.js +178 -0
- package/dist/esm/lib/attempt/deadline.d.ts +44 -0
- package/dist/esm/lib/attempt/deadline.js +101 -0
- package/dist/esm/lib/attempt/decision.d.ts +52 -0
- package/dist/esm/lib/attempt/decision.js +134 -0
- package/dist/esm/lib/attempt/effect.d.ts +76 -0
- package/dist/esm/lib/attempt/effect.js +160 -0
- package/dist/esm/lib/attempt/errors.d.ts +41 -0
- package/dist/esm/lib/attempt/errors.js +44 -0
- package/dist/esm/lib/attempt/index.d.ts +18 -0
- package/dist/esm/lib/attempt/index.js +15 -0
- package/dist/esm/lib/attempt/name.d.ts +21 -0
- package/dist/esm/lib/attempt/name.js +43 -0
- package/dist/esm/lib/attempt/observed.d.ts +66 -0
- package/dist/esm/lib/attempt/observed.js +171 -0
- package/dist/esm/lib/attempt/policy.d.ts +45 -0
- package/dist/esm/lib/attempt/policy.js +83 -0
- package/dist/esm/lib/attempt/record.d.ts +11 -0
- package/dist/esm/lib/attempt/record.js +24 -0
- package/dist/esm/lib/attempt/retryLoopContext.d.ts +18 -0
- package/dist/esm/lib/attempt/retryLoopContext.js +24 -0
- package/dist/esm/lib/attempt/retryLoopTypes.d.ts +18 -0
- package/dist/esm/lib/attempt/retryLoopTypes.js +2 -0
- package/dist/esm/lib/attempt/runner.d.ts +157 -0
- package/dist/esm/lib/attempt/runner.js +523 -0
- package/dist/esm/lib/attempt/standalone.d.ts +47 -0
- package/dist/esm/lib/attempt/standalone.js +126 -0
- package/dist/esm/lib/attempt/types.d.ts +453 -0
- package/dist/esm/lib/attempt/types.js +16 -0
- package/dist/esm/lib/budget/index.d.ts +9 -0
- package/dist/esm/lib/budget/index.js +9 -0
- package/dist/esm/lib/budget/timeBudget.d.ts +136 -0
- package/dist/esm/lib/budget/timeBudget.js +666 -0
- package/dist/esm/lib/builder/FlowChartBuilder.d.ts +88 -3
- package/dist/esm/lib/builder/FlowChartBuilder.js +199 -9
- package/dist/esm/lib/builder/retryLoop.d.ts +56 -0
- package/dist/esm/lib/builder/retryLoop.js +283 -0
- package/dist/esm/lib/builder/types.d.ts +35 -1
- package/dist/esm/lib/builder/types.js +1 -1
- package/dist/esm/lib/decide/decide.js +2 -2
- package/dist/esm/lib/decide/index.d.ts +1 -1
- package/dist/esm/lib/decide/index.js +2 -2
- package/dist/esm/lib/decide/types.d.ts +3 -0
- package/dist/esm/lib/decide/types.js +1 -8
- package/dist/esm/lib/engine/graph/StageNode.d.ts +11 -1
- package/dist/esm/lib/engine/graph/StageNode.js +1 -1
- package/dist/esm/lib/engine/graph/prefixNodeTree.js +5 -1
- package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +36 -6
- package/dist/esm/lib/engine/handlers/DeciderHandler.js +9 -5
- package/dist/esm/lib/engine/handlers/ResumeEntry.js +3 -1
- package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -5
- package/dist/esm/lib/engine/handlers/StageRunner.d.ts +8 -1
- package/dist/esm/lib/engine/handlers/StageRunner.js +36 -9
- package/dist/esm/lib/engine/handlers/SubflowExecutor.js +24 -5
- package/dist/esm/lib/engine/handlers/commitStage.d.ts +7 -0
- package/dist/esm/lib/engine/handlers/commitStage.js +22 -4
- package/dist/esm/lib/engine/handlers/stageError.d.ts +9 -0
- package/dist/esm/lib/engine/handlers/stageError.js +23 -1
- package/dist/esm/lib/engine/index.d.ts +2 -2
- package/dist/esm/lib/engine/index.js +1 -1
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +68 -40
- package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
- package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
- package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
- package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +61 -9
- package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
- package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
- package/dist/esm/lib/engine/narrative/formatting/sentences.d.ts +23 -0
- package/dist/esm/lib/engine/narrative/formatting/sentences.js +127 -1
- package/dist/esm/lib/engine/narrative/index.d.ts +2 -2
- package/dist/esm/lib/engine/narrative/index.js +1 -1
- package/dist/esm/lib/engine/narrative/narrativeTypes.d.ts +27 -21
- package/dist/esm/lib/engine/narrative/narrativeTypes.js +1 -1
- package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
- package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
- package/dist/esm/lib/engine/narrative/recorders/index.d.ts +1 -1
- package/dist/esm/lib/engine/narrative/recorders/index.js +1 -1
- package/dist/esm/lib/engine/narrative/types.d.ts +74 -5
- package/dist/esm/lib/engine/narrative/types.js +1 -1
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +194 -118
- package/dist/esm/lib/engine/traversalContext.d.ts +7 -2
- package/dist/esm/lib/engine/traversalContext.js +6 -3
- package/dist/esm/lib/engine/types.d.ts +52 -57
- package/dist/esm/lib/engine/types.js +1 -1
- package/dist/esm/lib/errors/terminalFailure.d.ts +29 -0
- package/dist/esm/lib/errors/terminalFailure.js +60 -0
- package/dist/esm/lib/{decide → filter}/evaluator.d.ts +7 -2
- package/dist/esm/lib/filter/evaluator.js +135 -0
- package/dist/esm/lib/ids/idempotencyKey.d.ts +14 -0
- package/dist/esm/lib/ids/idempotencyKey.js +24 -0
- package/dist/esm/lib/memory/StageContext.d.ts +123 -3
- package/dist/esm/lib/memory/StageContext.js +245 -4
- package/dist/esm/lib/memory/attention.d.ts +26 -0
- package/dist/esm/lib/memory/attention.js +171 -0
- package/dist/esm/lib/memory/borrowedMutation.d.ts +8 -0
- package/dist/esm/lib/memory/borrowedMutation.js +14 -1
- package/dist/esm/lib/memory/frameTypes.d.ts +38 -0
- package/dist/esm/lib/memory/frameTypes.js +3 -1
- package/dist/esm/lib/memory/redaction.d.ts +12 -0
- package/dist/esm/lib/memory/redaction.js +54 -5
- package/dist/esm/lib/pause/record.js +10 -1
- package/dist/esm/lib/pause/types.d.ts +19 -0
- package/dist/esm/lib/pause/types.js +17 -1
- package/dist/esm/lib/reactive/createTypedScope.js +3 -1
- package/dist/esm/lib/reactive/types.d.ts +36 -4
- package/dist/esm/lib/reactive/types.js +3 -1
- package/dist/esm/lib/recorder/AttemptRecorder.d.ts +141 -0
- package/dist/esm/lib/recorder/AttemptRecorder.js +412 -0
- package/dist/esm/lib/recorder/ControlDepRecorder.d.ts +36 -2
- package/dist/esm/lib/recorder/ControlDepRecorder.js +50 -2
- package/dist/esm/lib/recorder/EmitRecorder.d.ts +3 -0
- package/dist/esm/lib/recorder/EmitRecorder.js +1 -1
- package/dist/esm/lib/recorder/InOutRecorder.d.ts +37 -1
- package/dist/esm/lib/recorder/InOutRecorder.js +75 -6
- package/dist/esm/lib/recorder/QualityRecorder.d.ts +32 -5
- package/dist/esm/lib/recorder/QualityRecorder.js +87 -29
- package/dist/esm/lib/recorder/TopologyRecorder.d.ts +35 -5
- package/dist/esm/lib/recorder/TopologyRecorder.js +76 -2
- package/dist/esm/lib/recorder/attemptMetricRows.d.ts +11 -0
- package/dist/esm/lib/recorder/attemptMetricRows.js +202 -0
- package/dist/esm/lib/recorder/attemptMetrics.d.ts +7 -0
- package/dist/esm/lib/recorder/attemptMetrics.js +165 -0
- package/dist/esm/lib/recorder/attemptMetricsTypes.d.ts +114 -0
- package/dist/esm/lib/recorder/attemptMetricsTypes.js +2 -0
- package/dist/esm/lib/recorder/attemptOTel.d.ts +78 -0
- package/dist/esm/lib/recorder/attemptOTel.js +107 -0
- package/dist/esm/lib/recorder/attemptSeries.d.ts +81 -0
- package/dist/esm/lib/recorder/attemptSeries.js +103 -0
- package/dist/esm/lib/recorder/hooks.d.ts +9 -0
- package/dist/esm/lib/recorder/hooks.js +4 -1
- package/dist/esm/lib/runner/DeferredObserverTier.js +13 -1
- package/dist/esm/lib/runner/ExecutionRuntime.d.ts +54 -6
- package/dist/esm/lib/runner/ExecutionRuntime.js +57 -5
- package/dist/esm/lib/runner/FlowChartExecutor.d.ts +46 -2
- package/dist/esm/lib/runner/FlowChartExecutor.js +330 -101
- package/dist/esm/lib/runner/RunnableChart.d.ts +6 -0
- package/dist/esm/lib/runner/RunnableChart.js +5 -1
- package/dist/esm/lib/runner/attach.d.ts +2 -1
- package/dist/esm/lib/runner/attach.js +8 -2
- package/dist/esm/lib/runner/checkpoint.js +3 -1
- package/dist/esm/lib/runner/deadline.d.ts +42 -0
- package/dist/esm/lib/runner/deadline.js +90 -0
- package/dist/esm/lib/runner/index.d.ts +3 -1
- package/dist/esm/lib/runner/index.js +2 -1
- package/dist/esm/lib/runner/options.d.ts +17 -0
- package/dist/esm/lib/runner/options.js +3 -1
- package/dist/esm/lib/runner/recordSink.d.ts +128 -0
- package/dist/esm/lib/runner/recordSink.js +296 -0
- package/dist/esm/lib/runner/resume.d.ts +3 -0
- package/dist/esm/lib/runner/resume.js +22 -2
- package/dist/esm/lib/runner/snapshot.d.ts +2 -2
- package/dist/esm/lib/runner/snapshot.js +6 -2
- package/dist/esm/lib/scope/ScopeFacade.d.ts +118 -4
- package/dist/esm/lib/scope/ScopeFacade.js +304 -7
- package/dist/esm/lib/scope/recorders/DebugRecorder.d.ts +17 -3
- package/dist/esm/lib/scope/recorders/DebugRecorder.js +79 -13
- package/dist/esm/lib/scope/recorders/MetricRecorder.d.ts +10 -0
- package/dist/esm/lib/scope/recorders/MetricRecorder.js +15 -2
- package/dist/esm/lib/scope/runtime.d.ts +3 -0
- package/dist/esm/lib/scope/runtime.js +1 -1
- package/dist/esm/lib/scope/types.d.ts +6 -0
- package/dist/esm/lib/scope/types.js +1 -1
- package/dist/esm/lib/sinks/fileSink.d.ts +135 -0
- package/dist/esm/lib/sinks/fileSink.js +387 -0
- package/dist/esm/recorders.d.ts +8 -2
- package/dist/esm/recorders.js +7 -1
- package/dist/esm/sinks.d.ts +23 -0
- package/dist/esm/sinks.js +23 -0
- package/dist/esm/trace.d.ts +2 -2
- package/dist/esm/trace.js +1 -1
- package/dist/index.js +77 -60
- package/dist/lib/attempt/anySignal.js +43 -0
- package/dist/lib/attempt/call.js +134 -0
- package/dist/lib/attempt/category.js +136 -0
- package/dist/lib/attempt/correlation.js +186 -0
- package/dist/lib/attempt/deadline.js +112 -0
- package/dist/lib/attempt/decision.js +139 -0
- package/dist/lib/attempt/effect.js +174 -0
- package/dist/lib/attempt/errors.js +49 -0
- package/dist/lib/attempt/index.js +26 -0
- package/dist/lib/attempt/name.js +48 -0
- package/dist/lib/attempt/observed.js +177 -0
- package/dist/lib/attempt/policy.js +92 -0
- package/dist/lib/attempt/record.js +29 -0
- package/dist/lib/attempt/retryLoopContext.js +31 -0
- package/dist/lib/attempt/retryLoopTypes.js +3 -0
- package/dist/lib/attempt/runner.js +530 -0
- package/dist/lib/attempt/standalone.js +130 -0
- package/dist/lib/attempt/types.js +17 -0
- package/dist/lib/budget/index.js +17 -0
- package/dist/lib/budget/timeBudget.js +674 -0
- package/dist/lib/builder/FlowChartBuilder.js +199 -9
- package/dist/lib/builder/retryLoop.js +287 -0
- package/dist/lib/builder/types.js +1 -1
- package/dist/lib/decide/decide.js +2 -2
- package/dist/lib/decide/index.js +2 -2
- package/dist/lib/decide/types.js +1 -8
- package/dist/lib/engine/graph/StageNode.js +1 -1
- package/dist/lib/engine/graph/prefixNodeTree.js +5 -1
- package/dist/lib/engine/handlers/ChildrenExecutor.js +36 -6
- package/dist/lib/engine/handlers/DeciderHandler.js +7 -3
- package/dist/lib/engine/handlers/ResumeEntry.js +3 -1
- package/dist/lib/engine/handlers/SelectorHandler.js +4 -3
- package/dist/lib/engine/handlers/StageRunner.js +36 -9
- package/dist/lib/engine/handlers/SubflowExecutor.js +24 -5
- package/dist/lib/engine/handlers/commitStage.js +24 -5
- package/dist/lib/engine/handlers/stageError.js +26 -2
- package/dist/lib/engine/index.js +1 -1
- package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +67 -39
- package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
- package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +60 -8
- package/dist/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
- package/dist/lib/engine/narrative/formatting/sentences.js +131 -2
- package/dist/lib/engine/narrative/index.js +1 -1
- package/dist/lib/engine/narrative/narrativeTypes.js +1 -1
- package/dist/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
- package/dist/lib/engine/narrative/recorders/index.js +1 -1
- package/dist/lib/engine/narrative/types.js +1 -1
- package/dist/lib/engine/traversal/FlowchartTraverser.js +192 -116
- package/dist/lib/engine/traversalContext.js +6 -3
- package/dist/lib/engine/types.js +1 -1
- package/dist/lib/errors/terminalFailure.js +64 -0
- package/dist/lib/filter/evaluator.js +139 -0
- package/dist/lib/ids/idempotencyKey.js +28 -0
- package/dist/lib/memory/StageContext.js +246 -5
- package/dist/lib/memory/attention.js +175 -0
- package/dist/lib/memory/borrowedMutation.js +16 -2
- package/dist/lib/memory/frameTypes.js +3 -1
- package/dist/lib/memory/redaction.js +54 -5
- package/dist/lib/pause/record.js +10 -1
- package/dist/lib/pause/types.js +17 -1
- package/dist/lib/reactive/createTypedScope.js +3 -1
- package/dist/lib/reactive/types.js +3 -1
- package/dist/lib/recorder/AttemptRecorder.js +417 -0
- package/dist/lib/recorder/ControlDepRecorder.js +50 -2
- package/dist/lib/recorder/EmitRecorder.js +1 -1
- package/dist/lib/recorder/InOutRecorder.js +75 -6
- package/dist/lib/recorder/QualityRecorder.js +87 -29
- package/dist/lib/recorder/TopologyRecorder.js +76 -2
- package/dist/lib/recorder/attemptMetricRows.js +209 -0
- package/dist/lib/recorder/attemptMetrics.js +174 -0
- package/dist/lib/recorder/attemptMetricsTypes.js +3 -0
- package/dist/lib/recorder/attemptOTel.js +111 -0
- package/dist/lib/recorder/attemptSeries.js +113 -0
- package/dist/lib/recorder/hooks.js +4 -1
- package/dist/lib/runner/DeferredObserverTier.js +13 -1
- package/dist/lib/runner/ExecutionRuntime.js +57 -5
- package/dist/lib/runner/FlowChartExecutor.js +330 -101
- package/dist/lib/runner/RunnableChart.js +5 -1
- package/dist/lib/runner/attach.js +8 -2
- package/dist/lib/runner/checkpoint.js +3 -1
- package/dist/lib/runner/deadline.js +94 -0
- package/dist/lib/runner/index.js +4 -2
- package/dist/lib/runner/options.js +3 -1
- package/dist/lib/runner/recordSink.js +302 -0
- package/dist/lib/runner/resume.js +22 -2
- package/dist/lib/runner/snapshot.js +6 -2
- package/dist/lib/scope/ScopeFacade.js +303 -6
- package/dist/lib/scope/recorders/DebugRecorder.js +79 -13
- package/dist/lib/scope/recorders/MetricRecorder.js +15 -2
- package/dist/lib/scope/runtime.js +1 -1
- package/dist/lib/scope/types.js +1 -1
- package/dist/lib/sinks/fileSink.js +392 -0
- package/dist/recorders.js +10 -2
- package/dist/sinks.js +32 -0
- package/dist/trace.js +1 -1
- package/dist/types/index.d.ts +62 -2
- package/dist/types/lib/attempt/anySignal.d.ts +19 -0
- package/dist/types/lib/attempt/call.d.ts +88 -0
- package/dist/types/lib/attempt/category.d.ts +37 -0
- package/dist/types/lib/attempt/correlation.d.ts +95 -0
- package/dist/types/lib/attempt/deadline.d.ts +44 -0
- package/dist/types/lib/attempt/decision.d.ts +52 -0
- package/dist/types/lib/attempt/effect.d.ts +76 -0
- package/dist/types/lib/attempt/errors.d.ts +41 -0
- package/dist/types/lib/attempt/index.d.ts +18 -0
- package/dist/types/lib/attempt/name.d.ts +21 -0
- package/dist/types/lib/attempt/observed.d.ts +66 -0
- package/dist/types/lib/attempt/policy.d.ts +45 -0
- package/dist/types/lib/attempt/record.d.ts +11 -0
- package/dist/types/lib/attempt/retryLoopContext.d.ts +18 -0
- package/dist/types/lib/attempt/retryLoopTypes.d.ts +18 -0
- package/dist/types/lib/attempt/runner.d.ts +157 -0
- package/dist/types/lib/attempt/standalone.d.ts +47 -0
- package/dist/types/lib/attempt/types.d.ts +453 -0
- package/dist/types/lib/budget/index.d.ts +9 -0
- package/dist/types/lib/budget/timeBudget.d.ts +136 -0
- package/dist/types/lib/builder/FlowChartBuilder.d.ts +88 -3
- package/dist/types/lib/builder/retryLoop.d.ts +56 -0
- package/dist/types/lib/builder/types.d.ts +35 -1
- package/dist/types/lib/decide/index.d.ts +1 -1
- package/dist/types/lib/decide/types.d.ts +3 -0
- package/dist/types/lib/engine/graph/StageNode.d.ts +11 -1
- package/dist/types/lib/engine/handlers/StageRunner.d.ts +8 -1
- package/dist/types/lib/engine/handlers/commitStage.d.ts +7 -0
- package/dist/types/lib/engine/handlers/stageError.d.ts +9 -0
- package/dist/types/lib/engine/index.d.ts +2 -2
- package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
- package/dist/types/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
- package/dist/types/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
- package/dist/types/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
- package/dist/types/lib/engine/narrative/formatting/sentences.d.ts +23 -0
- package/dist/types/lib/engine/narrative/index.d.ts +2 -2
- package/dist/types/lib/engine/narrative/narrativeTypes.d.ts +27 -21
- package/dist/types/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
- package/dist/types/lib/engine/narrative/recorders/index.d.ts +1 -1
- package/dist/types/lib/engine/narrative/types.d.ts +74 -5
- package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
- package/dist/types/lib/engine/traversalContext.d.ts +7 -2
- package/dist/types/lib/engine/types.d.ts +52 -57
- package/dist/types/lib/errors/terminalFailure.d.ts +29 -0
- package/dist/types/lib/{decide → filter}/evaluator.d.ts +7 -2
- package/dist/types/lib/ids/idempotencyKey.d.ts +14 -0
- package/dist/types/lib/memory/StageContext.d.ts +123 -3
- package/dist/types/lib/memory/attention.d.ts +26 -0
- package/dist/types/lib/memory/borrowedMutation.d.ts +8 -0
- package/dist/types/lib/memory/frameTypes.d.ts +38 -0
- package/dist/types/lib/memory/redaction.d.ts +12 -0
- package/dist/types/lib/pause/types.d.ts +19 -0
- package/dist/types/lib/reactive/types.d.ts +36 -4
- package/dist/types/lib/recorder/AttemptRecorder.d.ts +141 -0
- package/dist/types/lib/recorder/ControlDepRecorder.d.ts +36 -2
- package/dist/types/lib/recorder/EmitRecorder.d.ts +3 -0
- package/dist/types/lib/recorder/InOutRecorder.d.ts +37 -1
- package/dist/types/lib/recorder/QualityRecorder.d.ts +32 -5
- package/dist/types/lib/recorder/TopologyRecorder.d.ts +35 -5
- package/dist/types/lib/recorder/attemptMetricRows.d.ts +11 -0
- package/dist/types/lib/recorder/attemptMetrics.d.ts +7 -0
- package/dist/types/lib/recorder/attemptMetricsTypes.d.ts +114 -0
- package/dist/types/lib/recorder/attemptOTel.d.ts +78 -0
- package/dist/types/lib/recorder/attemptSeries.d.ts +81 -0
- package/dist/types/lib/recorder/hooks.d.ts +9 -0
- package/dist/types/lib/runner/ExecutionRuntime.d.ts +54 -6
- package/dist/types/lib/runner/FlowChartExecutor.d.ts +46 -2
- package/dist/types/lib/runner/RunnableChart.d.ts +6 -0
- package/dist/types/lib/runner/attach.d.ts +2 -1
- package/dist/types/lib/runner/deadline.d.ts +42 -0
- package/dist/types/lib/runner/index.d.ts +3 -1
- package/dist/types/lib/runner/options.d.ts +17 -0
- package/dist/types/lib/runner/recordSink.d.ts +128 -0
- package/dist/types/lib/runner/resume.d.ts +3 -0
- package/dist/types/lib/runner/snapshot.d.ts +2 -2
- package/dist/types/lib/scope/ScopeFacade.d.ts +118 -4
- package/dist/types/lib/scope/recorders/DebugRecorder.d.ts +17 -3
- package/dist/types/lib/scope/recorders/MetricRecorder.d.ts +10 -0
- package/dist/types/lib/scope/runtime.d.ts +3 -0
- package/dist/types/lib/scope/types.d.ts +6 -0
- package/dist/types/lib/sinks/fileSink.d.ts +135 -0
- package/dist/types/recorders.d.ts +8 -2
- package/dist/types/sinks.d.ts +23 -0
- package/dist/types/trace.d.ts +2 -2
- package/package.json +20 -6
- package/dist/esm/lib/decide/evaluator.js +0 -130
- package/dist/lib/decide/evaluator.js +0 -134
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* }
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
+
import type { AttemptContext, AttemptError, CallOptions, RetryPolicy, RunCorrelation } from '../attempt/types.js';
|
|
17
|
+
import type { FlowChart } from '../builder/types.js';
|
|
18
|
+
import type { DetachDriver, DetachHandle } from '../detach/types.js';
|
|
16
19
|
import type { ExecutionEnv } from '../engine/types.js';
|
|
17
20
|
import { StageContext } from '../memory/StageContext.js';
|
|
18
21
|
import type { CommitEvent, RedactionPolicy, RedactionReport, ScopeRecorder } from './types.js';
|
|
@@ -63,6 +66,28 @@ export declare class ScopeFacade {
|
|
|
63
66
|
* tree and this stays unset; see {@link rule}.
|
|
64
67
|
*/
|
|
65
68
|
private _localRule?;
|
|
69
|
+
/**
|
|
70
|
+
* The run's correlation (10.1), installed by the executor's composed scope factory
|
|
71
|
+
* (`RunObservers · composeScopeFactory`) — stamped LAST on every scope and emit event this facade fires,
|
|
72
|
+
* only when present, so a run without one fires byte-identical events.
|
|
73
|
+
*/
|
|
74
|
+
private _correlation?;
|
|
75
|
+
/**
|
|
76
|
+
* The attempt this facade was built for (P1b) — the runner's, read off the
|
|
77
|
+
* context at construction. A facade is ONE attempt's handle: once that
|
|
78
|
+
* attempt ends without an answer (its cap, the deadline, a cancellation, a
|
|
79
|
+
* throw), the function behind it may still be running, and anything it
|
|
80
|
+
* touches through this facade is refused ({@link refuseIfAttemptEnded}) —
|
|
81
|
+
* a write or an emit is also recorded on the stage. Absent for a stage the
|
|
82
|
+
* runner does not run: nothing is fenced, as before.
|
|
83
|
+
*/
|
|
84
|
+
private readonly _attempt?;
|
|
85
|
+
/** The run's signal, for `$attempt()` of a stage the runner does not run. */
|
|
86
|
+
private readonly _runSignal?;
|
|
87
|
+
/** `$call`s with `of > 1` in flight through this facade — a keyless touching call inside one is refused (P3). */
|
|
88
|
+
private _retryingCalls;
|
|
89
|
+
/** This attempt's observed reports, grouped into series (P2) — made on the first report. */
|
|
90
|
+
private _observedBook?;
|
|
66
91
|
constructor(context: StageContext, stageName: string, readOnlyValues?: unknown, executionEnv?: ExecutionEnv);
|
|
67
92
|
/**
|
|
68
93
|
* The redaction rule this facade decides with — the SAME object its
|
|
@@ -93,6 +118,12 @@ export declare class ScopeFacade {
|
|
|
93
118
|
* @internal
|
|
94
119
|
*/
|
|
95
120
|
useRedactionPolicy(policy: RedactionPolicy): void;
|
|
121
|
+
/**
|
|
122
|
+
* Install the run's correlation — every scope and emit event this facade fires carries it; `undefined` clears
|
|
123
|
+
* it. Engine-only (the composed scope factory calls it once per stage), like `useRedactionPolicy`.
|
|
124
|
+
* @internal
|
|
125
|
+
*/
|
|
126
|
+
useCorrelation(correlation: RunCorrelation | undefined): void;
|
|
96
127
|
/** @internal */
|
|
97
128
|
getRedactionPolicy(): RedactionPolicy | undefined;
|
|
98
129
|
/**
|
|
@@ -119,6 +150,85 @@ export declare class ScopeFacade {
|
|
|
119
150
|
* to the stage that made the write.
|
|
120
151
|
*/
|
|
121
152
|
private assertLive;
|
|
153
|
+
/**
|
|
154
|
+
* The attempt fence (P1b): this facade's attempt has ended, so whatever the
|
|
155
|
+
* abandoned function does now must not reach the stage — not its buffer, its
|
|
156
|
+
* reads, its untracked sources or a recorder. Refused; a write or an emit is
|
|
157
|
+
* recorded on the stage first (`StageSnapshot.lateWrites`, the name only),
|
|
158
|
+
* a read (`channel` undefined) is not.
|
|
159
|
+
*/
|
|
160
|
+
private refuseIfAttemptEnded;
|
|
161
|
+
/**
|
|
162
|
+
* The attempt this stage function runs in — `scope.$attempt()` (design
|
|
163
|
+
* §3.1). Its `signal` aborts when the attempt must stop (its cap, the run's
|
|
164
|
+
* deadline, a cancellation): pass it to `fetch` and SDK calls. Its
|
|
165
|
+
* `timeLeftMs()` reads the run's deadline — time is an input the record
|
|
166
|
+
* cannot replay, so with a deadline the read marks the stage's commit
|
|
167
|
+
* `untrackedSources: ['env']`, as `getEnv()` does.
|
|
168
|
+
*
|
|
169
|
+
* A stage the attempt runner does not run (no retry policy, no `timeoutMs`,
|
|
170
|
+
* no deadline) is attempt 1 of 1, with the run's signal and `Infinity` left.
|
|
171
|
+
*
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const t = scope.$attempt();
|
|
174
|
+
* const res = await fetch(url, { signal: t.signal });
|
|
175
|
+
* if (t.timeLeftMs() < 1_000) scope.summary = 'partial';
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
getAttempt(): AttemptContext;
|
|
179
|
+
/**
|
|
180
|
+
* A call to an outside system, made inside this stage — `scope.$call(target, fn, policy?)` (design §3.6, P2).
|
|
181
|
+
* `fn` runs on the attempt runner under `policy` (none = ONE attempt, still recorded: a single call is evidence
|
|
182
|
+
* too), and every attempt is an `AttemptRecord` of kind `'call'` on this stage's execution-tree node and on
|
|
183
|
+
* `onAttempt` — its timing, outcome, failure category and the retry-or-stop decision, its error served under the
|
|
184
|
+
* run's redaction rule.
|
|
185
|
+
*
|
|
186
|
+
* The call lives within this stage attempt: it is capped by the time the attempt has left (its cap, the run's
|
|
187
|
+
* deadline) and `fn`'s `signal` aborts when the attempt does; once the attempt is over nothing of the call lands
|
|
188
|
+
* and no further attempt of it starts (`attempt/call.ts`). `target` is a NAME from code — never a value.
|
|
189
|
+
*
|
|
190
|
+
* ```typescript
|
|
191
|
+
* const quote = await scope.$call('stripe.quotes.create', (t) => stripe.quotes.create(body, { signal: t.signal }),
|
|
192
|
+
* { attempts: 3, timeoutMs: 10_000, backoffMs: (n) => 500 * n });
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* A call that CHANGES an outside system declares it (P3): `options.touches` names the system and
|
|
196
|
+
* `options.idempotencyKey` the key every attempt is made under (`t.idempotencyKey`) — a value from the stage's
|
|
197
|
+
* input or state, never from model output. A touching call that may retry without a key is refused here,
|
|
198
|
+
* before anything is sent; each record says what its attempt did (`effect`), and a call that ends without an answer after any attempt left the
|
|
199
|
+
* effect unknown rejects with `UnknownEffectError` — reconcile by the key, do not retry blindly.
|
|
200
|
+
*/
|
|
201
|
+
call<T>(target: string, fn: (attempt: AttemptContext) => Promise<T> | T, policy?: RetryPolicy, options?: CallOptions): Promise<T>;
|
|
202
|
+
/** `runCall` with this stage attempt as its host (`call`). */
|
|
203
|
+
private startCall;
|
|
204
|
+
/** @internal The explicit retry helper owns this state; the normal write path still owns retention/commit. */
|
|
205
|
+
writeRetryLoopState(key: string, state: {
|
|
206
|
+
readonly idempotencyKey: string;
|
|
207
|
+
}): void;
|
|
208
|
+
/** @internal Exactly the existing P3 key-retention law; operational state keeps the real key. */
|
|
209
|
+
serveRetryLoopKey(key: string): string;
|
|
210
|
+
/** @internal Loop state is durable data: never persist the thrown value, stack, cause or payload. */
|
|
211
|
+
serveRetryLoopError(error: unknown): AttemptError;
|
|
212
|
+
/** A touching call's target, its key served for the records (`RedactionRule · retainIdempotencyKey`: by name and by its sources). */
|
|
213
|
+
private callEffect;
|
|
214
|
+
/**
|
|
215
|
+
* A `$call` from an ended attempt, or from a frame that has committed: recorded by name (`lateWrites`, channel
|
|
216
|
+
* `'attempt'`) and refused — before anything reaches outside. The P1b fence first, so its message and record are
|
|
217
|
+
* the same.
|
|
218
|
+
*/
|
|
219
|
+
private refuseLateCall;
|
|
220
|
+
/**
|
|
221
|
+
* An outside attempt an adapter reported — `AttemptContext.observed` on this stage's attempt or on one of its
|
|
222
|
+
* calls' (P2). Read and validated first (a malformed report is the adapter's bug: a `TypeError`, and it never
|
|
223
|
+
* reaches the record). A report that comes after its attempt ended — the call attempt it was made through, this
|
|
224
|
+
* stage attempt, or the frame's commit — is recorded by name (`lateWrites`, channel `'attempt'`) and DROPPED,
|
|
225
|
+
* never thrown: adapters report from an SDK's own callbacks, which may fire after the stage moved on, and an
|
|
226
|
+
* observed attempt never changes control flow — in either direction. Its series opens at this stage attempt's call
|
|
227
|
+
* level: an SDK's call is a call the stage attempt made, so a report made through a `$call` is that call's sibling.
|
|
228
|
+
*/
|
|
229
|
+
private recordObserved;
|
|
230
|
+
/** This facade's attempt has ended — the P1b fence is closed. */
|
|
231
|
+
private attemptHasEnded;
|
|
122
232
|
/** Called by StageContext.commit() observer. Converts tracked writes to CommitEvent format.
|
|
123
233
|
* Errors are caught to prevent recorder issues from aborting the traversal. */
|
|
124
234
|
private _onCommitFired;
|
|
@@ -147,9 +257,9 @@ export declare class ScopeFacade {
|
|
|
147
257
|
*/
|
|
148
258
|
emitEvent(name: string, payload: unknown): void;
|
|
149
259
|
/** See `ScopeMethods.$detachAndJoinLater`. */
|
|
150
|
-
detachAndJoinLater(driver:
|
|
260
|
+
detachAndJoinLater(driver: DetachDriver, child: FlowChart, input?: unknown): DetachHandle;
|
|
151
261
|
/** See `ScopeMethods.$detachAndForget`. */
|
|
152
|
-
detachAndForget(driver:
|
|
262
|
+
detachAndForget(driver: DetachDriver, child: FlowChart, input?: unknown): void;
|
|
153
263
|
/**
|
|
154
264
|
* Build the subflowPath (outer → inner) for event enrichment.
|
|
155
265
|
*
|
|
@@ -251,8 +361,10 @@ export declare class ScopeFacade {
|
|
|
251
361
|
* Returns the execution environment — read-only infrastructure values
|
|
252
362
|
* that propagate through nested executors (like `process.env` for flowcharts).
|
|
253
363
|
*
|
|
254
|
-
* Contains: signal (abort), timeoutMs, traceId
|
|
255
|
-
*
|
|
364
|
+
* Contains: signal (abort — the run's one effective signal), timeoutMs, traceId, operationId, traceparent,
|
|
365
|
+
* deadline (epoch ms) — the run's env as admitted (`attempt/correlation.ts · admitRunEnv`: one own-field
|
|
366
|
+
* snapshot; `traceparent` is the canonical header the run's correlation carries, never the received bytes), then
|
|
367
|
+
* armed (`runner/deadline.ts · armRun`). Frozen at construction time. Inherited by subflows automatically.
|
|
256
368
|
*
|
|
257
369
|
* ```typescript
|
|
258
370
|
* const { signal, traceId } = scope.getEnv();
|
|
@@ -266,6 +378,8 @@ export declare class ScopeFacade {
|
|
|
266
378
|
/** @internal */
|
|
267
379
|
getPipelineId(): string;
|
|
268
380
|
private _invokeHook;
|
|
381
|
+
/** The event as fired: unchanged without a correlation, else with the run's correlation as its last key. */
|
|
382
|
+
private _correlated;
|
|
269
383
|
/**
|
|
270
384
|
* The scope channel's isolation: a recorder's throw becomes an `onError` on every recorder
|
|
271
385
|
* (stamped with this stage), and a throw from `onError` itself is dropped.
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DebugRecorder — Development-focused recorder for detailed debugging
|
|
3
3
|
*
|
|
4
|
-
* Captures errors (always
|
|
5
|
-
*
|
|
4
|
+
* Captures errors (always — a scope recorder's own failure, the scope
|
|
5
|
+
* channel's `onError`; a stage's failure is not one), mutations and reads
|
|
6
|
+
* (in verbose mode), and stage lifecycle events for troubleshooting.
|
|
7
|
+
*
|
|
8
|
+
* Attempts (10.1): one `attempt` row per attempt of a series that retried,
|
|
9
|
+
* gave up or timed out (`recorder/attemptSeries.ts · isRetryEvidence`) — its
|
|
10
|
+
* outcome, category, duration, decision, the cap and time left it ran under
|
|
11
|
+
* (present with a cap or a deadline) and served error — and one `attemptStop`
|
|
12
|
+
* row when the series gave up (exhausted, declined, no time left). Both verbosities: like a
|
|
13
|
+
* pause, an attempt is significant — and for a retried stage these rows are
|
|
14
|
+
* the failure evidence (a stage's error is never an `error` row). They arrive on the FLOW channel
|
|
15
|
+
* (`onAttempt`), so attach with `attachCombinedRecorder` to see them; the
|
|
16
|
+
* flow channel's own `onError` / `onPause` / `onResume` are ignored, so a
|
|
17
|
+
* combined attach never doubles a scope row.
|
|
6
18
|
*/
|
|
19
|
+
import type { FlowAttemptEvent } from '../../engine/narrative/types.js';
|
|
7
20
|
import type { RecorderOperation } from '../../recorder/RecorderOperation.js';
|
|
8
21
|
import type { ErrorEvent, PauseEvent, ReadEvent, ResumeEvent, ScopeRecorder, StageEvent, WriteEvent } from '../types.js';
|
|
9
22
|
export type DebugVerbosity = 'minimal' | 'verbose';
|
|
10
23
|
export interface DebugEntry {
|
|
11
|
-
type: 'read' | 'write' | 'error' | 'stageStart' | 'stageEnd' | 'pause' | 'resume';
|
|
24
|
+
type: 'read' | 'write' | 'error' | 'stageStart' | 'stageEnd' | 'pause' | 'resume' | 'attempt' | 'attemptStop';
|
|
12
25
|
stageName: string;
|
|
13
26
|
timestamp: number;
|
|
14
27
|
data: unknown;
|
|
@@ -48,6 +61,7 @@ export declare class DebugRecorder implements ScopeRecorder {
|
|
|
48
61
|
onStageEnd(event: StageEvent): void;
|
|
49
62
|
onPause(event: PauseEvent): void;
|
|
50
63
|
onResume(event: ResumeEvent): void;
|
|
64
|
+
onAttempt(event: FlowAttemptEvent): void;
|
|
51
65
|
getEntries(): DebugEntry[];
|
|
52
66
|
getErrors(): DebugEntry[];
|
|
53
67
|
getEntriesForStage(stageName: string): DebugEntry[];
|
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
* (Convention 1 — one purpose per recorder: this is the ScopeRecorder; the store
|
|
7
7
|
* is the storage).
|
|
8
8
|
*
|
|
9
|
+
* Attempts (10.1): a stage with a retry policy runs each attempt in a fresh
|
|
10
|
+
* scope, so this recorder sees one `onStageStart` per attempt. `attempts` is
|
|
11
|
+
* that count, present when it is 2 or more; `duration` spans the whole
|
|
12
|
+
* execution — from the FIRST attempt's start, waits included — never just the
|
|
13
|
+
* attempt that succeeded. An execution that never returned (it gave up) has
|
|
14
|
+
* no `onStageEnd`, so its duration stays `0`, as for any failed stage. A stage
|
|
15
|
+
* that ran once reads exactly as before.
|
|
16
|
+
*
|
|
9
17
|
* @example
|
|
10
18
|
* ```typescript
|
|
11
19
|
* const metric = new MetricRecorder();
|
|
@@ -38,6 +46,8 @@ export interface StepMetrics {
|
|
|
38
46
|
pauseCount: number;
|
|
39
47
|
/** Duration in ms for this invocation. */
|
|
40
48
|
duration: number;
|
|
49
|
+
/** How many attempts the execution made (its `onStageStart` count) — present only when it retried (≥ 2). */
|
|
50
|
+
attempts?: number;
|
|
41
51
|
}
|
|
42
52
|
/** Aggregated metrics across all invocations (backward compatible). */
|
|
43
53
|
export interface AggregatedMetrics {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* ScopeFacade owns recording, redaction and state access; custom scopes may
|
|
8
8
|
* explicitly supply a smaller port (including `{}` for data-only scopes).
|
|
9
9
|
*/
|
|
10
|
+
import type { RunCorrelation } from '../attempt/types.js';
|
|
10
11
|
import type { RedactionPolicy, ScopeRecorder } from './types.js';
|
|
11
12
|
/** Engine-facing capabilities. Never use a strict user-field proxy as this port. */
|
|
12
13
|
export interface ScopeRuntimeTarget {
|
|
@@ -15,6 +16,8 @@ export interface ScopeRuntimeTarget {
|
|
|
15
16
|
getScopeRecorders?(): ScopeRecorder[];
|
|
16
17
|
useSharedRedactedKeys?(keys: Set<string>): void;
|
|
17
18
|
useRedactionPolicy?(policy: RedactionPolicy): void;
|
|
19
|
+
/** The run's correlation, stamped on every scope and emit event this scope fires (10.1). */
|
|
20
|
+
useCorrelation?(correlation: RunCorrelation | undefined): void;
|
|
18
21
|
getRedactedKeys?(): Set<string>;
|
|
19
22
|
notifyStageStart?(): void;
|
|
20
23
|
notifyStageEnd?(duration?: number): void;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Architecture follows composition-over-inheritance: Recorders are
|
|
6
6
|
* attached to Scope instances to observe read/write/commit operations.
|
|
7
7
|
*/
|
|
8
|
+
import type { RunCorrelation } from '../attempt/types.js';
|
|
8
9
|
import type { StructuredErrorInfo } from '../errors/errorInfo.js';
|
|
9
10
|
export interface RecorderContext {
|
|
10
11
|
stageName: string;
|
|
@@ -14,6 +15,11 @@ export interface RecorderContext {
|
|
|
14
15
|
runtimeStageId: string;
|
|
15
16
|
pipelineId: string;
|
|
16
17
|
timestamp: number;
|
|
18
|
+
/**
|
|
19
|
+
* The run's correlation (10.1) — the same frozen object as `TraversalContext.correlation` on the flow events
|
|
20
|
+
* and `getSnapshot().correlation`. Absent — no key — when the run's env gave none.
|
|
21
|
+
*/
|
|
22
|
+
readonly correlation?: RunCorrelation;
|
|
17
23
|
}
|
|
18
24
|
export interface ReadEvent extends RecorderContext {
|
|
19
25
|
key?: string;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sinks/fileSink.ts — the record, one JSON line per entry, in a file (design §3.5, §4, packet P6). NODE ONLY: the
|
|
3
|
+
* one file in `src/` that imports a Node built-in, reachable only through the `footprintjs/sinks` door.
|
|
4
|
+
*
|
|
5
|
+
* WHY A FILE, WHY THIS SHAPE. A run's record must outlive the process that made it — a killed process, a crashed
|
|
6
|
+
* host, a serverless freeze. Each entry the log hands over is encoded, checked and given its own offset in the file,
|
|
7
|
+
* and its write is handed to the I/O pool AT ONCE (a positional write — no entry waits for the event loop to turn);
|
|
8
|
+
* the pool's threads perform them while the main thread runs on. A process killed after a pool thread wrote an entry
|
|
9
|
+
* keeps it. Until then it is not on disk: microseconds on a free pool, but the pool (4 threads by default) is shared
|
|
10
|
+
* with DNS lookups, zlib, crypto and other fs work, so while it is busy the window is as long as that work — and since
|
|
11
|
+
* writes complete out of order, a kill can lose an entry in the middle (the reader reports the hole). `flush()` waits for every write and
|
|
12
|
+
* `fsync`s — the step that also survives the machine losing power, and the one the executor awaits after each run's
|
|
13
|
+
* closing entry.
|
|
14
|
+
*
|
|
15
|
+
* THE THREAT MODEL, as code — every resource bounded, nothing that can stall the run:
|
|
16
|
+
* - ONLY THE PATH THE APP GIVES. Resolved once and opened once, at `fileSink(path)`; every entry goes to that open
|
|
17
|
+
* file. A symbolic link at the path is refused (`O_NOFOLLOW`, where the platform has it), and so is anything
|
|
18
|
+
* that is not a regular file, a file with another hard link, another owner, or group/world write. A file the
|
|
19
|
+
* sink creates is `0o600`.
|
|
20
|
+
* - ATOMIC PER ENTRY. A line is encoded in full first — an entry JSON cannot write (a `BigInt`, a cycle) is
|
|
21
|
+
* refused whole — then written at its own offset. A write that fails part-way leaves a hole up to the next
|
|
22
|
+
* entry's offset; the reader splits at it (NUL), so a torn line never swallows the one after it (an existing
|
|
23
|
+
* file with a torn tail gets a newline first).
|
|
24
|
+
* - BOUNDED: `maxEntryBytes` (one line, 8 MiB — refused by name, before it is encoded when its length already
|
|
25
|
+
* says so), `maxQueuedBytes` (accepted, not yet written, 16 MiB — past it an entry is DROPPED and counted, never
|
|
26
|
+
* buffered without limit), `maxBytes` (the file, 64 MiB — once full, every further entry is refused and counted;
|
|
27
|
+
* a closing entry may use a 64 KiB reserve so a full file can still say how the run ended), `flushTimeoutMs`
|
|
28
|
+
* (10 s — then `flush()` rejects). Every refusal throws from the sink method, which the log counts
|
|
29
|
+
* (`getSnapshot().sink`); a write that fails later rejects that entry's promise, counted the same way.
|
|
30
|
+
* - ASYNCHRONOUS WRITES ONLY. No method blocks on the disk; the file is released asynchronously, after every
|
|
31
|
+
* write and every started fsync.
|
|
32
|
+
* - NO SECRET ON DISK is the EXECUTOR's law, applied before any entry reaches an adapter (`runner/recordSink.ts`):
|
|
33
|
+
* this file writes what it is handed and reads nothing else.
|
|
34
|
+
* - ONE WRITER PER FILE. A second sink on a file this process has open is refused (by device and inode, across the
|
|
35
|
+
* CommonJS and ESM builds). ANOTHER PROCESS writing the same path is not seen at open: each writes at its own
|
|
36
|
+
* offsets and would overwrite the other. `flush()` checks the file's size against what this sink placed and rejects
|
|
37
|
+
* (a loss the run counts) when another writer's bytes reach past it — best effort: an overwrite this sink's own
|
|
38
|
+
* later writes cover is not seen. Give each process its own file.
|
|
39
|
+
*
|
|
40
|
+
* WHAT JSON KEEPS. A line holds what `JSON.stringify` keeps: a `Date` becomes its ISO string, a `Map` / `Set` an
|
|
41
|
+
* empty object, `undefined` disappears. A record of plain JSON values reads back exactly (`readRecordFile` →
|
|
42
|
+
* `readStoredRecord`); for richer values, bring an adapter with a richer encoding.
|
|
43
|
+
*/
|
|
44
|
+
import type { RecordSink } from 'foottrace/write';
|
|
45
|
+
/** The default cap on a record file: 64 MiB. */
|
|
46
|
+
export declare const DEFAULT_FILE_SINK_MAX_BYTES: number;
|
|
47
|
+
/** The default cap on ONE entry's line: 8 MiB. */
|
|
48
|
+
export declare const DEFAULT_FILE_SINK_MAX_ENTRY_BYTES: number;
|
|
49
|
+
/** The default cap on bytes accepted but not yet written: 16 MiB. */
|
|
50
|
+
export declare const DEFAULT_FILE_SINK_MAX_QUEUED_BYTES: number;
|
|
51
|
+
/** The default bound on `flush()`: 10 s. */
|
|
52
|
+
export declare const DEFAULT_FILE_SINK_FLUSH_TIMEOUT_MS = 10000;
|
|
53
|
+
/** `fileSink`'s options — every resource the sink can spend, bounded. */
|
|
54
|
+
export interface FileSinkOptions {
|
|
55
|
+
/**
|
|
56
|
+
* The most bytes the file may hold (the bytes already in it count). Once an entry would pass it, the file is FULL:
|
|
57
|
+
* that entry and every later one is refused and counted by the run, never written — except a closing entry, which
|
|
58
|
+
* may use 64 KiB more so a full file can still say how the run ended. Default 64 MiB.
|
|
59
|
+
*/
|
|
60
|
+
readonly maxBytes?: number;
|
|
61
|
+
/** The largest ONE entry's line may be; a larger entry is refused whole (`maxEntryBytes` named). Default 8 MiB. */
|
|
62
|
+
readonly maxEntryBytes?: number;
|
|
63
|
+
/**
|
|
64
|
+
* The most bytes accepted and not yet on disk. Writes are asynchronous, so a sink slower than the run queues; past
|
|
65
|
+
* this bound an entry is DROPPED and counted (never buffered without limit, never a stall). Default 16 MiB.
|
|
66
|
+
*/
|
|
67
|
+
readonly maxQueuedBytes?: number;
|
|
68
|
+
/** How long `flush()` (drain the queue, then `fsync`) may take before it rejects. Default 10 s. */
|
|
69
|
+
readonly flushTimeoutMs?: number;
|
|
70
|
+
}
|
|
71
|
+
/** A record sink that appends to one file — `RecordSink` plus what the app needs to manage the file. */
|
|
72
|
+
export interface FileSink extends RecordSink {
|
|
73
|
+
/** The absolute path the sink writes to — resolved once, when it was made. */
|
|
74
|
+
readonly path: string;
|
|
75
|
+
/**
|
|
76
|
+
* Bytes this sink knows are on disk: the file's size when it opened plus every byte its writes completed — a
|
|
77
|
+
* running sum, not the file's end (writes complete out of order; a failed one leaves a hole).
|
|
78
|
+
*/
|
|
79
|
+
readonly bytes: number;
|
|
80
|
+
/** Bytes accepted and not yet written. */
|
|
81
|
+
readonly queuedBytes: number;
|
|
82
|
+
/** `true` once an entry was refused for `maxBytes`: the file is full, and only a closing entry may still go. */
|
|
83
|
+
readonly full: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Release the file. Idempotent. Every entry after it is refused (the run counts it), and `flush()` rejects;
|
|
86
|
+
* entries already accepted are still written (and a flush already started finishes), then the file is closed —
|
|
87
|
+
* the promise settles then.
|
|
88
|
+
*/
|
|
89
|
+
close(): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A record sink that appends each entry to `path` as one JSON line — the crash-safe record on a Node host.
|
|
93
|
+
*
|
|
94
|
+
* Every method returns at once: the line is encoded, checked against every bound, given its offset and handed to
|
|
95
|
+
* the I/O pool. The method's promise settles when that line is written; a write that fails rejects it, and the run
|
|
96
|
+
* counts the loss.
|
|
97
|
+
*
|
|
98
|
+
* @throws TypeError when `path` is not a non-empty string or does not name a regular file the writer owns alone;
|
|
99
|
+
* RangeError for a bound that is not a whole number ≥ 1; the operating system's error when
|
|
100
|
+
* the file cannot be opened (a symbolic link at `path` included). Made once, at setup — never during a run.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* import { fileSink, readRecordFile } from 'footprintjs/sinks';
|
|
105
|
+
* import { readStoredRecord } from 'foottrace';
|
|
106
|
+
*
|
|
107
|
+
* const sink = fileSink('/var/footprint/orders.jsonl');
|
|
108
|
+
* const executor = new FlowChartExecutor(chart, { sink });
|
|
109
|
+
* await executor.run({ input });
|
|
110
|
+
* // …later, or after a crash:
|
|
111
|
+
* const record = readStoredRecord(readRecordFile('/var/footprint/orders.jsonl').entries);
|
|
112
|
+
* record.root(runId)?.complete; // false for a run that never ended
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export declare function fileSink(path: string, options?: FileSinkOptions): FileSink;
|
|
116
|
+
/** A record file read back: every parsed line, and every line that could not be. */
|
|
117
|
+
export interface RecordFile {
|
|
118
|
+
/** The parsed entries, in file order — untrusted input for `readStoredRecord` (`foottrace`). */
|
|
119
|
+
readonly entries: readonly unknown[];
|
|
120
|
+
/** Each line that is not JSON (a torn last line, a corrupt one), by its 1-based number. Blank lines are skipped. */
|
|
121
|
+
readonly unreadable: readonly {
|
|
122
|
+
readonly line: number;
|
|
123
|
+
readonly reason: string;
|
|
124
|
+
}[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Read a record file back, line by line — the entries for `readStoredRecord`, and every line that could not be
|
|
128
|
+
* read, by number, never a failed read. A stored key named `__proto__` stays data (`JSON.parse` makes it an own
|
|
129
|
+
* property). The file is untrusted: a file larger than `maxBytes` (default 256 MiB) is refused before it is read.
|
|
130
|
+
*
|
|
131
|
+
* @throws RangeError when the file is larger than `maxBytes`; the operating system's error when it cannot be read.
|
|
132
|
+
*/
|
|
133
|
+
export declare function readRecordFile(path: string, options?: {
|
|
134
|
+
readonly maxBytes?: number;
|
|
135
|
+
}): RecordFile;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import type { CombinedNarrativeRecorderOptions } from './lib/engine/narrative/CombinedNarrativeRecorder.js';
|
|
27
27
|
import { CombinedNarrativeRecorder } from './lib/engine/narrative/CombinedNarrativeRecorder.js';
|
|
28
|
-
import type { BreakRenderContext, DecisionRenderContext, EmitRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, NarrativeFormatter, OpRenderContext, SelectedRenderContext, StageRenderContext, SubflowRenderContext } from './lib/engine/narrative/narrativeTypes.js';
|
|
28
|
+
import type { AttemptRenderContext, BreakRenderContext, DecisionRenderContext, EmitRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, NarrativeFormatter, OpRenderContext, SelectedRenderContext, StageRenderContext, SubflowRenderContext } from './lib/engine/narrative/narrativeTypes.js';
|
|
29
29
|
import { AdaptiveNarrativeFlowRecorder } from './lib/engine/narrative/recorders/AdaptiveNarrativeFlowRecorder.js';
|
|
30
30
|
import type { ManifestEntry } from './lib/engine/narrative/recorders/ManifestFlowRecorder.js';
|
|
31
31
|
import { ManifestFlowRecorder } from './lib/engine/narrative/recorders/ManifestFlowRecorder.js';
|
|
@@ -66,7 +66,13 @@ export declare function manifest(): ManifestInstance;
|
|
|
66
66
|
export declare function adaptive(): AdaptiveNarrativeFlowRecorder;
|
|
67
67
|
export declare function milestone(): MilestoneNarrativeFlowRecorder;
|
|
68
68
|
export declare function windowed(maxEntries?: number): WindowedNarrativeFlowRecorder;
|
|
69
|
-
export type { BreakRenderContext, CombinedNarrativeRecorderOptions, DecisionRenderContext, EmitEvent, EmitRecorder, EmitRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, NarrativeFormatter, OpRenderContext, SelectedRenderContext, StageRenderContext, SubflowRenderContext, };
|
|
69
|
+
export type { AttemptRenderContext, BreakRenderContext, CombinedNarrativeRecorderOptions, DecisionRenderContext, EmitEvent, EmitRecorder, EmitRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, NarrativeFormatter, OpRenderContext, SelectedRenderContext, StageRenderContext, SubflowRenderContext, };
|
|
70
70
|
export type { AggregatedMetrics, MetricRecorderOptions, StageMetrics };
|
|
71
|
+
export type { AttemptAggregate, AttemptDecisionRow, AttemptMetricRef, AttemptQuery, AttemptRecorderOptions, AttemptRow, AttemptRunRow, AttemptRunStats, AttemptStats, AttemptStorageStats, AttemptStore, PhysicalAttemptRow, } from './lib/recorder/attemptMetricsTypes.js';
|
|
72
|
+
export { memoryStore } from './lib/recorder/AttemptRecorder.js';
|
|
71
73
|
export type { CompositeSnapshot } from './lib/recorder/index.js';
|
|
72
74
|
export { CompositeRecorder } from './lib/recorder/index.js';
|
|
75
|
+
import type { AttemptRecorderOptions } from './lib/recorder/attemptMetricsTypes.js';
|
|
76
|
+
import { AttemptRecorder } from './lib/recorder/AttemptRecorder.js';
|
|
77
|
+
/** Collect payload-free attempts during traversal; storage adapters are optional and provider-neutral. */
|
|
78
|
+
export declare function attempts(options?: AttemptRecorderOptions): AttemptRecorder;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* footprintjs/sinks — where a run's crash-safe record goes on a Node host (10.1, design §3.5).
|
|
3
|
+
*
|
|
4
|
+
* NODE ONLY. This door imports `node:fs`; it is the one door that does (`test/architecture/layering.test.ts`), so
|
|
5
|
+
* every other door stays loadable in a browser. The port itself — `RecordSink`, and the reference `memorySink()` —
|
|
6
|
+
* is foottrace's (`foottrace/write`); the reader is `readStoredRecord` (`foottrace`).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { flowChart, FlowChartExecutor } from 'footprintjs';
|
|
11
|
+
* import { fileSink, readRecordFile } from 'footprintjs/sinks';
|
|
12
|
+
* import { readStoredRecord } from 'foottrace';
|
|
13
|
+
*
|
|
14
|
+
* const executor = new FlowChartExecutor(chart, { sink: fileSink('/var/footprint/orders.jsonl') });
|
|
15
|
+
* await executor.run({ input });
|
|
16
|
+
*
|
|
17
|
+
* // After a crash — in another process:
|
|
18
|
+
* const record = readStoredRecord(readRecordFile('/var/footprint/orders.jsonl').entries);
|
|
19
|
+
* for (const log of record.logs.values()) if (!log.complete) console.log('never finished:', log.address);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export type { FileSink, FileSinkOptions, RecordFile } from './lib/sinks/fileSink.js';
|
|
23
|
+
export { DEFAULT_FILE_SINK_FLUSH_TIMEOUT_MS, DEFAULT_FILE_SINK_MAX_BYTES, DEFAULT_FILE_SINK_MAX_ENTRY_BYTES, DEFAULT_FILE_SINK_MAX_QUEUED_BYTES, fileSink, readRecordFile, } from './lib/sinks/fileSink.js';
|
package/dist/types/trace.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { BRANCH_SEGMENT_MARKER, buildBranchSegment, hasBranchSegmentMarker, isBr
|
|
|
11
11
|
export { BoundaryStateStore } from './lib/recorder/BoundaryStateStore.js';
|
|
12
12
|
export type { ControlDecisionRecord, ControlDepRecorderOptions } from './lib/recorder/ControlDepRecorder.js';
|
|
13
13
|
export { ControlDepRecorder, controlDepRecorder } from './lib/recorder/ControlDepRecorder.js';
|
|
14
|
-
export type { InOutEntry, InOutPhase, InOutRecorderOptions } from './lib/recorder/InOutRecorder.js';
|
|
14
|
+
export type { InOutAttempts, InOutEntry, InOutPhase, InOutRecorderOptions } from './lib/recorder/InOutRecorder.js';
|
|
15
15
|
export { InOutRecorder, inOutRecorder, ROOT_RUNTIME_STAGE_ID, ROOT_SUBFLOW_ID } from './lib/recorder/InOutRecorder.js';
|
|
16
16
|
export { KeyedStore } from './lib/recorder/KeyedStore.js';
|
|
17
17
|
export type { QualityEntry, QualityRecorderOptions, QualityScoringFn } from './lib/recorder/QualityRecorder.js';
|
|
@@ -19,5 +19,5 @@ export { QualityRecorder } from './lib/recorder/QualityRecorder.js';
|
|
|
19
19
|
export type { QualityFrame, QualityStackTrace } from './lib/recorder/qualityTrace.js';
|
|
20
20
|
export { formatQualityTrace, qualityTrace } from './lib/recorder/qualityTrace.js';
|
|
21
21
|
export { SequenceStore } from './lib/recorder/SequenceStore.js';
|
|
22
|
-
export type { Topology, TopologyEdge, TopologyIncomingKind, TopologyNode, TopologyRecorderOptions, } from './lib/recorder/TopologyRecorder.js';
|
|
22
|
+
export type { Topology, TopologyEdge, TopologyIncomingKind, TopologyNode, TopologyNodeKind, TopologyRecorderOptions, } from './lib/recorder/TopologyRecorder.js';
|
|
23
23
|
export { TopologyRecorder, topologyRecorder } from './lib/recorder/TopologyRecorder.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "footprintjs",
|
|
3
|
-
"version": "10.0
|
|
3
|
+
"version": "10.2.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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"node": ">=22"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
|
-
"clean": "rm -rf build/* coverage dist node_modules
|
|
41
|
+
"clean": "rm -rf build/* coverage dist node_modules",
|
|
42
42
|
"build": "rm -rf dist && tsc && tsc -p tsconfig.esm.json && node scripts/postbuild-esm.mjs",
|
|
43
43
|
"prepare": "husky",
|
|
44
44
|
"watch": "tsc -w",
|
|
@@ -137,6 +137,16 @@
|
|
|
137
137
|
"default": "./dist/detach.js"
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
|
+
"./sinks": {
|
|
141
|
+
"import": {
|
|
142
|
+
"types": "./dist/esm/sinks.d.ts",
|
|
143
|
+
"default": "./dist/esm/sinks.js"
|
|
144
|
+
},
|
|
145
|
+
"require": {
|
|
146
|
+
"types": "./dist/types/sinks.d.ts",
|
|
147
|
+
"default": "./dist/sinks.js"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
140
150
|
"./zod": {
|
|
141
151
|
"import": {
|
|
142
152
|
"types": "./dist/esm/zod.d.ts",
|
|
@@ -163,6 +173,9 @@
|
|
|
163
173
|
"detach": [
|
|
164
174
|
"./dist/types/detach.d.ts"
|
|
165
175
|
],
|
|
176
|
+
"sinks": [
|
|
177
|
+
"./dist/types/sinks.d.ts"
|
|
178
|
+
],
|
|
166
179
|
"zod": [
|
|
167
180
|
"./dist/types/zod.d.ts"
|
|
168
181
|
]
|
|
@@ -176,7 +189,7 @@
|
|
|
176
189
|
},
|
|
177
190
|
"sideEffects": false,
|
|
178
191
|
"dependencies": {
|
|
179
|
-
"foottrace": "^1.
|
|
192
|
+
"foottrace": "^1.3.0"
|
|
180
193
|
},
|
|
181
194
|
"peerDependencies": {
|
|
182
195
|
"zod": "^3.0.0 || ^4.0.0"
|
|
@@ -188,12 +201,12 @@
|
|
|
188
201
|
},
|
|
189
202
|
"devDependencies": {
|
|
190
203
|
"@arethetypeswrong/cli": "^0.18.1",
|
|
191
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
192
|
-
"@typescript-eslint/parser": "^
|
|
204
|
+
"@typescript-eslint/eslint-plugin": "^8.71.2",
|
|
205
|
+
"@typescript-eslint/parser": "^8.71.2",
|
|
193
206
|
"@vitest/coverage-v8": "^4.1.8",
|
|
194
207
|
"concurrently": "^8.0.1",
|
|
195
208
|
"esbuild": "^0.28.0",
|
|
196
|
-
"eslint": "^8.
|
|
209
|
+
"eslint": "^8.57.1",
|
|
197
210
|
"eslint-config-prettier": "^6.15.0",
|
|
198
211
|
"eslint-config-standard": "^17.0.0",
|
|
199
212
|
"eslint-import-resolver-typescript": "^3.5.2",
|
|
@@ -210,6 +223,7 @@
|
|
|
210
223
|
"prettier": "^2.8.1",
|
|
211
224
|
"publint": "^0.3.0",
|
|
212
225
|
"semver": "^7.8.5",
|
|
226
|
+
"tsx": "^4.23.15",
|
|
213
227
|
"typedoc": "^0.28.17",
|
|
214
228
|
"typescript": "~5.4.5",
|
|
215
229
|
"vitest": "^4.0.18",
|