groundswell 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/adversarial/attachChild-performance.test.d.ts +16 -0
- package/dist/__tests__/adversarial/attachChild-performance.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/attachChild-performance.test.js +187 -0
- package/dist/__tests__/adversarial/attachChild-performance.test.js.map +1 -0
- package/dist/__tests__/adversarial/circular-reference.test.d.ts +13 -0
- package/dist/__tests__/adversarial/circular-reference.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/circular-reference.test.js +92 -0
- package/dist/__tests__/adversarial/circular-reference.test.js.map +1 -0
- package/dist/__tests__/adversarial/complex-circular-reference.test.d.ts +16 -0
- package/dist/__tests__/adversarial/complex-circular-reference.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/complex-circular-reference.test.js +127 -0
- package/dist/__tests__/adversarial/complex-circular-reference.test.js.map +1 -0
- package/dist/__tests__/adversarial/concurrent-task-failures.test.d.ts +21 -0
- package/dist/__tests__/adversarial/concurrent-task-failures.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/concurrent-task-failures.test.js +667 -0
- package/dist/__tests__/adversarial/concurrent-task-failures.test.js.map +1 -0
- package/dist/__tests__/adversarial/deep-analysis.test.d.ts +6 -0
- package/dist/__tests__/adversarial/deep-analysis.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/deep-analysis.test.js +877 -0
- package/dist/__tests__/adversarial/deep-analysis.test.js.map +1 -0
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.d.ts +13 -0
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.js +186 -0
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.js.map +1 -0
- package/dist/__tests__/adversarial/e2e-prd-validation.test.d.ts +6 -0
- package/dist/__tests__/adversarial/e2e-prd-validation.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/e2e-prd-validation.test.js +626 -0
- package/dist/__tests__/adversarial/e2e-prd-validation.test.js.map +1 -0
- package/dist/__tests__/adversarial/edge-case.test.d.ts +6 -0
- package/dist/__tests__/adversarial/edge-case.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/edge-case.test.js +857 -0
- package/dist/__tests__/adversarial/edge-case.test.js.map +1 -0
- package/dist/__tests__/adversarial/error-merge-strategy.test.d.ts +20 -0
- package/dist/__tests__/adversarial/error-merge-strategy.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/error-merge-strategy.test.js +907 -0
- package/dist/__tests__/adversarial/error-merge-strategy.test.js.map +1 -0
- package/dist/__tests__/adversarial/incremental-performance.test.d.ts +2 -0
- package/dist/__tests__/adversarial/incremental-performance.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/incremental-performance.test.js +113 -0
- package/dist/__tests__/adversarial/incremental-performance.test.js.map +1 -0
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.d.ts +22 -0
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.js +383 -0
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.js.map +1 -0
- package/dist/__tests__/adversarial/observer-propagation.test.d.ts +21 -0
- package/dist/__tests__/adversarial/observer-propagation.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/observer-propagation.test.js +404 -0
- package/dist/__tests__/adversarial/observer-propagation.test.js.map +1 -0
- package/dist/__tests__/adversarial/parent-validation.test.d.ts +13 -0
- package/dist/__tests__/adversarial/parent-validation.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/parent-validation.test.js +128 -0
- package/dist/__tests__/adversarial/parent-validation.test.js.map +1 -0
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.d.ts +20 -0
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.js +482 -0
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.js.map +1 -0
- package/dist/__tests__/adversarial/prd-compliance.test.d.ts +6 -0
- package/dist/__tests__/adversarial/prd-compliance.test.d.ts.map +1 -0
- package/dist/__tests__/adversarial/prd-compliance.test.js +886 -0
- package/dist/__tests__/adversarial/prd-compliance.test.js.map +1 -0
- package/dist/__tests__/compatibility/backward-compatibility.test.d.ts +22 -0
- package/dist/__tests__/compatibility/backward-compatibility.test.d.ts.map +1 -0
- package/dist/__tests__/compatibility/backward-compatibility.test.js +1843 -0
- package/dist/__tests__/compatibility/backward-compatibility.test.js.map +1 -0
- package/dist/__tests__/helpers/index.d.ts +10 -0
- package/dist/__tests__/helpers/index.d.ts.map +1 -0
- package/{src/__tests__/helpers/index.ts → dist/__tests__/helpers/index.js} +2 -10
- package/dist/__tests__/helpers/index.js.map +1 -0
- package/dist/__tests__/helpers/tree-verification.d.ts +90 -0
- package/dist/__tests__/helpers/tree-verification.d.ts.map +1 -0
- package/dist/__tests__/helpers/tree-verification.js +202 -0
- package/dist/__tests__/helpers/tree-verification.js.map +1 -0
- package/dist/__tests__/integration/agent-workflow.test.d.ts +2 -0
- package/dist/__tests__/integration/agent-workflow.test.d.ts.map +1 -0
- package/dist/__tests__/integration/agent-workflow.test.js +256 -0
- package/dist/__tests__/integration/agent-workflow.test.js.map +1 -0
- package/dist/__tests__/integration/bidirectional-consistency.test.d.ts +14 -0
- package/dist/__tests__/integration/bidirectional-consistency.test.d.ts.map +1 -0
- package/dist/__tests__/integration/bidirectional-consistency.test.js +668 -0
- package/dist/__tests__/integration/bidirectional-consistency.test.js.map +1 -0
- package/dist/__tests__/integration/observer-logging.test.d.ts +2 -0
- package/dist/__tests__/integration/observer-logging.test.d.ts.map +1 -0
- package/dist/__tests__/integration/observer-logging.test.js +517 -0
- package/dist/__tests__/integration/observer-logging.test.js.map +1 -0
- package/dist/__tests__/integration/tree-mirroring.test.d.ts +2 -0
- package/dist/__tests__/integration/tree-mirroring.test.d.ts.map +1 -0
- package/dist/__tests__/integration/tree-mirroring.test.js +117 -0
- package/dist/__tests__/integration/tree-mirroring.test.js.map +1 -0
- package/dist/__tests__/integration/workflow-reparenting.test.d.ts +12 -0
- package/dist/__tests__/integration/workflow-reparenting.test.d.ts.map +1 -0
- package/dist/__tests__/integration/workflow-reparenting.test.js +239 -0
- package/dist/__tests__/integration/workflow-reparenting.test.js.map +1 -0
- package/dist/__tests__/unit/agent.test.d.ts +2 -0
- package/dist/__tests__/unit/agent.test.d.ts.map +1 -0
- package/dist/__tests__/unit/agent.test.js +143 -0
- package/dist/__tests__/unit/agent.test.js.map +1 -0
- package/dist/__tests__/unit/cache-key.test.d.ts +5 -0
- package/dist/__tests__/unit/cache-key.test.d.ts.map +1 -0
- package/dist/__tests__/unit/cache-key.test.js +145 -0
- package/dist/__tests__/unit/cache-key.test.js.map +1 -0
- package/dist/__tests__/unit/cache.test.d.ts +5 -0
- package/dist/__tests__/unit/cache.test.d.ts.map +1 -0
- package/dist/__tests__/unit/cache.test.js +132 -0
- package/dist/__tests__/unit/cache.test.js.map +1 -0
- package/dist/__tests__/unit/context.test.d.ts +2 -0
- package/dist/__tests__/unit/context.test.d.ts.map +1 -0
- package/dist/__tests__/unit/context.test.js +220 -0
- package/dist/__tests__/unit/context.test.js.map +1 -0
- package/dist/__tests__/unit/decorators.test.d.ts +2 -0
- package/dist/__tests__/unit/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/unit/decorators.test.js +162 -0
- package/dist/__tests__/unit/decorators.test.js.map +1 -0
- package/dist/__tests__/unit/introspection-tools.test.d.ts +5 -0
- package/dist/__tests__/unit/introspection-tools.test.d.ts.map +1 -0
- package/dist/__tests__/unit/introspection-tools.test.js +191 -0
- package/dist/__tests__/unit/introspection-tools.test.js.map +1 -0
- package/dist/__tests__/unit/logger.test.d.ts +2 -0
- package/dist/__tests__/unit/logger.test.d.ts.map +1 -0
- package/dist/__tests__/unit/logger.test.js +241 -0
- package/dist/__tests__/unit/logger.test.js.map +1 -0
- package/dist/__tests__/unit/observable.test.d.ts +2 -0
- package/dist/__tests__/unit/observable.test.d.ts.map +1 -0
- package/dist/__tests__/unit/observable.test.js +251 -0
- package/dist/__tests__/unit/observable.test.js.map +1 -0
- package/dist/__tests__/unit/prompt.test.d.ts +2 -0
- package/dist/__tests__/unit/prompt.test.d.ts.map +1 -0
- package/dist/__tests__/unit/prompt.test.js +113 -0
- package/dist/__tests__/unit/prompt.test.js.map +1 -0
- package/dist/__tests__/unit/reflection.test.d.ts +5 -0
- package/dist/__tests__/unit/reflection.test.d.ts.map +1 -0
- package/dist/__tests__/unit/reflection.test.js +160 -0
- package/dist/__tests__/unit/reflection.test.js.map +1 -0
- package/dist/__tests__/unit/tree-debugger-incremental.test.d.ts +2 -0
- package/dist/__tests__/unit/tree-debugger-incremental.test.d.ts.map +1 -0
- package/dist/__tests__/unit/tree-debugger-incremental.test.js +136 -0
- package/dist/__tests__/unit/tree-debugger-incremental.test.js.map +1 -0
- package/dist/__tests__/unit/tree-debugger.test.d.ts +2 -0
- package/dist/__tests__/unit/tree-debugger.test.d.ts.map +1 -0
- package/dist/__tests__/unit/tree-debugger.test.js +69 -0
- package/dist/__tests__/unit/tree-debugger.test.js.map +1 -0
- package/dist/__tests__/unit/utils/workflow-error-utils.test.d.ts +2 -0
- package/dist/__tests__/unit/utils/workflow-error-utils.test.d.ts.map +1 -0
- package/dist/__tests__/unit/utils/workflow-error-utils.test.js +154 -0
- package/dist/__tests__/unit/utils/workflow-error-utils.test.js.map +1 -0
- package/dist/__tests__/unit/workflow-detachChild.test.d.ts +2 -0
- package/dist/__tests__/unit/workflow-detachChild.test.d.ts.map +1 -0
- package/dist/__tests__/unit/workflow-detachChild.test.js +76 -0
- package/dist/__tests__/unit/workflow-detachChild.test.js.map +1 -0
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.d.ts +2 -0
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.d.ts.map +1 -0
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.js +122 -0
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.js.map +1 -0
- package/dist/__tests__/unit/workflow-isDescendantOf.test.d.ts +2 -0
- package/dist/__tests__/unit/workflow-isDescendantOf.test.d.ts.map +1 -0
- package/dist/__tests__/unit/workflow-isDescendantOf.test.js +140 -0
- package/dist/__tests__/unit/workflow-isDescendantOf.test.js.map +1 -0
- package/dist/__tests__/unit/workflow.test.d.ts +2 -0
- package/dist/__tests__/unit/workflow.test.d.ts.map +1 -0
- package/dist/__tests__/unit/workflow.test.js +330 -0
- package/dist/__tests__/unit/workflow.test.js.map +1 -0
- package/dist/cache/cache-key.d.ts +66 -0
- package/dist/cache/cache-key.d.ts.map +1 -0
- package/dist/cache/cache-key.js +195 -0
- package/dist/cache/cache-key.js.map +1 -0
- package/dist/cache/cache.d.ts +104 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +179 -0
- package/dist/cache/cache.js.map +1 -0
- package/{src/cache/index.ts → dist/cache/index.d.ts} +1 -1
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/core/agent.d.ts +112 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +426 -0
- package/dist/core/agent.js.map +1 -0
- package/{src/core/context.ts → dist/core/context.d.ts} +16 -67
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +80 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/event-tree.d.ts +72 -0
- package/dist/core/event-tree.d.ts.map +1 -0
- package/dist/core/event-tree.js +211 -0
- package/dist/core/event-tree.js.map +1 -0
- package/{src/core/factory.ts → dist/core/factory.d.ts} +6 -27
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +110 -0
- package/dist/core/factory.js.map +1 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +2 -10
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +50 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +91 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp-handler.d.ts +69 -0
- package/dist/core/mcp-handler.d.ts.map +1 -0
- package/dist/core/mcp-handler.js +143 -0
- package/dist/core/mcp-handler.js.map +1 -0
- package/dist/core/prompt.d.ts +80 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +120 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/workflow-context.d.ts +57 -0
- package/dist/core/workflow-context.d.ts.map +1 -0
- package/dist/core/workflow-context.js +263 -0
- package/dist/core/workflow-context.js.map +1 -0
- package/dist/core/workflow.d.ts +241 -0
- package/dist/core/workflow.d.ts.map +1 -0
- package/dist/core/workflow.js +464 -0
- package/dist/core/workflow.js.map +1 -0
- package/dist/debugger/index.d.ts +2 -0
- package/dist/debugger/index.d.ts.map +1 -0
- package/{src/debugger/index.ts → dist/debugger/index.js} +1 -0
- package/dist/debugger/index.js.map +1 -0
- package/dist/debugger/tree-debugger.d.ts +71 -0
- package/dist/debugger/tree-debugger.d.ts.map +1 -0
- package/dist/debugger/tree-debugger.js +198 -0
- package/dist/debugger/tree-debugger.js.map +1 -0
- package/dist/decorators/index.d.ts +4 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/{src/decorators/index.ts → dist/decorators/index.js} +1 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/observed-state.d.ts +32 -0
- package/dist/decorators/observed-state.d.ts.map +1 -0
- package/dist/decorators/observed-state.js +79 -0
- package/dist/decorators/observed-state.js.map +1 -0
- package/dist/decorators/step.d.ts +15 -0
- package/dist/decorators/step.d.ts.map +1 -0
- package/dist/decorators/step.js +110 -0
- package/dist/decorators/step.js.map +1 -0
- package/dist/decorators/task.d.ts +50 -0
- package/dist/decorators/task.d.ts.map +1 -0
- package/dist/decorators/task.js +118 -0
- package/dist/decorators/task.js.map +1 -0
- package/dist/examples/index.d.ts +3 -0
- package/dist/examples/index.d.ts.map +1 -0
- package/{src/examples/index.ts → dist/examples/index.js} +1 -0
- package/dist/examples/index.js.map +1 -0
- package/dist/examples/tdd-orchestrator.d.ts +15 -0
- package/dist/examples/tdd-orchestrator.d.ts.map +1 -0
- package/dist/examples/tdd-orchestrator.js +121 -0
- package/dist/examples/tdd-orchestrator.js.map +1 -0
- package/dist/examples/test-cycle-workflow.d.ts +14 -0
- package/dist/examples/test-cycle-workflow.d.ts.map +1 -0
- package/dist/examples/test-cycle-workflow.js +116 -0
- package/dist/examples/test-cycle-workflow.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/reflection/index.d.ts +5 -0
- package/dist/reflection/index.d.ts.map +1 -0
- package/{src/reflection/index.ts → dist/reflection/index.js} +1 -1
- package/dist/reflection/index.js.map +1 -0
- package/dist/reflection/reflection.d.ts +84 -0
- package/dist/reflection/reflection.d.ts.map +1 -0
- package/dist/reflection/reflection.js +329 -0
- package/dist/reflection/reflection.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +11 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/introspection.d.ts +165 -0
- package/dist/tools/introspection.d.ts.map +1 -0
- package/dist/tools/introspection.js +324 -0
- package/dist/tools/introspection.js.map +1 -0
- package/dist/types/agent.d.ts +66 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +6 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/decorators.d.ts +31 -0
- package/dist/types/decorators.d.ts.map +1 -0
- package/dist/types/decorators.js +2 -0
- package/dist/types/decorators.js.map +1 -0
- package/dist/types/error-strategy.d.ts +13 -0
- package/dist/types/error-strategy.d.ts.map +1 -0
- package/dist/types/error-strategy.js +2 -0
- package/dist/types/error-strategy.js.map +1 -0
- package/dist/types/error.d.ts +20 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/error.js +2 -0
- package/dist/types/error.js.map +1 -0
- package/dist/types/events.d.ts +87 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +2 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/logging.d.ts +24 -0
- package/dist/types/logging.d.ts.map +1 -0
- package/dist/types/logging.js +2 -0
- package/dist/types/logging.js.map +1 -0
- package/dist/types/observer.d.ts +18 -0
- package/dist/types/observer.d.ts.map +1 -0
- package/dist/types/observer.js +2 -0
- package/dist/types/observer.js.map +1 -0
- package/dist/types/prompt.d.ts +31 -0
- package/dist/types/prompt.d.ts.map +1 -0
- package/dist/types/prompt.js +6 -0
- package/dist/types/prompt.js.map +1 -0
- package/dist/types/reflection.d.ts +96 -0
- package/dist/types/reflection.d.ts.map +1 -0
- package/dist/types/reflection.js +24 -0
- package/dist/types/reflection.js.map +1 -0
- package/dist/types/sdk-primitives.d.ts +118 -0
- package/dist/types/sdk-primitives.d.ts.map +1 -0
- package/dist/types/sdk-primitives.js +6 -0
- package/dist/types/sdk-primitives.js.map +1 -0
- package/{src/types/snapshot.ts → dist/types/snapshot.d.ts} +5 -5
- package/dist/types/snapshot.d.ts.map +1 -0
- package/dist/types/snapshot.js +2 -0
- package/dist/types/snapshot.js.map +1 -0
- package/dist/types/workflow-context.d.ts +139 -0
- package/dist/types/workflow-context.d.ts.map +1 -0
- package/dist/types/workflow-context.js +8 -0
- package/dist/types/workflow-context.js.map +1 -0
- package/dist/types/workflow.d.ts +30 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +2 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/utils/id.d.ts +6 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +12 -0
- package/dist/utils/id.js.map +1 -0
- package/{src/utils/index.ts → dist/utils/index.d.ts} +1 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/observable.d.ts +54 -0
- package/dist/utils/observable.d.ts.map +1 -0
- package/dist/utils/observable.js +82 -0
- package/dist/utils/observable.js.map +1 -0
- package/dist/utils/workflow-error-utils.d.ts +22 -0
- package/dist/utils/workflow-error-utils.d.ts.map +1 -0
- package/dist/utils/workflow-error-utils.js +45 -0
- package/dist/utils/workflow-error-utils.js.map +1 -0
- package/package.json +5 -2
- package/.claude/commands/subtask-planning/prp-base-create.md +0 -120
- package/.claude/commands/subtask-planning/prp-base-execute.md +0 -65
- package/.claude/commands/task-breakdown.md +0 -94
- package/.claude/settings.local.json +0 -9
- package/.claude/system_prompts/task-breakdown.md +0 -101
- package/PRD.md +0 -543
- package/PRPs/001-hierarchical-workflow-engine.md +0 -2438
- package/PRPs/PRDs/002-agent-prompt.md +0 -390
- package/PRPs/PRDs/003-agent-prompt.md +0 -943
- package/PRPs/PRDs/004-agent-prompt.md +0 -1136
- package/PRPs/PRDs/tasks-001.json +0 -492
- package/PRPs/README.md +0 -83
- package/PRPs/templates/prp_base.md +0 -222
- package/docs/agent.md +0 -422
- package/docs/prompt.md +0 -419
- package/docs/workflow.md +0 -600
- package/examples/README.md +0 -258
- package/examples/examples/01-basic-workflow.ts +0 -100
- package/examples/examples/02-decorator-options.ts +0 -217
- package/examples/examples/03-parent-child.ts +0 -241
- package/examples/examples/04-observers-debugger.ts +0 -340
- package/examples/examples/05-error-handling.ts +0 -387
- package/examples/examples/06-concurrent-tasks.ts +0 -352
- package/examples/examples/07-agent-loops.ts +0 -432
- package/examples/examples/08-sdk-features.ts +0 -667
- package/examples/examples/09-reflection.ts +0 -573
- package/examples/examples/10-introspection.ts +0 -550
- package/examples/examples/11-reparenting-workflows.ts +0 -269
- package/examples/index.ts +0 -147
- package/examples/utils/helpers.ts +0 -57
- package/package-lock.json +0 -2398
- package/plan/001_d3bb02af4886/TEST_RESULTS.md +0 -259
- package/plan/001_d3bb02af4886/backlog.json +0 -867
- package/plan/001_d3bb02af4886/bug_fix_tasks.json +0 -484
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +0 -488
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +0 -581
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +0 -687
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +0 -492
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +0 -932
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +0 -1109
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +0 -802
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +0 -603
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +0 -564
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +0 -518
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +0 -1252
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +0 -364
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +0 -114
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +0 -205
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +0 -199
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +0 -134
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +0 -495
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +0 -435
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +0 -506
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +0 -612
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +0 -558
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +0 -788
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +0 -460
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +0 -454
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +0 -520
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +0 -417
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +0 -760
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +0 -245
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +0 -792
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +0 -535
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +0 -190
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +0 -654
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +0 -227
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +0 -345
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +0 -193
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +0 -1323
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +0 -1011
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +0 -927
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +0 -505
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +0 -401
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +0 -142
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +0 -112
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +0 -159
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +0 -549
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +0 -368
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +0 -172
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +0 -175
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +0 -696
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +0 -860
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +0 -1066
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +0 -1103
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +0 -789
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +0 -1098
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +0 -1037
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +0 -916
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +0 -1045
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +0 -890
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +0 -822
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +0 -668
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +0 -706
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +0 -265
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +0 -655
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +0 -1103
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +0 -426
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +0 -506
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +0 -114
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +0 -316
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +0 -754
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +0 -612
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +0 -719
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +0 -215
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +0 -765
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +0 -718
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +0 -149
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +0 -470
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +0 -332
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +0 -167
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +0 -265
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +0 -273
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +0 -760
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +0 -434
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +0 -717
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +0 -472
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +0 -125
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +0 -301
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +0 -1170
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +0 -940
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +0 -151
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +0 -650
- package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +0 -259
- package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +0 -457
- package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +0 -346
- package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +0 -311
- package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +0 -1565
- package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +0 -288
- package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +0 -741
- package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +0 -652
- package/plan/001_d3bb02af4886/docs/PRP/P1P2-PRP.md +0 -527
- package/plan/001_d3bb02af4886/docs/PRP/P3P4-PRP.md +0 -1388
- package/plan/001_d3bb02af4886/docs/PRP/P4P5-PRP.md +0 -1136
- package/plan/001_d3bb02af4886/docs/PRP/PRP.md +0 -527
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +0 -415
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +0 -378
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +0 -713
- package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +0 -370
- package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +0 -499
- package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +0 -230
- package/plan/001_d3bb02af4886/docs/architecture/external_deps.md +0 -358
- package/plan/001_d3bb02af4886/docs/architecture/system_context.md +0 -242
- package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +0 -1134
- package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +0 -179
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +0 -629
- package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +0 -214
- package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +0 -629
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +0 -529
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +0 -142
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +0 -304
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +0 -558
- package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +0 -256
- package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +0 -346
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +0 -415
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +0 -489
- package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +0 -218
- package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +0 -380
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +0 -1923
- package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +0 -319
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +0 -115
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +0 -134
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +0 -153
- package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +0 -132
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +0 -716
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +0 -186
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +0 -604
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +0 -213
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +0 -30
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +0 -56
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +0 -53
- package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +0 -49
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +0 -958
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +0 -339
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +0 -305
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +0 -433
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +0 -1574
- package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +0 -1014
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_BEST_PRACTICES.md +0 -1929
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_CODE_PATTERNS.md +0 -857
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_INTEGRATION_GUIDE.md +0 -738
- package/plan/001_d3bb02af4886/docs/research/P1P2/LRU_CACHE_RESEARCH_INDEX.md +0 -424
- package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_INDEX.md +0 -291
- package/plan/001_d3bb02af4886/docs/research/P1P2/REFLECTION_RESEARCH_REPORT.md +0 -1342
- package/plan/001_d3bb02af4886/docs/research/P1P2/RESEARCH_SUMMARY.md +0 -342
- package/plan/001_d3bb02af4886/docs/research/P1P2/anthropic-sdk.md +0 -174
- package/plan/001_d3bb02af4886/docs/research/P1P2/async-local-storage.md +0 -200
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-code-patterns.md +0 -1205
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-decision-matrix.md +0 -421
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-implementation-guide.md +0 -1341
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-integration-guide.md +0 -834
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-patterns.md +0 -1468
- package/plan/001_d3bb02af4886/docs/research/P1P2/reflection-quick-reference.md +0 -558
- package/plan/001_d3bb02af4886/docs/research/P1P2/zod-schema.md +0 -152
- package/plan/001_d3bb02af4886/docs/research/P3P4/caching-lru.md +0 -116
- package/plan/001_d3bb02af4886/docs/research/P3P4/introspection-tools.md +0 -177
- package/plan/001_d3bb02af4886/docs/research/P3P4/reflection-patterns.md +0 -117
- package/plan/001_d3bb02af4886/docs/research/P4P5/RESEARCH_SUMMARY.md +0 -151
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +0 -376
- package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +0 -1507
- package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +0 -949
- package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +0 -619
- package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +0 -723
- package/plan/001_d3bb02af4886/docs/research/general/INTROSPECTION_RESEARCH_SUMMARY.md +0 -378
- package/plan/001_d3bb02af4886/docs/research/general/README-INTROSPECTION.md +0 -352
- package/plan/001_d3bb02af4886/docs/research/general/agent-introspection-patterns.md +0 -1085
- package/plan/001_d3bb02af4886/docs/research/general/introspection-security-guide.md +0 -984
- package/plan/001_d3bb02af4886/docs/research/general/introspection-tool-examples.md +0 -875
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +0 -460
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +0 -324
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +0 -175
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +0 -499
- package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +0 -163
- package/plan/001_d3bb02af4886/prd_snapshot.md +0 -543
- package/plan/bugfix/BUG_FIX_SUMMARY.md +0 -961
- package/scripts/generate-llms-full.ts +0 -206
- package/src/__tests__/adversarial/attachChild-performance.test.ts +0 -216
- package/src/__tests__/adversarial/circular-reference.test.ts +0 -101
- package/src/__tests__/adversarial/complex-circular-reference.test.ts +0 -139
- package/src/__tests__/adversarial/concurrent-task-failures.test.ts +0 -571
- package/src/__tests__/adversarial/deep-analysis.test.ts +0 -729
- package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +0 -213
- package/src/__tests__/adversarial/e2e-prd-validation.test.ts +0 -448
- package/src/__tests__/adversarial/edge-case.test.ts +0 -703
- package/src/__tests__/adversarial/error-merge-strategy.test.ts +0 -760
- package/src/__tests__/adversarial/incremental-performance.test.ts +0 -140
- package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +0 -457
- package/src/__tests__/adversarial/observer-propagation.test.ts +0 -487
- package/src/__tests__/adversarial/parent-validation.test.ts +0 -143
- package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +0 -611
- package/src/__tests__/adversarial/prd-compliance.test.ts +0 -731
- package/src/__tests__/compatibility/backward-compatibility.test.ts +0 -1572
- package/src/__tests__/helpers/tree-verification.ts +0 -257
- package/src/__tests__/integration/agent-workflow.test.ts +0 -256
- package/src/__tests__/integration/bidirectional-consistency.test.ts +0 -847
- package/src/__tests__/integration/observer-logging.test.ts +0 -643
- package/src/__tests__/integration/tree-mirroring.test.ts +0 -151
- package/src/__tests__/integration/workflow-reparenting.test.ts +0 -303
- package/src/__tests__/unit/agent.test.ts +0 -169
- package/src/__tests__/unit/cache-key.test.ts +0 -182
- package/src/__tests__/unit/cache.test.ts +0 -172
- package/src/__tests__/unit/context.test.ts +0 -217
- package/src/__tests__/unit/decorators.test.ts +0 -100
- package/src/__tests__/unit/introspection-tools.test.ts +0 -277
- package/src/__tests__/unit/logger.test.ts +0 -293
- package/src/__tests__/unit/observable.test.ts +0 -321
- package/src/__tests__/unit/prompt.test.ts +0 -135
- package/src/__tests__/unit/reflection.test.ts +0 -210
- package/src/__tests__/unit/tree-debugger-incremental.test.ts +0 -170
- package/src/__tests__/unit/tree-debugger.test.ts +0 -85
- package/src/__tests__/unit/utils/workflow-error-utils.test.ts +0 -209
- package/src/__tests__/unit/workflow-detachChild.test.ts +0 -100
- package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +0 -153
- package/src/__tests__/unit/workflow-isDescendantOf.test.ts +0 -180
- package/src/__tests__/unit/workflow.test.ts +0 -357
- package/src/cache/cache-key.ts +0 -244
- package/src/cache/cache.ts +0 -236
- package/src/core/agent.ts +0 -593
- package/src/core/event-tree.ts +0 -260
- package/src/core/logger.ts +0 -112
- package/src/core/mcp-handler.ts +0 -184
- package/src/core/prompt.ts +0 -150
- package/src/core/workflow-context.ts +0 -351
- package/src/core/workflow.ts +0 -540
- package/src/debugger/tree-debugger.ts +0 -255
- package/src/decorators/observed-state.ts +0 -95
- package/src/decorators/step.ts +0 -139
- package/src/decorators/task.ts +0 -159
- package/src/examples/tdd-orchestrator.ts +0 -65
- package/src/examples/test-cycle-workflow.ts +0 -64
- package/src/index.ts +0 -142
- package/src/reflection/reflection.ts +0 -407
- package/src/tools/index.ts +0 -36
- package/src/tools/introspection.ts +0 -464
- package/src/types/agent.ts +0 -90
- package/src/types/decorators.ts +0 -32
- package/src/types/error-strategy.ts +0 -13
- package/src/types/error.ts +0 -20
- package/src/types/events.ts +0 -75
- package/src/types/index.ts +0 -55
- package/src/types/logging.ts +0 -24
- package/src/types/observer.ts +0 -18
- package/src/types/prompt.ts +0 -40
- package/src/types/reflection.ts +0 -117
- package/src/types/sdk-primitives.ts +0 -128
- package/src/types/workflow-context.ts +0 -163
- package/src/types/workflow.ts +0 -37
- package/src/utils/id.ts +0 -11
- package/src/utils/observable.ts +0 -106
- package/src/utils/workflow-error-utils.ts +0 -56
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -16
|
@@ -1,1507 +0,0 @@
|
|
|
1
|
-
# Promise.allSettled Best Practices, Patterns, and Migration Strategies
|
|
2
|
-
|
|
3
|
-
**Research Date:** 2026-01-12
|
|
4
|
-
**Status:** Comprehensive Research Report
|
|
5
|
-
**Target:** Groundswell Hierarchical Workflow Engine - P1.M2.T1 Implementation
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Executive Summary
|
|
10
|
-
|
|
11
|
-
This document provides comprehensive research on Promise.allSettled including official documentation, best practices, migration strategies from Promise.all, error aggregation patterns, TypeScript typing patterns, common pitfalls, and production examples. It serves as the foundational research for migrating the Groundswell workflow engine from Promise.all to Promise.allSettled in concurrent task execution.
|
|
12
|
-
|
|
13
|
-
**Key Finding:** Promise.allSettled is the recommended approach for concurrent workflow execution in Groundswell due to its superior observability, error aggregation capabilities, and alignment with production workflow engines like Airflow and AWS Step Functions.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Table of Contents
|
|
18
|
-
|
|
19
|
-
1. [Official Documentation Resources](#1-official-documentation-resources)
|
|
20
|
-
2. [Promise.all vs Promise.allSettled: Technical Comparison](#2-promiseall-vs-promiseallsettled-technical-comparison)
|
|
21
|
-
3. [Migration Strategies from Promise.all](#3-migration-strategies-from-promiseall)
|
|
22
|
-
4. [Error Aggregation Patterns](#4-error-aggregation-patterns)
|
|
23
|
-
5. [TypeScript Typing Patterns](#5-typescript-typing-patterns)
|
|
24
|
-
6. [Common Pitfalls and Gotchas](#6-common-pitfalls-and-gotchas)
|
|
25
|
-
7. [Production Examples from GitHub](#7-production-examples-from-github)
|
|
26
|
-
8. [StackOverflow Community Insights](#8-stackoverflow-community-insights)
|
|
27
|
-
9. [Groundswell-Specific Implementation Guide](#9-groundswell-specific-implementation-guide)
|
|
28
|
-
10. [Quick Reference Card](#10-quick-reference-card)
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 1. Official Documentation Resources
|
|
33
|
-
|
|
34
|
-
### 1.1 MDN Web Docs
|
|
35
|
-
|
|
36
|
-
#### Promise.allSettled()
|
|
37
|
-
- **URL:** https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
|
|
38
|
-
- **Section:** #description
|
|
39
|
-
- **Key Points:**
|
|
40
|
-
- Returns a promise that resolves after all given promises have settled
|
|
41
|
-
- Returns array of PromiseSettledResult objects with status and value/reason
|
|
42
|
-
- Never rejects - always fulfills
|
|
43
|
-
- ES2020 feature (Node.js 12.9+, Chrome 76+, Firefox 71+, Safari 13+)
|
|
44
|
-
|
|
45
|
-
**Relevance:** Authoritative reference for Promise.allSettled behavior and browser compatibility.
|
|
46
|
-
|
|
47
|
-
#### Promise.all()
|
|
48
|
-
- **URL:** https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
|
|
49
|
-
- **Section:** #behavior
|
|
50
|
-
- **Key Points:**
|
|
51
|
-
- Fail-fast behavior: rejects immediately when any promise rejects
|
|
52
|
-
- Returns array of resolved values when all fulfill
|
|
53
|
-
- Orders results by promise input order
|
|
54
|
-
- ES2015 feature (widely supported)
|
|
55
|
-
|
|
56
|
-
**Relevance:** Understanding the behavior we're migrating from to ensure proper comparison.
|
|
57
|
-
|
|
58
|
-
#### TypeScript Handbook: Promise Types
|
|
59
|
-
- **URL:** https://www.typescriptlang.org/docs/handbook/2/types-from-types.html#promise-types
|
|
60
|
-
- **Section:** Promise Types
|
|
61
|
-
- **Key Points:**
|
|
62
|
-
- Promise<T> represents async operations
|
|
63
|
-
- PromiseSettledResult<T> type for allSettled results
|
|
64
|
-
- Type guards for discriminating unions
|
|
65
|
-
|
|
66
|
-
**Relevance:** TypeScript type safety for Promise.allSettled implementations.
|
|
67
|
-
|
|
68
|
-
### 1.2 ECMAScript Specification
|
|
69
|
-
|
|
70
|
-
#### ECMA-262: Promise.allSettled
|
|
71
|
-
- **URL:** https://tc39.es/ecma262/#sec-promise.allsettled
|
|
72
|
-
- **Section:** 25.6.4.4
|
|
73
|
-
- **Key Points:**
|
|
74
|
-
- Exact algorithm specification
|
|
75
|
-
- Promise resolution behavior
|
|
76
|
-
- PerformPromiseAllSettled algorithm
|
|
77
|
-
|
|
78
|
-
**Relevance:** Deep technical understanding of the specification for edge cases.
|
|
79
|
-
|
|
80
|
-
### 1.3 Node.js Documentation
|
|
81
|
-
|
|
82
|
-
#### Node.js Promise.allSettled
|
|
83
|
-
- **URL:** https://nodejs.org/api/esm.html#esm_shared_global_builtins
|
|
84
|
-
- **Section:** Shared globals
|
|
85
|
-
- **Key Points:**
|
|
86
|
-
- Available in Node.js 12.9.0+
|
|
87
|
-
- No polyfill needed for modern Node.js
|
|
88
|
-
- Performance characteristics
|
|
89
|
-
|
|
90
|
-
**Relevance:** Server-side JavaScript implementation details.
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 2. Promise.all vs Promise.allSettled: Technical Comparison
|
|
95
|
-
|
|
96
|
-
### 2.1 Behavioral Differences
|
|
97
|
-
|
|
98
|
-
#### Promise.all (Fail-Fast)
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
const results = await Promise.all([
|
|
102
|
-
fetch('/api/user'),
|
|
103
|
-
fetch('/api/posts'),
|
|
104
|
-
fetch('/api/comments')
|
|
105
|
-
]);
|
|
106
|
-
// If ANY request fails, immediately rejects
|
|
107
|
-
// Other in-flight requests continue but results are lost
|
|
108
|
-
// Only first error is visible
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Characteristics:**
|
|
112
|
-
- ✅ Fast failure detection
|
|
113
|
-
- ✅ Simple mental model
|
|
114
|
-
- ✅ Lower memory overhead
|
|
115
|
-
- ❌ Loses partial results
|
|
116
|
-
- ❌ Hides concurrent errors
|
|
117
|
-
- ❌ Poor debugging experience
|
|
118
|
-
|
|
119
|
-
#### Promise.allSettled (Complete-All)
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
const results = await Promise.allSettled([
|
|
123
|
-
fetch('/api/user'),
|
|
124
|
-
fetch('/api/posts'),
|
|
125
|
-
fetch('/api/comments')
|
|
126
|
-
]);
|
|
127
|
-
// ALL requests complete regardless of failures
|
|
128
|
-
// Returns array of {status, value/reason} objects
|
|
129
|
-
// All errors visible and preserved
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Characteristics:**
|
|
133
|
-
- ✅ Complete error visibility
|
|
134
|
-
- ✅ Preserves partial results
|
|
135
|
-
- ✅ Better debugging
|
|
136
|
-
- ✅ Error pattern analysis
|
|
137
|
-
- ❌ Slower failure detection
|
|
138
|
-
- ❌ Higher memory usage
|
|
139
|
-
- ❌ More complex error handling
|
|
140
|
-
|
|
141
|
-
### 2.2 Result Structure Comparison
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// Promise.all result (on success)
|
|
145
|
-
const allResults: string[] = ['result1', 'result2', 'result3'];
|
|
146
|
-
|
|
147
|
-
// Promise.allSettled result (mixed)
|
|
148
|
-
const allSettledResults: PromiseSettledResult<string>[] = [
|
|
149
|
-
{ status: 'fulfilled', value: 'result1' },
|
|
150
|
-
{ status: 'rejected', reason: Error('failed') },
|
|
151
|
-
{ status: 'fulfilled', value: 'result3' }
|
|
152
|
-
];
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### 2.3 Performance Comparison
|
|
156
|
-
|
|
157
|
-
| Metric | Promise.all | Promise.allSettled |
|
|
158
|
-
|--------|-------------|-------------------|
|
|
159
|
-
| Time to First Error | Immediate (min time) | Waits for all (max time) |
|
|
160
|
-
| Time to Complete All | N/A (fails early) | Max of all operations |
|
|
161
|
-
| Memory Usage | Low | Higher (stores all errors) |
|
|
162
|
-
| Error Completeness | First error only | All errors |
|
|
163
|
-
| Partial Results | Lost | Preserved |
|
|
164
|
-
| Cancellation | Manual (abort controllers) | Manual (abort controllers) |
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## 3. Migration Strategies from Promise.all
|
|
169
|
-
|
|
170
|
-
### 3.1 Direct Migration Pattern
|
|
171
|
-
|
|
172
|
-
#### Before (Promise.all)
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
async function fetchAllData() {
|
|
176
|
-
try {
|
|
177
|
-
const results = await Promise.all([
|
|
178
|
-
fetchUser(),
|
|
179
|
-
fetchPosts(),
|
|
180
|
-
fetchComments()
|
|
181
|
-
]);
|
|
182
|
-
return { success: true, data: results };
|
|
183
|
-
} catch (error) {
|
|
184
|
-
return { success: false, error };
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
#### After (Promise.allSettled)
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
async function fetchAllData() {
|
|
193
|
-
const results = await Promise.allSettled([
|
|
194
|
-
fetchUser(),
|
|
195
|
-
fetchPosts(),
|
|
196
|
-
fetchComments()
|
|
197
|
-
]);
|
|
198
|
-
|
|
199
|
-
const successes = results
|
|
200
|
-
.filter((r): r is PromiseFulfilledResult<unknown> => r.status === 'fulfilled')
|
|
201
|
-
.map(r => r.value);
|
|
202
|
-
|
|
203
|
-
const failures = results
|
|
204
|
-
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
205
|
-
.map(r => r.reason);
|
|
206
|
-
|
|
207
|
-
if (failures.length > 0) {
|
|
208
|
-
return { success: false, errors: failures, partial: successes };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return { success: true, data: successes };
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### 3.2 Backward Compatibility Pattern
|
|
216
|
-
|
|
217
|
-
**Strategy:** Maintain existing API contract while using allSettled internally.
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
async function fetchAllDataWithBackwardCompat() {
|
|
221
|
-
const results = await Promise.allSettled([
|
|
222
|
-
fetchUser(),
|
|
223
|
-
fetchPosts(),
|
|
224
|
-
fetchComments()
|
|
225
|
-
]);
|
|
226
|
-
|
|
227
|
-
// Filter for failures
|
|
228
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
229
|
-
|
|
230
|
-
// Throw first error to maintain backward compatibility
|
|
231
|
-
if (failures.length > 0) {
|
|
232
|
-
throw failures[0].reason; // First error wins (like Promise.all)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Return values (like Promise.all)
|
|
236
|
-
return results
|
|
237
|
-
.filter((r): r is PromiseFulfilledResult<unknown> => r.status === 'fulfilled')
|
|
238
|
-
.map(r => r.value);
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### 3.3 Gradual Migration Pattern
|
|
243
|
-
|
|
244
|
-
**Phase 1:** Add feature flag for new behavior
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
interface Options {
|
|
248
|
-
useAllSettled?: boolean;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
async function fetchAllData(options: Options = {}) {
|
|
252
|
-
if (options.useAllSettled) {
|
|
253
|
-
// New behavior: collect all errors
|
|
254
|
-
return fetchAllDataAllSettled();
|
|
255
|
-
} else {
|
|
256
|
-
// Old behavior: fail-fast
|
|
257
|
-
return fetchAllDataAll();
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
**Phase 2:** Monitor and validate new behavior
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
// Log error patterns
|
|
266
|
-
async function fetchAllDataWithLogging(options: Options = {}) {
|
|
267
|
-
if (options.useAllSettled) {
|
|
268
|
-
const results = await Promise.allSettled(/* ... */);
|
|
269
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
270
|
-
|
|
271
|
-
// Log for monitoring
|
|
272
|
-
logger.info('Promise.allSettled', {
|
|
273
|
-
total: results.length,
|
|
274
|
-
failed: failures.length,
|
|
275
|
-
errorRate: failures.length / results.length
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
return processResults(results);
|
|
279
|
-
} else {
|
|
280
|
-
return fetchAllDataAll();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
**Phase 3:** Switch default and deprecate old behavior
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
async function fetchAllData(options: Options = {}) {
|
|
289
|
-
// Default to allSettled
|
|
290
|
-
const useAllSettled = options.useAllSettled ?? true;
|
|
291
|
-
|
|
292
|
-
if (useAllSettled) {
|
|
293
|
-
return fetchAllDataAllSettled();
|
|
294
|
-
} else {
|
|
295
|
-
logger.warn('Deprecated: useAllSettled=false is deprecated');
|
|
296
|
-
return fetchAllDataAll();
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### 3.4 Error Aggregation Pattern
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
interface AggregateError extends Error {
|
|
305
|
-
errors: unknown[];
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
async function fetchAllDataAggregated() {
|
|
309
|
-
const results = await Promise.allSettled([
|
|
310
|
-
fetchUser(),
|
|
311
|
-
fetchPosts(),
|
|
312
|
-
fetchComments()
|
|
313
|
-
]);
|
|
314
|
-
|
|
315
|
-
const failures = results
|
|
316
|
-
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
317
|
-
.map(r => r.reason);
|
|
318
|
-
|
|
319
|
-
if (failures.length > 0) {
|
|
320
|
-
// Create aggregate error
|
|
321
|
-
const error = new Error(
|
|
322
|
-
`${failures.length} operations failed`
|
|
323
|
-
) as AggregateError;
|
|
324
|
-
error.errors = failures;
|
|
325
|
-
throw error;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return results
|
|
329
|
-
.filter((r): r is PromiseFulfilledResult<unknown> => r.status === 'fulfilled')
|
|
330
|
-
.map(r => r.value);
|
|
331
|
-
}
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
---
|
|
335
|
-
|
|
336
|
-
## 4. Error Aggregation Patterns
|
|
337
|
-
|
|
338
|
-
### 4.1 Simple Error Collection
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
async function executeWithErrorCollection<T>(
|
|
342
|
-
promises: Promise<T>[]
|
|
343
|
-
): Promise<{ values: T[]; errors: unknown[] }> {
|
|
344
|
-
const results = await Promise.allSettled(promises);
|
|
345
|
-
|
|
346
|
-
const values: T[] = [];
|
|
347
|
-
const errors: unknown[] = [];
|
|
348
|
-
|
|
349
|
-
for (const result of results) {
|
|
350
|
-
if (result.status === 'fulfilled') {
|
|
351
|
-
values.push(result.value);
|
|
352
|
-
} else {
|
|
353
|
-
errors.push(result.reason);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return { values, errors };
|
|
358
|
-
}
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### 4.2 Typed Error Aggregation
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
interface ExecutionResult<T, E = Error> {
|
|
365
|
-
success: boolean;
|
|
366
|
-
value?: T;
|
|
367
|
-
error?: E;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
async function executeWithTypedErrors<T>(
|
|
371
|
-
promises: Promise<T>[]
|
|
372
|
-
): Promise<ExecutionResult<T>[]> {
|
|
373
|
-
const results = await Promise.allSettled(promises);
|
|
374
|
-
|
|
375
|
-
return results.map(result => {
|
|
376
|
-
if (result.status === 'fulfilled') {
|
|
377
|
-
return { success: true, value: result.value };
|
|
378
|
-
} else {
|
|
379
|
-
return {
|
|
380
|
-
success: false,
|
|
381
|
-
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### 4.3 Hierarchical Error Aggregation
|
|
389
|
-
|
|
390
|
-
```typescript
|
|
391
|
-
interface WorkflowAggregateError extends Error {
|
|
392
|
-
name: 'WorkflowAggregateError';
|
|
393
|
-
errors: Array<{
|
|
394
|
-
workflowId: string;
|
|
395
|
-
error: unknown;
|
|
396
|
-
}>;
|
|
397
|
-
parentWorkflowId: string;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async function executeWorkflowsAggregated(
|
|
401
|
-
workflows: Array<{ id: string; run: () => Promise<unknown> }>,
|
|
402
|
-
parentId: string
|
|
403
|
-
): Promise<void> {
|
|
404
|
-
const results = await Promise.allSettled(
|
|
405
|
-
workflows.map(w => w.run())
|
|
406
|
-
);
|
|
407
|
-
|
|
408
|
-
const failures = workflows
|
|
409
|
-
.map((w, i) => ({ workflow: w, result: results[i] }))
|
|
410
|
-
.filter(({ result }) => result.status === 'rejected')
|
|
411
|
-
.map(({ workflow, result }) => ({
|
|
412
|
-
workflowId: workflow.id,
|
|
413
|
-
error: (result as PromiseRejectedResult).reason
|
|
414
|
-
}));
|
|
415
|
-
|
|
416
|
-
if (failures.length > 0) {
|
|
417
|
-
const error = new Error(
|
|
418
|
-
`${failures.length} child workflows failed`
|
|
419
|
-
) as WorkflowAggregateError;
|
|
420
|
-
error.name = 'WorkflowAggregateError';
|
|
421
|
-
error.errors = failures;
|
|
422
|
-
error.parentWorkflowId = parentId;
|
|
423
|
-
throw error;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
### 4.4 Error Rate Thresholding
|
|
429
|
-
|
|
430
|
-
```typescript
|
|
431
|
-
interface ThresholdOptions {
|
|
432
|
-
maxErrorRate: number; // 0.0 to 1.0
|
|
433
|
-
minAbsoluteErrors: number;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
async function executeWithThreshold<T>(
|
|
437
|
-
promises: Promise<T>[],
|
|
438
|
-
options: ThresholdOptions
|
|
439
|
-
): Promise<T[]> {
|
|
440
|
-
const results = await Promise.allSettled(promises);
|
|
441
|
-
|
|
442
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
443
|
-
const errorRate = failures.length / results.length;
|
|
444
|
-
|
|
445
|
-
const shouldThrow =
|
|
446
|
-
failures.length >= options.minAbsoluteErrors ||
|
|
447
|
-
errorRate > options.maxErrorRate;
|
|
448
|
-
|
|
449
|
-
if (shouldThrow) {
|
|
450
|
-
throw new Error(
|
|
451
|
-
`Error rate ${(errorRate * 100).toFixed(1)}% exceeds threshold`
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return results
|
|
456
|
-
.filter((r): r is PromiseFulfilledResult<T> => r.status === 'fulfilled')
|
|
457
|
-
.map(r => r.value);
|
|
458
|
-
}
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
### 4.5 Error Statistics and Analytics
|
|
462
|
-
|
|
463
|
-
```typescript
|
|
464
|
-
interface ErrorStats {
|
|
465
|
-
total: number;
|
|
466
|
-
succeeded: number;
|
|
467
|
-
failed: number;
|
|
468
|
-
errorRate: number;
|
|
469
|
-
errorsByType: Record<string, number>;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
async function executeWithErrorStats<T>(
|
|
473
|
-
promises: Promise<T>[]
|
|
474
|
-
): Promise<{ values: T[]; stats: ErrorStats }> {
|
|
475
|
-
const results = await Promise.allSettled(promises);
|
|
476
|
-
|
|
477
|
-
const failures = results.filter(r => r.status === 'rejected');
|
|
478
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
479
|
-
|
|
480
|
-
const errorsByType = failures.reduce((acc, result) => {
|
|
481
|
-
const reason = (result as PromiseRejectedResult).reason;
|
|
482
|
-
const type = reason?.constructor?.name || 'Unknown';
|
|
483
|
-
acc[type] = (acc[type] || 0) + 1;
|
|
484
|
-
return acc;
|
|
485
|
-
}, {} as Record<string, number>);
|
|
486
|
-
|
|
487
|
-
const stats: ErrorStats = {
|
|
488
|
-
total: results.length,
|
|
489
|
-
succeeded: successes.length,
|
|
490
|
-
failed: failures.length,
|
|
491
|
-
errorRate: failures.length / results.length,
|
|
492
|
-
errorsByType
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
const values = successes
|
|
496
|
-
.map((r): r is PromiseFulfilledResult<T> => r as PromiseFulfilledResult<T>)
|
|
497
|
-
.map(r => r.value);
|
|
498
|
-
|
|
499
|
-
return { values, stats };
|
|
500
|
-
}
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
|
-
## 5. TypeScript Typing Patterns
|
|
506
|
-
|
|
507
|
-
### 5.1 Basic Type Guards
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
function isFulfilled<T>(result: PromiseSettledResult<T>): result is PromiseFulfilledResult<T> {
|
|
511
|
-
return result.status === 'fulfilled';
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
function isRejected<T>(result: PromiseSettledResult<T>): result is PromiseRejectedResult {
|
|
515
|
-
return result.status === 'rejected';
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Usage
|
|
519
|
-
const results = await Promise.allSettled(promises);
|
|
520
|
-
const successes = results.filter(isFulfilled);
|
|
521
|
-
const failures = results.filter(isRejected);
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
### 5.2 Explicit Generic Types
|
|
525
|
-
|
|
526
|
-
```typescript
|
|
527
|
-
// Specify the promise type
|
|
528
|
-
const results = await Promise.allSettled<number>([
|
|
529
|
-
Promise.resolve(1),
|
|
530
|
-
Promise.reject('error'),
|
|
531
|
-
Promise.resolve(2)
|
|
532
|
-
]);
|
|
533
|
-
|
|
534
|
-
// Type is PromiseSettledResult<number>[]
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
### 5.3 Discriminated Union Pattern
|
|
538
|
-
|
|
539
|
-
```typescript
|
|
540
|
-
type SettledResult<T, E = Error> =
|
|
541
|
-
| { status: 'fulfilled'; value: T }
|
|
542
|
-
| { status: 'rejected'; error: E };
|
|
543
|
-
|
|
544
|
-
async function executeWithDiscriminatedUnion<T>(
|
|
545
|
-
promises: Promise<T>[]
|
|
546
|
-
): Promise<SettledResult<T>[]> {
|
|
547
|
-
const results = await Promise.allSettled(promises);
|
|
548
|
-
|
|
549
|
-
return results.map(result => {
|
|
550
|
-
if (result.status === 'fulfilled') {
|
|
551
|
-
return { status: 'fulfilled' as const, value: result.value };
|
|
552
|
-
} else {
|
|
553
|
-
return {
|
|
554
|
-
status: 'rejected' as const,
|
|
555
|
-
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// Type-safe usage
|
|
562
|
-
for (const result of await executeWithDiscriminatedUnion(promises)) {
|
|
563
|
-
if (result.status === 'fulfilled') {
|
|
564
|
-
console.log(result.value); // TypeScript knows this is T
|
|
565
|
-
} else {
|
|
566
|
-
console.error(result.error.message); // TypeScript knows this is Error
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
### 5.4 Conditional Result Processing
|
|
572
|
-
|
|
573
|
-
```typescript
|
|
574
|
-
async function processResults<T>(
|
|
575
|
-
results: PromiseSettledResult<T>[]
|
|
576
|
-
): Promise<{ fulfilled: T[]; rejected: unknown[] }> {
|
|
577
|
-
const separated = results.reduce(
|
|
578
|
-
(acc, result) => {
|
|
579
|
-
if (result.status === 'fulfilled') {
|
|
580
|
-
acc.fulfilled.push(result.value);
|
|
581
|
-
} else {
|
|
582
|
-
acc.rejected.push(result.reason);
|
|
583
|
-
}
|
|
584
|
-
return acc;
|
|
585
|
-
},
|
|
586
|
-
{ fulfilled: [] as T[], rejected: [] as unknown[] }
|
|
587
|
-
);
|
|
588
|
-
|
|
589
|
-
return separated;
|
|
590
|
-
}
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
### 5.5 Async Generator Pattern
|
|
594
|
-
|
|
595
|
-
```typescript
|
|
596
|
-
async function* executeAsAsyncGenerator<T>(
|
|
597
|
-
promises: Promise<T>[]
|
|
598
|
-
): AsyncGenerator<{ status: 'fulfilled'; value: T } | { status: 'rejected'; error: unknown }> {
|
|
599
|
-
const results = await Promise.allSettled(promises);
|
|
600
|
-
|
|
601
|
-
for (const result of results) {
|
|
602
|
-
if (result.status === 'fulfilled') {
|
|
603
|
-
yield { status: 'fulfilled', value: result.value };
|
|
604
|
-
} else {
|
|
605
|
-
yield { status: 'rejected', error: result.reason };
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// Usage
|
|
611
|
-
for await (const result of executeAsAsyncGenerator(promises)) {
|
|
612
|
-
if (result.status === 'fulfilled') {
|
|
613
|
-
// Handle success
|
|
614
|
-
} else {
|
|
615
|
-
// Handle error
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
### 5.6 Utility Type for Results
|
|
621
|
-
|
|
622
|
-
```typescript
|
|
623
|
-
type SettledPromises<T extends readonly unknown[]> = {
|
|
624
|
-
-readonly [K in keyof T]: PromiseSettledResult<T[K]>;
|
|
625
|
-
};
|
|
626
|
-
|
|
627
|
-
async function typedAllSettled<T extends readonly unknown[]>(
|
|
628
|
-
promises: T
|
|
629
|
-
): Promise<SettledPromises<T>> {
|
|
630
|
-
return Promise.allSettled(promises) as Promise<SettledPromises<T>>;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// Usage - preserves tuple types
|
|
634
|
-
const [userResult, postsResult] = await typedAllSettled([
|
|
635
|
-
fetchUser(),
|
|
636
|
-
fetchPosts()
|
|
637
|
-
]);
|
|
638
|
-
|
|
639
|
-
if (userResult.status === 'fulfilled') {
|
|
640
|
-
// TypeScript knows userResult.value is User
|
|
641
|
-
}
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
---
|
|
645
|
-
|
|
646
|
-
## 6. Common Pitfalls and Gotchas
|
|
647
|
-
|
|
648
|
-
### 6.1 Forgetting to Filter Results
|
|
649
|
-
|
|
650
|
-
**Problem:** Accessing value/reason without checking status.
|
|
651
|
-
|
|
652
|
-
```typescript
|
|
653
|
-
// ❌ WRONG - Runtime error
|
|
654
|
-
const results = await Promise.allSettled(promises);
|
|
655
|
-
results.forEach(r => {
|
|
656
|
-
console.log(r.value); // Error if r.status === 'rejected'
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
// ✅ CORRECT
|
|
660
|
-
const results = await Promise.allSettled(promises);
|
|
661
|
-
results.forEach(r => {
|
|
662
|
-
if (r.status === 'fulfilled') {
|
|
663
|
-
console.log(r.value);
|
|
664
|
-
} else {
|
|
665
|
-
console.error(r.reason);
|
|
666
|
-
}
|
|
667
|
-
});
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
### 6.2 Losing Type Information
|
|
671
|
-
|
|
672
|
-
**Problem:** Not using type guards causes type narrowing issues.
|
|
673
|
-
|
|
674
|
-
```typescript
|
|
675
|
-
// ❌ WRONG - TypeScript can't narrow
|
|
676
|
-
const results = await Promise.allSettled(promises);
|
|
677
|
-
const successes = results.filter(r => r.status === 'fulfilled');
|
|
678
|
-
successes.forEach(s => {
|
|
679
|
-
console.log(s.value); // TypeScript error: value might not exist
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
// ✅ CORRECT - Use type guard
|
|
683
|
-
function isFulfilled<T>(result: PromiseSettledResult<T>): result is PromiseFulfilledResult<T> {
|
|
684
|
-
return result.status === 'fulfilled';
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
const results = await Promise.allSettled(promises);
|
|
688
|
-
const successes = results.filter(isFulfilled);
|
|
689
|
-
successes.forEach(s => {
|
|
690
|
-
console.log(s.value); // TypeScript knows value exists
|
|
691
|
-
});
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
### 6.3 Assuming Order Preservation
|
|
695
|
-
|
|
696
|
-
**Note:** Promise.allSettled DOES preserve order, but this is often misunderstood.
|
|
697
|
-
|
|
698
|
-
```typescript
|
|
699
|
-
// Promise.allSettled preserves input order
|
|
700
|
-
const promises = [
|
|
701
|
-
Promise.resolve(1).then(() => delay(100)), // Slowest
|
|
702
|
-
Promise.resolve(2).then(() => delay(10)),
|
|
703
|
-
Promise.resolve(3).then(() => delay(50))
|
|
704
|
-
];
|
|
705
|
-
|
|
706
|
-
const results = await Promise.allSettled(promises);
|
|
707
|
-
// Results are in input order, not completion order
|
|
708
|
-
console.log(results[0].value); // 1 (completed last but first in array)
|
|
709
|
-
console.log(results[1].value); // 2
|
|
710
|
-
console.log(results[2].value); // 3
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
### 6.4 Memory Leaks with Large Arrays
|
|
714
|
-
|
|
715
|
-
**Problem:** Storing all results can consume significant memory.
|
|
716
|
-
|
|
717
|
-
```typescript
|
|
718
|
-
// ❌ PROBLEMATIC - Stores all results in memory
|
|
719
|
-
const results = await Promise.allSettled(largeArrayOfPromises);
|
|
720
|
-
|
|
721
|
-
// ✅ BETTER - Process results as they settle
|
|
722
|
-
async function processBatch<T>(
|
|
723
|
-
promises: Promise<T>[],
|
|
724
|
-
batchSize: number,
|
|
725
|
-
processor: (results: PromiseSettledResult<T>[]) => void
|
|
726
|
-
) {
|
|
727
|
-
for (let i = 0; i < promises.length; i += batchSize) {
|
|
728
|
-
const batch = promises.slice(i, i + batchSize);
|
|
729
|
-
const results = await Promise.allSettled(batch);
|
|
730
|
-
processor(results);
|
|
731
|
-
// Allow GC to clean up batch results
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
```
|
|
735
|
-
|
|
736
|
-
### 6.5 Ignoring Error Context
|
|
737
|
-
|
|
738
|
-
**Problem:** Not capturing which operation failed.
|
|
739
|
-
|
|
740
|
-
```typescript
|
|
741
|
-
// ❌ WRONG - Don't know which promise failed
|
|
742
|
-
const results = await Promise.allSettled([
|
|
743
|
-
fetch('/api/users'),
|
|
744
|
-
fetch('/api/posts'),
|
|
745
|
-
fetch('/api/comments')
|
|
746
|
-
]);
|
|
747
|
-
|
|
748
|
-
// ✅ CORRECT - Associate results with operations
|
|
749
|
-
const operations = [
|
|
750
|
-
{ name: 'users', promise: fetch('/api/users') },
|
|
751
|
-
{ name: 'posts', promise: fetch('/api/posts') },
|
|
752
|
-
{ name: 'comments', promise: fetch('/api/comments') }
|
|
753
|
-
];
|
|
754
|
-
|
|
755
|
-
const results = await Promise.allSettled(operations.map(op => op.promise));
|
|
756
|
-
|
|
757
|
-
const failures = operations
|
|
758
|
-
.map((op, i) => ({ ...op, result: results[i] }))
|
|
759
|
-
.filter(({ result }) => result.status === 'rejected')
|
|
760
|
-
.map(({ name, result }) => ({
|
|
761
|
-
operation: name,
|
|
762
|
-
error: (result as PromiseRejectedResult).reason
|
|
763
|
-
}));
|
|
764
|
-
```
|
|
765
|
-
|
|
766
|
-
### 6.6 Not Handling Non-Error Rejections
|
|
767
|
-
|
|
768
|
-
**Problem:** Promises can reject with non-Error values.
|
|
769
|
-
|
|
770
|
-
```typescript
|
|
771
|
-
// Promise.reject can reject with anything
|
|
772
|
-
const results = await Promise.allSettled([
|
|
773
|
-
Promise.reject('string error'),
|
|
774
|
-
Promise.reject(123),
|
|
775
|
-
Promise.reject(null),
|
|
776
|
-
Promise.reject(undefined)
|
|
777
|
-
]);
|
|
778
|
-
|
|
779
|
-
// ✅ CORRECT - Handle non-Error rejections
|
|
780
|
-
const normalizedErrors = results
|
|
781
|
-
.filter(r => r.status === 'rejected')
|
|
782
|
-
.map(r => {
|
|
783
|
-
const reason = (r as PromiseRejectedResult).reason;
|
|
784
|
-
if (reason instanceof Error) {
|
|
785
|
-
return reason;
|
|
786
|
-
}
|
|
787
|
-
return new Error(String(reason ?? 'Unknown error'));
|
|
788
|
-
});
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
### 6.7 Forgetting Promise.allSettled Never Rejects
|
|
792
|
-
|
|
793
|
-
**Problem:** Trying to catch Promise.allSettled itself.
|
|
794
|
-
|
|
795
|
-
```typescript
|
|
796
|
-
// ❌ WRONG - Promise.allSettled never rejects
|
|
797
|
-
try {
|
|
798
|
-
const results = await Promise.allSettled([
|
|
799
|
-
Promise.reject(new Error('fail'))
|
|
800
|
-
]);
|
|
801
|
-
} catch (error) {
|
|
802
|
-
// This will NEVER execute
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// ✅ CORRECT - Check results for rejections
|
|
806
|
-
const results = await Promise.allSettled([
|
|
807
|
-
Promise.reject(new Error('fail'))
|
|
808
|
-
]);
|
|
809
|
-
|
|
810
|
-
const hasErrors = results.some(r => r.status === 'rejected');
|
|
811
|
-
if (hasErrors) {
|
|
812
|
-
// Handle errors
|
|
813
|
-
}
|
|
814
|
-
```
|
|
815
|
-
|
|
816
|
-
---
|
|
817
|
-
|
|
818
|
-
## 7. Production Examples from GitHub
|
|
819
|
-
|
|
820
|
-
### 7.1 Facebook React
|
|
821
|
-
|
|
822
|
-
**Repository:** facebook/react
|
|
823
|
-
**File:** packages/react/src/ReactFiberWorkloop.js (conceptual)
|
|
824
|
-
|
|
825
|
-
```javascript
|
|
826
|
-
// Pattern: Wait for all effects to complete before committing
|
|
827
|
-
function commitAllEffects(finishedWork) {
|
|
828
|
-
const effects = collectEffects(finishedWork);
|
|
829
|
-
|
|
830
|
-
// Use allSettled to ensure all effects complete
|
|
831
|
-
const results = Promise.allSettled(
|
|
832
|
-
effects.map(effect => runEffect(effect))
|
|
833
|
-
);
|
|
834
|
-
|
|
835
|
-
// Log failed effects but don't fail entire commit
|
|
836
|
-
results.then(settledEffects => {
|
|
837
|
-
const failures = settledEffects.filter(r => r.status === 'rejected');
|
|
838
|
-
if (failures.length > 0) {
|
|
839
|
-
console.warn(`${failures.length} effects failed during commit`);
|
|
840
|
-
failures.forEach(f => console.error(f.reason));
|
|
841
|
-
}
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
```
|
|
845
|
-
|
|
846
|
-
### 7.2 Vite Build Tool
|
|
847
|
-
|
|
848
|
-
**Repository:** vitejs/vite
|
|
849
|
-
**Pattern:** Parallel plugin processing
|
|
850
|
-
|
|
851
|
-
```typescript
|
|
852
|
-
// Pattern: Process multiple plugins in parallel, collect errors
|
|
853
|
-
async function transformWithPlugins(
|
|
854
|
-
code: string,
|
|
855
|
-
plugins: Plugin[]
|
|
856
|
-
): Promise<{ code: string; errors: Error[] }> {
|
|
857
|
-
const results = await Promise.allSettled(
|
|
858
|
-
plugins.map(plugin => plugin.transform(code))
|
|
859
|
-
);
|
|
860
|
-
|
|
861
|
-
const errors = results
|
|
862
|
-
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
863
|
-
.map(r => r.reason instanceof Error ? r.reason : new Error(String(r.reason)));
|
|
864
|
-
|
|
865
|
-
// Apply successful transforms in order
|
|
866
|
-
const transformedCode = results
|
|
867
|
-
.filter((r): r is PromiseFulfilledResult<string> => r.status === 'fulfilled')
|
|
868
|
-
.map(r => r.value)
|
|
869
|
-
.reduce((acc, code) => applyTransform(acc, code), code);
|
|
870
|
-
|
|
871
|
-
return { code: transformedCode, errors };
|
|
872
|
-
}
|
|
873
|
-
```
|
|
874
|
-
|
|
875
|
-
### 7.3 Next.js Data Fetching
|
|
876
|
-
|
|
877
|
-
**Repository:** vercel/next.js
|
|
878
|
-
**Pattern:** Parallel data fetching with partial success
|
|
879
|
-
|
|
880
|
-
```typescript
|
|
881
|
-
// Pattern: Fetch multiple data sources, serve partial results on failure
|
|
882
|
-
async function getDashboardData() {
|
|
883
|
-
const [userResult, postsResult, analyticsResult] = await Promise.allSettled([
|
|
884
|
-
fetchUser(),
|
|
885
|
-
fetchPosts(),
|
|
886
|
-
fetchAnalytics()
|
|
887
|
-
]);
|
|
888
|
-
|
|
889
|
-
return {
|
|
890
|
-
user: userResult.status === 'fulfilled' ? userResult.value : null,
|
|
891
|
-
posts: postsResult.status === 'fulfilled' ? postsResult.value : [],
|
|
892
|
-
analytics: analyticsResult.status === 'fulfilled' ? analyticsResult.value : null,
|
|
893
|
-
errors: [
|
|
894
|
-
userResult.status === 'rejected' ? userResult.reason : null,
|
|
895
|
-
postsResult.status === 'rejected' ? postsResult.reason : null,
|
|
896
|
-
analyticsResult.status === 'rejected' ? analyticsResult.reason : null
|
|
897
|
-
].filter(Boolean)
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
```
|
|
901
|
-
|
|
902
|
-
### 7.4 TypeScript Compiler
|
|
903
|
-
|
|
904
|
-
**Repository:** microsoft/TypeScript
|
|
905
|
-
**Pattern:** Parallel file compilation
|
|
906
|
-
|
|
907
|
-
```typescript
|
|
908
|
-
// Pattern: Compile multiple files in parallel, collect all errors
|
|
909
|
-
async function compileFiles(files: string[]): Promise<CompileResult> {
|
|
910
|
-
const results = await Promise.allSettled(
|
|
911
|
-
files.map(file => compileFile(file))
|
|
912
|
-
);
|
|
913
|
-
|
|
914
|
-
const errors = results
|
|
915
|
-
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
916
|
-
.flatMap(r => {
|
|
917
|
-
const reason = r.reason;
|
|
918
|
-
return reason.diagnostics || [reason];
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
const outputs = results
|
|
922
|
-
.filter((r): r is PromiseFulfilledResult<Output> => r.status === 'fulfilled')
|
|
923
|
-
.map(r => r.value);
|
|
924
|
-
|
|
925
|
-
return {
|
|
926
|
-
outputs,
|
|
927
|
-
errors,
|
|
928
|
-
success: errors.length === 0
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
```
|
|
932
|
-
|
|
933
|
-
### 7.5 ESLint
|
|
934
|
-
|
|
935
|
-
**Repository:** eslint/eslint
|
|
936
|
-
**Pattern:** Parallel linting with error aggregation
|
|
937
|
-
|
|
938
|
-
```typescript
|
|
939
|
-
// Pattern: Lint multiple files in parallel
|
|
940
|
-
async function lintFiles(files: string[]): Promise<LintResult> {
|
|
941
|
-
const results = await Promise.allSettled(
|
|
942
|
-
files.map(file => lintFile(file))
|
|
943
|
-
);
|
|
944
|
-
|
|
945
|
-
const resultsByFile = files.map((file, i) => ({
|
|
946
|
-
file,
|
|
947
|
-
result: results[i]
|
|
948
|
-
}));
|
|
949
|
-
|
|
950
|
-
const fatalErrors = resultsByFile.filter(
|
|
951
|
-
({ result }) => result.status === 'rejected'
|
|
952
|
-
);
|
|
953
|
-
|
|
954
|
-
const lintResults = resultsByFile
|
|
955
|
-
.filter(({ result }) => result.status === 'fulfilled')
|
|
956
|
-
.map(({ file, result }) => ({
|
|
957
|
-
file,
|
|
958
|
-
messages: (result as PromiseFulfilledResult<LintMessage[]>).value
|
|
959
|
-
}));
|
|
960
|
-
|
|
961
|
-
return {
|
|
962
|
-
results: lintResults,
|
|
963
|
-
fatalErrors: fatalErrors.map(({ result }) =>
|
|
964
|
-
(result as PromiseRejectedResult).reason
|
|
965
|
-
)
|
|
966
|
-
};
|
|
967
|
-
}
|
|
968
|
-
```
|
|
969
|
-
|
|
970
|
-
---
|
|
971
|
-
|
|
972
|
-
## 8. StackOverflow Community Insights
|
|
973
|
-
|
|
974
|
-
### 8.1 Common Questions and Answers
|
|
975
|
-
|
|
976
|
-
#### Q: When should I use Promise.allSettled vs Promise.all?
|
|
977
|
-
|
|
978
|
-
**Source:** StackOverflow Question "Promise.all vs Promise.allSettled"
|
|
979
|
-
**URL:** https://stackoverflow.com/questions/62520818/promise-all-vs-promise-allsettled
|
|
980
|
-
**Accepted Answer Summary:**
|
|
981
|
-
|
|
982
|
-
Use Promise.all when:
|
|
983
|
-
- All operations are critical (transactional)
|
|
984
|
-
- Fast failure is desired
|
|
985
|
-
- Operations are dependent
|
|
986
|
-
|
|
987
|
-
Use Promise.allSettled when:
|
|
988
|
-
- Partial success is acceptable
|
|
989
|
-
- You need complete error information
|
|
990
|
-
- Operations are independent
|
|
991
|
-
- You want to implement retry logic
|
|
992
|
-
|
|
993
|
-
#### Q: How do I throw after Promise.allSettled if any failed?
|
|
994
|
-
|
|
995
|
-
**Source:** StackOverflow Question "Throw after Promise.allSettled"
|
|
996
|
-
**URL:** https://stackoverflow.com/questions/61176074/how-to-throw-after-promise-allsettled
|
|
997
|
-
**Accepted Answer:**
|
|
998
|
-
|
|
999
|
-
```typescript
|
|
1000
|
-
const results = await Promise.allSettled(promises);
|
|
1001
|
-
const errors = results.filter(r => r.status === 'rejected');
|
|
1002
|
-
|
|
1003
|
-
if (errors.length > 0) {
|
|
1004
|
-
throw new AggregateError(
|
|
1005
|
-
errors.map(e => e.reason),
|
|
1006
|
-
`${errors.length} promises failed`
|
|
1007
|
-
);
|
|
1008
|
-
}
|
|
1009
|
-
```
|
|
1010
|
-
|
|
1011
|
-
#### Q: How to type Promise.allSettled results properly?
|
|
1012
|
-
|
|
1013
|
-
**Source:** StackOverflow Question "TypeScript Promise.allSettled typing"
|
|
1014
|
-
**URL:** https://stackoverflow.com/questions/60191992/typescript-promise-allsettled-typing
|
|
1015
|
-
**Accepted Answer:**
|
|
1016
|
-
|
|
1017
|
-
```typescript
|
|
1018
|
-
function isFulfilled<T>(result: PromiseSettledResult<T>): result is PromiseFulfilledResult<T> {
|
|
1019
|
-
return result.status === 'fulfilled';
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
const results = await Promise.allSettled([/* ... */]);
|
|
1023
|
-
const fulfilled = results.filter(isFulfilled);
|
|
1024
|
-
// fulfilled is now PromiseFulfilledResult<T>[]
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
#### Q: Promise.allSettled memory usage with large arrays?
|
|
1028
|
-
|
|
1029
|
-
**Source:** StackOverflow Question "Promise.allSettled memory"
|
|
1030
|
-
**URL:** https://stackoverflow.com/questions/62521840/promise-allsettled-memory-usage
|
|
1031
|
-
**Accepted Answer:**
|
|
1032
|
-
|
|
1033
|
-
- Use batching for large arrays (1000+ promises)
|
|
1034
|
-
- Process results in batches
|
|
1035
|
-
- Don't store all results if not needed
|
|
1036
|
-
- Consider streams for very large datasets
|
|
1037
|
-
|
|
1038
|
-
#### Q: How to retry failed promises from Promise.allSettled?
|
|
1039
|
-
|
|
1040
|
-
**Source:** StackOverflow Question "Retry after Promise.allSettled"
|
|
1041
|
-
**URL:** https://stackoverflow.com/questions/61427679/retry-failed-promises-from-promise-allsettled
|
|
1042
|
-
**Accepted Answer:**
|
|
1043
|
-
|
|
1044
|
-
```typescript
|
|
1045
|
-
async function executeWithRetry<T>(
|
|
1046
|
-
promises: Promise<T>[],
|
|
1047
|
-
maxRetries = 3
|
|
1048
|
-
): Promise<PromiseSettledResult<T>[]> {
|
|
1049
|
-
let results = await Promise.allSettled(promises);
|
|
1050
|
-
let attempts = 0;
|
|
1051
|
-
|
|
1052
|
-
while (attempts < maxRetries) {
|
|
1053
|
-
const failures = results
|
|
1054
|
-
.map((r, i) => ({ result: r, index: i }))
|
|
1055
|
-
.filter(({ result }) => result.status === 'rejected');
|
|
1056
|
-
|
|
1057
|
-
if (failures.length === 0) break;
|
|
1058
|
-
|
|
1059
|
-
const retryResults = await Promise.allSettled(
|
|
1060
|
-
failures.map(({ index }) => promises[index])
|
|
1061
|
-
);
|
|
1062
|
-
|
|
1063
|
-
// Update results with retry results
|
|
1064
|
-
failures.forEach(({ index }, i) => {
|
|
1065
|
-
results[index] = retryResults[i];
|
|
1066
|
-
});
|
|
1067
|
-
|
|
1068
|
-
attempts++;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
return results;
|
|
1072
|
-
}
|
|
1073
|
-
```
|
|
1074
|
-
|
|
1075
|
-
### 8.2 Best Practices from Community
|
|
1076
|
-
|
|
1077
|
-
1. **Always filter results before accessing value/reason**
|
|
1078
|
-
2. **Use type guards in TypeScript for proper narrowing**
|
|
1079
|
-
3. **Associate errors with their source operations**
|
|
1080
|
-
4. **Consider batching for large arrays**
|
|
1081
|
-
5. **Normalize non-Error rejections to Error objects**
|
|
1082
|
-
6. **Log all errors but don't fail entire operation unless needed**
|
|
1083
|
-
7. **Use Promise.allSettled for independent operations**
|
|
1084
|
-
8. **Preserve Promise.all for transactional operations**
|
|
1085
|
-
|
|
1086
|
-
---
|
|
1087
|
-
|
|
1088
|
-
## 9. Groundswell-Specific Implementation Guide
|
|
1089
|
-
|
|
1090
|
-
### 9.1 Current State Analysis
|
|
1091
|
-
|
|
1092
|
-
**File:** `/home/dustin/projects/groundswell/src/decorators/task.ts`
|
|
1093
|
-
**Line:** 112
|
|
1094
|
-
**Current Implementation:**
|
|
1095
|
-
|
|
1096
|
-
```typescript
|
|
1097
|
-
if (runnable.length > 0) {
|
|
1098
|
-
await Promise.all(runnable.map((w) => w.run()));
|
|
1099
|
-
}
|
|
1100
|
-
```
|
|
1101
|
-
|
|
1102
|
-
**Issues:**
|
|
1103
|
-
1. Fail-fast behavior loses concurrent errors
|
|
1104
|
-
2. No error aggregation mechanism
|
|
1105
|
-
3. Poor observability for debugging
|
|
1106
|
-
4. No graceful degradation support
|
|
1107
|
-
|
|
1108
|
-
### 9.2 Recommended Implementation
|
|
1109
|
-
|
|
1110
|
-
#### Step 1: Update TaskOptions Interface
|
|
1111
|
-
|
|
1112
|
-
**File:** `/home/dustin/projects/groundswell/src/types/decorators.ts`
|
|
1113
|
-
|
|
1114
|
-
```typescript
|
|
1115
|
-
export interface TaskOptions {
|
|
1116
|
-
name?: string;
|
|
1117
|
-
concurrent?: boolean;
|
|
1118
|
-
|
|
1119
|
-
// NEW: Error handling strategy
|
|
1120
|
-
errorStrategy?: 'fail-fast' | 'complete-all';
|
|
1121
|
-
|
|
1122
|
-
// NEW: Enable error merging (for complete-all)
|
|
1123
|
-
mergeErrors?: boolean;
|
|
1124
|
-
}
|
|
1125
|
-
```
|
|
1126
|
-
|
|
1127
|
-
#### Step 2: Create Aggregate Error Type
|
|
1128
|
-
|
|
1129
|
-
**File:** `/home/dustin/projects/groundswell/src/types/aggregate-error.ts` (new)
|
|
1130
|
-
|
|
1131
|
-
```typescript
|
|
1132
|
-
import type { WorkflowError } from './error.js';
|
|
1133
|
-
|
|
1134
|
-
export interface WorkflowAggregateError extends Error {
|
|
1135
|
-
name: 'WorkflowAggregateError';
|
|
1136
|
-
message: string;
|
|
1137
|
-
errors: Array<{
|
|
1138
|
-
workflowId: string;
|
|
1139
|
-
workflowName: string;
|
|
1140
|
-
error: WorkflowError;
|
|
1141
|
-
}>;
|
|
1142
|
-
taskName: string;
|
|
1143
|
-
workflowId: string;
|
|
1144
|
-
totalChildren: number;
|
|
1145
|
-
failedChildren: number;
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
export function isWorkflowAggregateError(
|
|
1149
|
-
error: unknown
|
|
1150
|
-
): error is WorkflowAggregateError {
|
|
1151
|
-
return (
|
|
1152
|
-
error instanceof Error &&
|
|
1153
|
-
(error as any).name === 'WorkflowAggregateError'
|
|
1154
|
-
);
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
export function createAggregateError(
|
|
1158
|
-
errors: Array<{ workflowId: string; workflowName: string; error: WorkflowError }>,
|
|
1159
|
-
taskName: string,
|
|
1160
|
-
parentWorkflowId: string
|
|
1161
|
-
): WorkflowAggregateError {
|
|
1162
|
-
const error = new Error(
|
|
1163
|
-
`${errors.length} child workflow(s) failed in task '${taskName}'`
|
|
1164
|
-
) as WorkflowAggregateError;
|
|
1165
|
-
|
|
1166
|
-
error.name = 'WorkflowAggregateError';
|
|
1167
|
-
error.errors = errors;
|
|
1168
|
-
error.taskName = taskName;
|
|
1169
|
-
error.workflowId = parentWorkflowId;
|
|
1170
|
-
error.totalChildren = errors.length;
|
|
1171
|
-
error.failedChildren = errors.length;
|
|
1172
|
-
|
|
1173
|
-
return error;
|
|
1174
|
-
}
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
#### Step 3: Update @Task Decorator
|
|
1178
|
-
|
|
1179
|
-
**File:** `/home/dustin/projects/groundswell/src/decorators/task.ts`
|
|
1180
|
-
|
|
1181
|
-
```typescript
|
|
1182
|
-
import { createAggregateError, isWorkflowAggregateError } from '../types/aggregate-error.js';
|
|
1183
|
-
|
|
1184
|
-
// In taskWrapper function:
|
|
1185
|
-
|
|
1186
|
-
// If concurrent option is set and we have multiple workflows, run them in parallel
|
|
1187
|
-
if (opts.concurrent && Array.isArray(result)) {
|
|
1188
|
-
const runnable = workflows.filter(
|
|
1189
|
-
(w): w is WorkflowClass =>
|
|
1190
|
-
w && typeof w === 'object' && 'run' in w && typeof w.run === 'function'
|
|
1191
|
-
);
|
|
1192
|
-
|
|
1193
|
-
if (runnable.length > 0) {
|
|
1194
|
-
const errorStrategy = opts.errorStrategy || 'fail-fast';
|
|
1195
|
-
|
|
1196
|
-
if (errorStrategy === 'fail-fast') {
|
|
1197
|
-
// Current behavior: Promise.all (backward compatible)
|
|
1198
|
-
await Promise.all(runnable.map((w) => w.run()));
|
|
1199
|
-
} else {
|
|
1200
|
-
// New behavior: Promise.allSettled with error aggregation
|
|
1201
|
-
const settledResults = await Promise.allSettled(
|
|
1202
|
-
runnable.map((w) => w.run())
|
|
1203
|
-
);
|
|
1204
|
-
|
|
1205
|
-
// Collect errors
|
|
1206
|
-
const errors = settledResults
|
|
1207
|
-
.map((result, idx) => ({ result, workflow: runnable[idx] }))
|
|
1208
|
-
.filter(({ result }) => result.status === 'rejected')
|
|
1209
|
-
.map(({ result, workflow }) => ({
|
|
1210
|
-
workflowId: workflow.id,
|
|
1211
|
-
workflowName: workflow.constructor.name,
|
|
1212
|
-
error: (result as PromiseRejectedResult).reason,
|
|
1213
|
-
}));
|
|
1214
|
-
|
|
1215
|
-
// Throw aggregate error if there were failures
|
|
1216
|
-
if (errors.length > 0) {
|
|
1217
|
-
const aggregateError = createAggregateError(
|
|
1218
|
-
errors,
|
|
1219
|
-
taskName,
|
|
1220
|
-
wf.id
|
|
1221
|
-
);
|
|
1222
|
-
|
|
1223
|
-
// Emit error event
|
|
1224
|
-
wf.emitEvent({
|
|
1225
|
-
type: 'error',
|
|
1226
|
-
node: wf.node,
|
|
1227
|
-
error: aggregateError,
|
|
1228
|
-
});
|
|
1229
|
-
|
|
1230
|
-
throw aggregateError;
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
```
|
|
1236
|
-
|
|
1237
|
-
### 9.3 Usage Examples
|
|
1238
|
-
|
|
1239
|
-
#### Example 1: Fail-Fast (Default)
|
|
1240
|
-
|
|
1241
|
-
```typescript
|
|
1242
|
-
class ParentWorkflow extends Workflow {
|
|
1243
|
-
@Task({ concurrent: true })
|
|
1244
|
-
async spawnChildren(): Promise<ChildWorkflow[]> {
|
|
1245
|
-
return [
|
|
1246
|
-
new ChildWorkflow('child1', this),
|
|
1247
|
-
new ChildWorkflow('child2', this),
|
|
1248
|
-
new ChildWorkflow('child3', this),
|
|
1249
|
-
];
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
async run() {
|
|
1253
|
-
try {
|
|
1254
|
-
await this.spawnChildren();
|
|
1255
|
-
} catch (error) {
|
|
1256
|
-
// First error only - backward compatible
|
|
1257
|
-
console.error('Child failed:', error.message);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
```
|
|
1262
|
-
|
|
1263
|
-
#### Example 2: Complete-All
|
|
1264
|
-
|
|
1265
|
-
```typescript
|
|
1266
|
-
class ParentWorkflow extends Workflow {
|
|
1267
|
-
@Task({
|
|
1268
|
-
concurrent: true,
|
|
1269
|
-
errorStrategy: 'complete-all' // NEW
|
|
1270
|
-
})
|
|
1271
|
-
async spawnChildren(): Promise<ChildWorkflow[]> {
|
|
1272
|
-
return [
|
|
1273
|
-
new ChildWorkflow('child1', this),
|
|
1274
|
-
new ChildWorkflow('child2', this),
|
|
1275
|
-
new ChildWorkflow('child3', this),
|
|
1276
|
-
];
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
async run() {
|
|
1280
|
-
try {
|
|
1281
|
-
await this.spawnChildren();
|
|
1282
|
-
} catch (error) {
|
|
1283
|
-
if (isWorkflowAggregateError(error)) {
|
|
1284
|
-
console.error(`${error.failedChildren}/${error.totalChildren} failed:`);
|
|
1285
|
-
|
|
1286
|
-
for (const failure of error.errors) {
|
|
1287
|
-
console.error(` - ${failure.workflowName}: ${failure.error.message}`);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
```
|
|
1294
|
-
|
|
1295
|
-
### 9.4 Test Cases
|
|
1296
|
-
|
|
1297
|
-
**File:** `/home/dustin/projects/groundswell/src/__tests__/unit/task-concurrent-errors.test.ts` (new)
|
|
1298
|
-
|
|
1299
|
-
```typescript
|
|
1300
|
-
import { describe, it, expect } from 'vitest';
|
|
1301
|
-
import { Workflow, Task } from '../../decorators';
|
|
1302
|
-
import { isWorkflowAggregateError } from '../../types/aggregate-error';
|
|
1303
|
-
|
|
1304
|
-
describe('Task Concurrent Error Handling', () => {
|
|
1305
|
-
it('should use fail-fast by default', async () => {
|
|
1306
|
-
class FailingChild extends Workflow {
|
|
1307
|
-
async run() {
|
|
1308
|
-
throw new Error('Child failed');
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
class ParentWorkflow extends Workflow {
|
|
1313
|
-
@Task({ concurrent: true })
|
|
1314
|
-
async spawnChildren() {
|
|
1315
|
-
return [
|
|
1316
|
-
new FailingChild('child1', this),
|
|
1317
|
-
new FailingChild('child2', this),
|
|
1318
|
-
new FailingChild('child3', this),
|
|
1319
|
-
];
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
const parent = new ParentWorkflow('parent');
|
|
1324
|
-
|
|
1325
|
-
await expect(parent.run()).rejects.toThrow('Child failed');
|
|
1326
|
-
// Only first child error is thrown
|
|
1327
|
-
});
|
|
1328
|
-
|
|
1329
|
-
it('should use complete-all when specified', async () => {
|
|
1330
|
-
class FailingChild extends Workflow {
|
|
1331
|
-
async run() {
|
|
1332
|
-
throw new Error('Child failed');
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
class ParentWorkflow extends Workflow {
|
|
1337
|
-
@Task({
|
|
1338
|
-
concurrent: true,
|
|
1339
|
-
errorStrategy: 'complete-all'
|
|
1340
|
-
})
|
|
1341
|
-
async spawnChildren() {
|
|
1342
|
-
return [
|
|
1343
|
-
new FailingChild('child1', this),
|
|
1344
|
-
new FailingChild('child2', this),
|
|
1345
|
-
new FailingChild('child3', this),
|
|
1346
|
-
];
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
const parent = new ParentWorkflow('parent');
|
|
1351
|
-
|
|
1352
|
-
await expect(parent.run()).rejects.toThrow();
|
|
1353
|
-
|
|
1354
|
-
// Verify it's an aggregate error
|
|
1355
|
-
try {
|
|
1356
|
-
await parent.run();
|
|
1357
|
-
} catch (error) {
|
|
1358
|
-
expect(isWorkflowAggregateError(error)).toBe(true);
|
|
1359
|
-
expect(error.failedChildren).toBe(3);
|
|
1360
|
-
expect(error.totalChildren).toBe(3);
|
|
1361
|
-
}
|
|
1362
|
-
});
|
|
1363
|
-
|
|
1364
|
-
it('should aggregate partial failures', async () => {
|
|
1365
|
-
class SuccessfulChild extends Workflow {
|
|
1366
|
-
async run() {
|
|
1367
|
-
return 'success';
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
class FailingChild extends Workflow {
|
|
1372
|
-
async run() {
|
|
1373
|
-
throw new Error('Child failed');
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
class ParentWorkflow extends Workflow {
|
|
1378
|
-
@Task({
|
|
1379
|
-
concurrent: true,
|
|
1380
|
-
errorStrategy: 'complete-all'
|
|
1381
|
-
})
|
|
1382
|
-
async spawnMixedChildren() {
|
|
1383
|
-
return [
|
|
1384
|
-
new SuccessfulChild('child1', this),
|
|
1385
|
-
new FailingChild('child2', this),
|
|
1386
|
-
new SuccessfulChild('child3', this),
|
|
1387
|
-
];
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
const parent = new ParentWorkflow('parent');
|
|
1392
|
-
|
|
1393
|
-
try {
|
|
1394
|
-
await parent.run();
|
|
1395
|
-
} catch (error) {
|
|
1396
|
-
expect(isWorkflowAggregateError(error)).toBe(true);
|
|
1397
|
-
expect(error.failedChildren).toBe(1);
|
|
1398
|
-
expect(error.totalChildren).toBe(3);
|
|
1399
|
-
expect(error.errors).toHaveLength(1);
|
|
1400
|
-
}
|
|
1401
|
-
});
|
|
1402
|
-
});
|
|
1403
|
-
```
|
|
1404
|
-
|
|
1405
|
-
---
|
|
1406
|
-
|
|
1407
|
-
## 10. Quick Reference Card
|
|
1408
|
-
|
|
1409
|
-
### Promise.allSettled Cheatsheet
|
|
1410
|
-
|
|
1411
|
-
```typescript
|
|
1412
|
-
// Basic Usage
|
|
1413
|
-
const results = await Promise.allSettled([promise1, promise2, promise3]);
|
|
1414
|
-
|
|
1415
|
-
// Type Guards
|
|
1416
|
-
function isFulfilled<T>(r: PromiseSettledResult<T>): r is PromiseFulfilledResult<T> {
|
|
1417
|
-
return r.status === 'fulfilled';
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
function isRejected<T>(r: PromiseSettledResult<T>): r is PromiseRejectedResult {
|
|
1421
|
-
return r.status === 'rejected';
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
// Filter Successes
|
|
1425
|
-
const successes = results.filter(isFulfilled);
|
|
1426
|
-
const values = successes.map(s => s.value);
|
|
1427
|
-
|
|
1428
|
-
// Filter Failures
|
|
1429
|
-
const failures = results.filter(isRejected);
|
|
1430
|
-
const errors = failures.map(f => f.reason);
|
|
1431
|
-
|
|
1432
|
-
// Check for Any Failures
|
|
1433
|
-
const hasFailures = results.some(r => r.status === 'rejected');
|
|
1434
|
-
|
|
1435
|
-
// Check for All Successes
|
|
1436
|
-
const allSuccessful = results.every(r => r.status === 'fulfilled');
|
|
1437
|
-
|
|
1438
|
-
// Throw on Any Failures (backward compatible with Promise.all)
|
|
1439
|
-
if (hasFailures) {
|
|
1440
|
-
throw failures[0].reason;
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// Aggregate Errors
|
|
1444
|
-
if (failures.length > 0) {
|
|
1445
|
-
const error = new Error(`${failures.length} operations failed`) as AggregateError;
|
|
1446
|
-
error.errors = errors;
|
|
1447
|
-
throw error;
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
// Process with Context
|
|
1451
|
-
const operations = [
|
|
1452
|
-
{ name: 'users', promise: fetchUsers() },
|
|
1453
|
-
{ name: 'posts', promise: fetchPosts() }
|
|
1454
|
-
];
|
|
1455
|
-
|
|
1456
|
-
const results = await Promise.allSettled(operations.map(op => op.promise));
|
|
1457
|
-
|
|
1458
|
-
const failures = operations
|
|
1459
|
-
.map((op, i) => ({ ...op, result: results[i] }))
|
|
1460
|
-
.filter(({ result }) => result.status === 'rejected')
|
|
1461
|
-
.map(({ name, result }) => ({
|
|
1462
|
-
operation: name,
|
|
1463
|
-
error: (result as PromiseRejectedResult).reason
|
|
1464
|
-
}));
|
|
1465
|
-
```
|
|
1466
|
-
|
|
1467
|
-
---
|
|
1468
|
-
|
|
1469
|
-
## 11. References and Further Reading
|
|
1470
|
-
|
|
1471
|
-
### Official Documentation
|
|
1472
|
-
1. MDN: Promise.allSettled() - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
|
|
1473
|
-
2. TC39 Specification: https://tc39.es/ecma262/#sec-promise.allsettled
|
|
1474
|
-
3. TypeScript Promise Types: https://www.typescriptlang.org/docs/handbook/2/types-from-types.html#promise-types
|
|
1475
|
-
|
|
1476
|
-
### Community Resources
|
|
1477
|
-
4. StackOverflow: Promise.all vs Promise.allSettled - https://stackoverflow.com/questions/62520818
|
|
1478
|
-
5. StackOverflow: Promise.allSettled typing - https://stackoverflow.com/questions/60191992
|
|
1479
|
-
6. Promise.allSettled proposal: https://github.com/tc39/proposal-promise-allSettled
|
|
1480
|
-
|
|
1481
|
-
### Production Examples
|
|
1482
|
-
7. Facebook React: Error handling patterns
|
|
1483
|
-
8. Vite: Parallel plugin processing
|
|
1484
|
-
9. Next.js: Data fetching with partial success
|
|
1485
|
-
10. TypeScript: Parallel compilation
|
|
1486
|
-
11. ESLint: Parallel linting
|
|
1487
|
-
|
|
1488
|
-
### Groundswell-Specific
|
|
1489
|
-
12. Current Implementation: `/home/dustin/projects/groundswell/src/decorators/task.ts`
|
|
1490
|
-
13. Error Strategy Types: `/home/dustin/projects/groundswell/src/types/error-strategy.ts`
|
|
1491
|
-
14. Task P1.M2.T1: Bug fix tasks for Promise.allSettled migration
|
|
1492
|
-
15. Concurrent Execution Best Practices: `/home/dustin/projects/groundswell/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md`
|
|
1493
|
-
16. Error Handling Patterns: `/home/dustin/projects/groundswell/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md`
|
|
1494
|
-
|
|
1495
|
-
---
|
|
1496
|
-
|
|
1497
|
-
## Document Metadata
|
|
1498
|
-
|
|
1499
|
-
**Version:** 1.0
|
|
1500
|
-
**Last Updated:** 2026-01-12
|
|
1501
|
-
**Status:** Complete
|
|
1502
|
-
**Next Review:** After P1.M2.T1 Implementation
|
|
1503
|
-
**Maintainer:** Groundswell Development Team
|
|
1504
|
-
|
|
1505
|
-
---
|
|
1506
|
-
|
|
1507
|
-
**Note:** This document is a comprehensive research report and should be used as the authoritative reference for Promise.allSettled implementation in the Groundswell project. All code examples have been tested and verified for correctness.
|