reqon-dsl 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +22 -0
- package/dist/ast/nodes.d.ts +83 -4
- package/dist/ast/nodes.js +14 -0
- package/dist/auth/circuit-breaker.js +7 -6
- package/dist/auth/rate-limiter.d.ts +4 -0
- package/dist/auth/rate-limiter.js +9 -16
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +84 -4
- package/dist/config/constants.d.ts +141 -0
- package/dist/config/constants.js +128 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.js +4 -0
- package/dist/control/index.d.ts +2 -0
- package/dist/control/index.js +1 -0
- package/dist/control/server.d.ts +88 -0
- package/dist/control/server.js +238 -0
- package/dist/control/types.d.ts +55 -0
- package/dist/control/types.js +7 -0
- package/dist/debug/cli-debugger.d.ts +17 -0
- package/dist/debug/cli-debugger.js +180 -0
- package/dist/debug/controller.d.ts +94 -0
- package/dist/debug/controller.js +45 -0
- package/dist/debug/index.d.ts +6 -0
- package/dist/debug/index.js +5 -0
- package/dist/errors/index.d.ts +67 -0
- package/dist/errors/index.js +89 -1
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/state.d.ts +24 -0
- package/dist/index.d.ts +21 -1
- package/dist/index.js +33 -2
- package/dist/interpreter/context.d.ts +14 -0
- package/dist/interpreter/context.js +15 -0
- package/dist/interpreter/evaluator.d.ts +63 -1
- package/dist/interpreter/evaluator.js +186 -39
- package/dist/interpreter/executor.d.ts +70 -14
- package/dist/interpreter/executor.js +503 -174
- package/dist/interpreter/fetch-handler.d.ts +9 -0
- package/dist/interpreter/fetch-handler.js +133 -24
- package/dist/interpreter/http.d.ts +5 -0
- package/dist/interpreter/http.js +26 -12
- package/dist/interpreter/index.d.ts +3 -1
- package/dist/interpreter/index.js +2 -0
- package/dist/interpreter/pagination.d.ts +11 -2
- package/dist/interpreter/pagination.js +95 -31
- package/dist/interpreter/signals.d.ts +8 -0
- package/dist/interpreter/signals.js +12 -0
- package/dist/interpreter/source-manager.d.ts +75 -0
- package/dist/interpreter/source-manager.js +157 -0
- package/dist/interpreter/step-handlers/apply-handler.d.ts +29 -0
- package/dist/interpreter/step-handlers/apply-handler.js +79 -0
- package/dist/interpreter/step-handlers/for-handler.d.ts +13 -0
- package/dist/interpreter/step-handlers/for-handler.js +71 -4
- package/dist/interpreter/step-handlers/index.d.ts +4 -2
- package/dist/interpreter/step-handlers/index.js +4 -2
- package/dist/interpreter/step-handlers/match-handler.d.ts +9 -0
- package/dist/interpreter/step-handlers/match-handler.js +43 -16
- package/dist/interpreter/step-handlers/pause-handler.d.ts +52 -0
- package/dist/interpreter/step-handlers/pause-handler.js +87 -0
- package/dist/interpreter/step-handlers/store-handler.d.ts +11 -1
- package/dist/interpreter/step-handlers/store-handler.js +45 -13
- package/dist/interpreter/step-handlers/types.d.ts +3 -0
- package/dist/interpreter/step-handlers/validate-handler.d.ts +2 -1
- package/dist/interpreter/step-handlers/validate-handler.js +4 -2
- package/dist/interpreter/step-handlers/webhook-handler.d.ts +3 -0
- package/dist/interpreter/step-handlers/webhook-handler.js +18 -2
- package/dist/interpreter/store-manager.d.ts +46 -0
- package/dist/interpreter/store-manager.js +66 -0
- package/dist/lexer/index.d.ts +11 -4
- package/dist/lexer/index.js +11 -4
- package/dist/lexer/tokens.d.ts +17 -1
- package/dist/lexer/tokens.js +36 -0
- package/dist/mcp/index.d.ts +11 -0
- package/dist/mcp/index.js +11 -0
- package/dist/mcp/server.d.ts +17 -0
- package/dist/mcp/server.js +451 -0
- package/dist/oas/index.d.ts +2 -0
- package/dist/oas/index.js +1 -0
- package/dist/oas/mock-generator.d.ts +12 -0
- package/dist/oas/mock-generator.js +187 -0
- package/dist/observability/events.d.ts +244 -0
- package/dist/observability/events.js +90 -0
- package/dist/observability/index.d.ts +15 -0
- package/dist/observability/index.js +12 -0
- package/dist/observability/logger.d.ts +106 -0
- package/dist/observability/logger.js +259 -0
- package/dist/observability/otel.d.ts +135 -0
- package/dist/observability/otel.js +386 -0
- package/dist/parser/action-parser.d.ts +105 -0
- package/dist/parser/action-parser.js +645 -0
- package/dist/parser/expressions.d.ts +13 -0
- package/dist/parser/expressions.js +72 -2
- package/dist/parser/fetch-parser.d.ts +27 -0
- package/dist/parser/fetch-parser.js +269 -0
- package/dist/parser/index.d.ts +17 -0
- package/dist/parser/index.js +17 -0
- package/dist/parser/parser.d.ts +44 -46
- package/dist/parser/parser.js +122 -1070
- package/dist/parser/pipeline-parser.d.ts +12 -0
- package/dist/parser/pipeline-parser.js +52 -0
- package/dist/parser/schedule-parser.d.ts +7 -0
- package/dist/parser/schedule-parser.js +137 -0
- package/dist/parser/source-parser.d.ts +9 -0
- package/dist/parser/source-parser.js +151 -0
- package/dist/pause/index.d.ts +14 -0
- package/dist/pause/index.js +11 -0
- package/dist/pause/manager.d.ts +118 -0
- package/dist/pause/manager.js +245 -0
- package/dist/pause/state.d.ts +93 -0
- package/dist/pause/state.js +103 -0
- package/dist/pause/store.d.ts +61 -0
- package/dist/pause/store.js +156 -0
- package/dist/plugin.d.ts +9 -12
- package/dist/plugin.js +10 -13
- package/dist/stores/factory.d.ts +1 -1
- package/dist/stores/factory.js +3 -2
- package/dist/stores/file.d.ts +26 -0
- package/dist/stores/file.js +64 -10
- package/dist/stores/index.d.ts +16 -1
- package/dist/stores/index.js +16 -1
- package/dist/stores/memory.d.ts +4 -0
- package/dist/stores/memory.js +11 -0
- package/dist/stores/types.d.ts +17 -0
- package/dist/stores/types.js +12 -0
- package/dist/trace/index.d.ts +16 -0
- package/dist/trace/index.js +12 -0
- package/dist/trace/recorder.d.ts +71 -0
- package/dist/trace/recorder.js +144 -0
- package/dist/trace/replay.d.ts +132 -0
- package/dist/trace/replay.js +264 -0
- package/dist/trace/state.d.ts +102 -0
- package/dist/trace/state.js +86 -0
- package/dist/trace/store.d.ts +69 -0
- package/dist/trace/store.js +225 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/type-guards.d.ts +58 -0
- package/dist/utils/type-guards.js +92 -0
- package/dist/webhook/server.js +7 -6
- package/package.json +55 -6
- package/.claude/settings.local.json +0 -31
- package/.claude/skills/api-integration.md +0 -125
- package/.claude/skills/database-schema.md +0 -51
- package/.claude/skills/dsl-design.md +0 -80
- package/.claude/skills/property-testing.md +0 -143
- package/.claude/skills/reqon/SKILL.md +0 -44
- package/.claude/skills/reqon/references/examples.md +0 -206
- package/.claude/skills/reqon/references/syntax.md +0 -263
- package/.claude/skills/vscode-extension.md +0 -113
- package/.github/dependabot.yml +0 -32
- package/.github/pull_request_template.md +0 -21
- package/.github/workflows/ci.yml +0 -174
- package/.github/workflows/release.yml +0 -73
- package/CLAUDE.md +0 -72
- package/CONTRIBUTING.md +0 -161
- package/TODO.md +0 -51
- package/dist/auth/auth.test.d.ts +0 -1
- package/dist/auth/auth.test.js +0 -255
- package/dist/errors/errors.test.d.ts +0 -1
- package/dist/errors/errors.test.js +0 -165
- package/dist/execution/execution.test.d.ts +0 -1
- package/dist/execution/execution.test.js +0 -246
- package/dist/integration.test.d.ts +0 -1
- package/dist/integration.test.js +0 -168
- package/dist/interpreter/evaluator.test.d.ts +0 -1
- package/dist/interpreter/evaluator.test.js +0 -512
- package/dist/interpreter/http.test.d.ts +0 -1
- package/dist/interpreter/http.test.js +0 -299
- package/dist/interpreter/progress.test.d.ts +0 -1
- package/dist/interpreter/progress.test.js +0 -216
- package/dist/interpreter/schema-matcher.test.d.ts +0 -1
- package/dist/interpreter/schema-matcher.test.js +0 -122
- package/dist/lexer/lexer.d.ts +0 -24
- package/dist/lexer/lexer.js +0 -264
- package/dist/lexer/lexer.test.d.ts +0 -1
- package/dist/lexer/lexer.test.js +0 -259
- package/dist/loader/loader.test.d.ts +0 -1
- package/dist/loader/loader.test.js +0 -287
- package/dist/oas/oas.test.d.ts +0 -1
- package/dist/oas/oas.test.js +0 -218
- package/dist/parser/expressions.test.d.ts +0 -1
- package/dist/parser/expressions.test.js +0 -378
- package/dist/parser/match.test.d.ts +0 -1
- package/dist/parser/match.test.js +0 -254
- package/dist/parser/parser.test.d.ts +0 -1
- package/dist/parser/parser.test.js +0 -333
- package/dist/parser/schedule.test.d.ts +0 -1
- package/dist/parser/schedule.test.js +0 -241
- package/dist/scheduler/cron-parser.test.d.ts +0 -1
- package/dist/scheduler/cron-parser.test.js +0 -188
- package/dist/stores/file.test.d.ts +0 -1
- package/dist/stores/file.test.js +0 -165
- package/dist/stores/memory.test.d.ts +0 -1
- package/dist/stores/memory.test.js +0 -157
- package/dist/stores/stores.test.d.ts +0 -1
- package/dist/stores/stores.test.js +0 -158
- package/dist/sync/sync.test.d.ts +0 -1
- package/dist/sync/sync.test.js +0 -221
- package/docusaurus/README.md +0 -41
- package/docusaurus/docs/advanced/execution-state.md +0 -283
- package/docusaurus/docs/advanced/extending-reqon.md +0 -388
- package/docusaurus/docs/advanced/multi-file-missions.md +0 -250
- package/docusaurus/docs/advanced/parallel-execution.md +0 -353
- package/docusaurus/docs/api-reference.md +0 -443
- package/docusaurus/docs/authentication/api-key.md +0 -339
- package/docusaurus/docs/authentication/basic.md +0 -276
- package/docusaurus/docs/authentication/bearer.md +0 -282
- package/docusaurus/docs/authentication/oauth2.md +0 -317
- package/docusaurus/docs/authentication/overview.md +0 -251
- package/docusaurus/docs/cli.md +0 -229
- package/docusaurus/docs/core-concepts/actions.md +0 -286
- package/docusaurus/docs/core-concepts/missions.md +0 -264
- package/docusaurus/docs/core-concepts/schemas.md +0 -353
- package/docusaurus/docs/core-concepts/sources.md +0 -339
- package/docusaurus/docs/core-concepts/stores.md +0 -332
- package/docusaurus/docs/dsl-syntax/expressions.md +0 -361
- package/docusaurus/docs/dsl-syntax/fetch.md +0 -293
- package/docusaurus/docs/dsl-syntax/for-loops.md +0 -324
- package/docusaurus/docs/dsl-syntax/map.md +0 -345
- package/docusaurus/docs/dsl-syntax/match.md +0 -387
- package/docusaurus/docs/dsl-syntax/pipelines.md +0 -397
- package/docusaurus/docs/dsl-syntax/validate.md +0 -401
- package/docusaurus/docs/error-handling/dead-letter-queues.md +0 -399
- package/docusaurus/docs/error-handling/flow-control.md +0 -337
- package/docusaurus/docs/error-handling/retry-strategies.md +0 -368
- package/docusaurus/docs/examples.md +0 -488
- package/docusaurus/docs/getting-started.md +0 -256
- package/docusaurus/docs/http/circuit-breaker.md +0 -401
- package/docusaurus/docs/http/incremental-sync.md +0 -394
- package/docusaurus/docs/http/pagination.md +0 -361
- package/docusaurus/docs/http/rate-limiting.md +0 -383
- package/docusaurus/docs/http/requests.md +0 -328
- package/docusaurus/docs/http/retry.md +0 -402
- package/docusaurus/docs/intro.md +0 -90
- package/docusaurus/docs/openapi/loading-specs.md +0 -305
- package/docusaurus/docs/openapi/operation-calls.md +0 -314
- package/docusaurus/docs/openapi/overview.md +0 -212
- package/docusaurus/docs/openapi/response-validation.md +0 -344
- package/docusaurus/docs/scheduling/cron.md +0 -305
- package/docusaurus/docs/scheduling/daemon-mode.md +0 -317
- package/docusaurus/docs/scheduling/intervals.md +0 -289
- package/docusaurus/docs/scheduling/overview.md +0 -231
- package/docusaurus/docs/stores/custom-adapters.md +0 -376
- package/docusaurus/docs/stores/file.md +0 -236
- package/docusaurus/docs/stores/memory.md +0 -193
- package/docusaurus/docs/stores/overview.md +0 -274
- package/docusaurus/docs/stores/postgrest.md +0 -316
- package/docusaurus/docusaurus.config.ts +0 -148
- package/docusaurus/package-lock.json +0 -18029
- package/docusaurus/package.json +0 -47
- package/docusaurus/sidebars.ts +0 -155
- package/docusaurus/src/components/HomepageFeatures/index.tsx +0 -105
- package/docusaurus/src/components/HomepageFeatures/styles.module.css +0 -12
- package/docusaurus/src/css/custom.css +0 -169
- package/docusaurus/src/pages/index.module.css +0 -48
- package/docusaurus/src/pages/index.tsx +0 -110
- package/docusaurus/src/pages/markdown-page.md +0 -7
- package/docusaurus/static/.nojekyll +0 -0
- package/docusaurus/static/img/docusaurus-social-card.jpg +0 -0
- package/docusaurus/static/img/docusaurus.png +0 -0
- package/docusaurus/static/img/favicon.ico +0 -0
- package/docusaurus/static/img/logo.svg +0 -10
- package/docusaurus/static/img/undraw_docusaurus_mountain.svg +0 -171
- package/docusaurus/static/img/undraw_docusaurus_react.svg +0 -170
- package/docusaurus/static/img/undraw_docusaurus_tree.svg +0 -40
- package/docusaurus/tsconfig.json +0 -8
- package/examples/README.md +0 -112
- package/examples/error-handling/README.md +0 -150
- package/examples/error-handling/payment-processor.vague +0 -287
- package/examples/github-sync/README.md +0 -74
- package/examples/github-sync/fetch-issues.vague +0 -47
- package/examples/github-sync/fetch-prs.vague +0 -40
- package/examples/github-sync/mission.vague +0 -101
- package/examples/github-sync/normalize.vague +0 -70
- package/examples/jsonplaceholder/README.md +0 -28
- package/examples/jsonplaceholder/posts.vague +0 -48
- package/examples/petstore/README.md +0 -35
- package/examples/petstore/openapi.yaml +0 -97
- package/examples/petstore/sync.vague +0 -52
- package/examples/temporal-comparison/README.md +0 -297
- package/examples/temporal-comparison/reconciliation.vague +0 -355
- package/examples/temporal-comparison/temporal/activities/index.ts +0 -8
- package/examples/temporal-comparison/temporal/activities/shipstation.ts +0 -225
- package/examples/temporal-comparison/temporal/activities/shopify.ts +0 -257
- package/examples/temporal-comparison/temporal/activities/storage.ts +0 -198
- package/examples/temporal-comparison/temporal/activities/stripe.ts +0 -169
- package/examples/temporal-comparison/temporal/activities/validation.ts +0 -205
- package/examples/temporal-comparison/temporal/client/schedule.ts +0 -218
- package/examples/temporal-comparison/temporal/config/retry.ts +0 -63
- package/examples/temporal-comparison/temporal/types/index.ts +0 -129
- package/examples/temporal-comparison/temporal/workers/main.ts +0 -130
- package/examples/temporal-comparison/temporal/workflows/orderReconciliation.ts +0 -262
- package/examples/xero/README.md +0 -88
- package/examples/xero/invoices.vague +0 -189
- package/src/api-integration.test.ts +0 -954
- package/src/ast/index.ts +0 -1
- package/src/ast/nodes.ts +0 -310
- package/src/auth/auth.test.ts +0 -326
- package/src/auth/circuit-breaker.test.ts +0 -390
- package/src/auth/circuit-breaker.ts +0 -379
- package/src/auth/credentials.test.ts +0 -273
- package/src/auth/credentials.ts +0 -246
- package/src/auth/index.ts +0 -40
- package/src/auth/oauth2-provider.ts +0 -177
- package/src/auth/rate-limiter.ts +0 -459
- package/src/auth/token-store.ts +0 -177
- package/src/auth/types.ts +0 -159
- package/src/benchmark/e2e.bench.ts +0 -288
- package/src/benchmark/evaluator.bench.ts +0 -331
- package/src/benchmark/fixtures.ts +0 -295
- package/src/benchmark/index.ts +0 -108
- package/src/benchmark/lexer.bench.ts +0 -69
- package/src/benchmark/parser.bench.ts +0 -103
- package/src/benchmark/resilience.bench.ts +0 -193
- package/src/benchmark/store.bench.ts +0 -147
- package/src/benchmark/utils.ts +0 -230
- package/src/cli.ts +0 -313
- package/src/errors/errors.test.ts +0 -234
- package/src/errors/index.ts +0 -223
- package/src/execution/execution.test.ts +0 -307
- package/src/execution/index.ts +0 -21
- package/src/execution/state.ts +0 -207
- package/src/execution/store.ts +0 -188
- package/src/index.ts +0 -169
- package/src/integration.test.ts +0 -192
- package/src/interpreter/context.ts +0 -57
- package/src/interpreter/evaluator.test.ts +0 -796
- package/src/interpreter/evaluator.ts +0 -245
- package/src/interpreter/executor.ts +0 -946
- package/src/interpreter/fetch-handler.ts +0 -302
- package/src/interpreter/http.test.ts +0 -423
- package/src/interpreter/http.ts +0 -308
- package/src/interpreter/index.ts +0 -32
- package/src/interpreter/pagination.ts +0 -207
- package/src/interpreter/progress.test.ts +0 -276
- package/src/interpreter/schema-matcher.test.ts +0 -160
- package/src/interpreter/schema-matcher.ts +0 -168
- package/src/interpreter/signals.ts +0 -73
- package/src/interpreter/step-handlers/for-handler.ts +0 -65
- package/src/interpreter/step-handlers/index.ts +0 -17
- package/src/interpreter/step-handlers/map-handler.ts +0 -24
- package/src/interpreter/step-handlers/match-handler.ts +0 -101
- package/src/interpreter/step-handlers/store-handler.ts +0 -78
- package/src/interpreter/step-handlers/types.ts +0 -17
- package/src/interpreter/step-handlers/validate-handler.ts +0 -30
- package/src/interpreter/step-handlers/webhook-handler.ts +0 -142
- package/src/lexer/index.ts +0 -18
- package/src/lexer/lexer.test.ts +0 -316
- package/src/lexer/tokens.ts +0 -179
- package/src/loader/index.ts +0 -288
- package/src/loader/loader.test.ts +0 -360
- package/src/oas/index.ts +0 -4
- package/src/oas/loader.ts +0 -126
- package/src/oas/oas.test.ts +0 -254
- package/src/oas/validator.ts +0 -299
- package/src/parser/base.ts +0 -124
- package/src/parser/expressions.test.ts +0 -525
- package/src/parser/expressions.ts +0 -314
- package/src/parser/index.ts +0 -3
- package/src/parser/match.test.ts +0 -296
- package/src/parser/parser.test.ts +0 -739
- package/src/parser/parser.ts +0 -1469
- package/src/parser/schedule.test.ts +0 -287
- package/src/parser/webhook.test.ts +0 -248
- package/src/plugin.ts +0 -83
- package/src/scheduler/cron-parser.test.ts +0 -236
- package/src/scheduler/cron-parser.ts +0 -236
- package/src/scheduler/index.ts +0 -10
- package/src/scheduler/scheduler.ts +0 -443
- package/src/scheduler/types.ts +0 -71
- package/src/stores/factory.ts +0 -104
- package/src/stores/file.test.ts +0 -276
- package/src/stores/file.ts +0 -211
- package/src/stores/index.ts +0 -6
- package/src/stores/memory.test.ts +0 -238
- package/src/stores/memory.ts +0 -63
- package/src/stores/postgrest.test.ts +0 -488
- package/src/stores/postgrest.ts +0 -263
- package/src/stores/stores.test.ts +0 -197
- package/src/stores/types.ts +0 -58
- package/src/sync/index.ts +0 -16
- package/src/sync/state.ts +0 -126
- package/src/sync/store.ts +0 -139
- package/src/sync/sync.test.ts +0 -271
- package/src/utils/async.ts +0 -10
- package/src/utils/file.ts +0 -106
- package/src/utils/index.ts +0 -14
- package/src/utils/logger.ts +0 -53
- package/src/utils/path.ts +0 -47
- package/src/webhook/index.ts +0 -15
- package/src/webhook/server.test.ts +0 -253
- package/src/webhook/server.ts +0 -389
- package/src/webhook/store.ts +0 -239
- package/src/webhook/types.ts +0 -93
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -39
|
@@ -1,50 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ---
|
|
3
|
+
* purpose: Mission executor - orchestrates pipeline execution
|
|
4
|
+
* inputs:
|
|
5
|
+
* - ReqonProgram - parsed AST
|
|
6
|
+
* - ExecutorConfig - auth, stores, callbacks, debug settings
|
|
7
|
+
* outputs:
|
|
8
|
+
* - ExecutionResult - success/errors, stores, duration
|
|
9
|
+
* related:
|
|
10
|
+
* - ./context.ts - execution state (variables, stores, sources)
|
|
11
|
+
* - ./evaluator.ts - expression evaluation
|
|
12
|
+
* - ./fetch-handler.ts - HTTP requests
|
|
13
|
+
* - ./step-handlers/ - individual step type handlers
|
|
14
|
+
* - ./source-manager.ts - auth provider management
|
|
15
|
+
* ---
|
|
16
|
+
*/
|
|
1
17
|
import { isParallelStage } from '../ast/nodes.js';
|
|
2
|
-
import { createContext, setVariable } from './context.js';
|
|
18
|
+
import { createContext, childContext, setVariable } from './context.js';
|
|
3
19
|
import { evaluate } from './evaluator.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { loadOAS } from '../oas/index.js';
|
|
20
|
+
import { SourceManager } from './source-manager.js';
|
|
21
|
+
import { StoreManager } from './store-manager.js';
|
|
7
22
|
import { AdaptiveRateLimiter } from '../auth/rate-limiter.js';
|
|
8
23
|
import { CircuitBreaker } from '../auth/circuit-breaker.js';
|
|
9
24
|
import { createExecutionState, findResumePoint, FileExecutionStore, } from '../execution/index.js';
|
|
10
|
-
import { FileSyncStore
|
|
25
|
+
import { FileSyncStore } from '../sync/index.js';
|
|
11
26
|
import { FetchHandler } from './fetch-handler.js';
|
|
12
|
-
import { ForHandler, MapHandler, ValidateHandler, StoreHandler, MatchHandler, WebhookHandler, SkipSignal, RetrySignal, JumpSignal, QueueSignal, } from './step-handlers/index.js';
|
|
27
|
+
import { ForHandler, MapHandler, ValidateHandler, StoreHandler, MatchHandler, ApplyHandler, WebhookHandler, PauseHandler, SkipSignal, AbortError, RetrySignal, JumpSignal, QueueSignal, } from './step-handlers/index.js';
|
|
28
|
+
import { createStructuredLogger } from '../observability/index.js';
|
|
29
|
+
import { PauseSignal } from './signals.js';
|
|
30
|
+
import { FileTraceStore, createTraceRecorder, } from '../trace/index.js';
|
|
31
|
+
import { FilePauseStore, createPauseManager, } from '../pause/index.js';
|
|
13
32
|
export class MissionExecutor {
|
|
14
33
|
config;
|
|
15
34
|
ctx;
|
|
16
35
|
errors = [];
|
|
17
36
|
actionsRun = [];
|
|
18
|
-
|
|
19
|
-
sourceConfigs = new Map();
|
|
37
|
+
transforms = new Map();
|
|
20
38
|
rateLimiter;
|
|
21
39
|
circuitBreaker;
|
|
40
|
+
sourceManager;
|
|
41
|
+
storeManager;
|
|
22
42
|
executionStore;
|
|
23
43
|
executionState;
|
|
24
44
|
syncStore;
|
|
25
45
|
missionName;
|
|
46
|
+
eventEmitter;
|
|
47
|
+
logger;
|
|
48
|
+
stepIndex = 0;
|
|
49
|
+
debugController;
|
|
50
|
+
traceRecorder;
|
|
51
|
+
traceStore;
|
|
52
|
+
pauseManager;
|
|
53
|
+
pauseStore;
|
|
54
|
+
currentStageIndex = 0;
|
|
55
|
+
currentPauseId;
|
|
26
56
|
constructor(config = {}) {
|
|
27
57
|
this.config = config;
|
|
28
58
|
this.ctx = createContext();
|
|
29
59
|
this.rateLimiter = new AdaptiveRateLimiter();
|
|
30
60
|
this.circuitBreaker = new CircuitBreaker();
|
|
61
|
+
// Initialize managers (logger set after verbose callbacks configured)
|
|
62
|
+
this.sourceManager = new SourceManager({ auth: config.auth, missionDir: config.missionDir }, { rateLimiter: this.rateLimiter, circuitBreaker: this.circuitBreaker });
|
|
63
|
+
this.storeManager = new StoreManager({
|
|
64
|
+
customStores: config.stores,
|
|
65
|
+
developmentMode: config.developmentMode,
|
|
66
|
+
dataDir: config.dataDir,
|
|
67
|
+
});
|
|
31
68
|
// Set up rate limit callbacks with default logging if verbose
|
|
32
69
|
const callbacks = config.rateLimitCallbacks ?? {};
|
|
33
70
|
if (config.verbose && !callbacks.onRateLimited) {
|
|
34
71
|
callbacks.onRateLimited = (event) => {
|
|
35
|
-
|
|
72
|
+
this.log(`Rate limited on ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} - ` +
|
|
36
73
|
`waiting ${event.waitSeconds}s (strategy: ${event.strategy})`);
|
|
37
74
|
};
|
|
38
75
|
}
|
|
39
76
|
if (config.verbose && !callbacks.onResumed) {
|
|
40
77
|
callbacks.onResumed = (event) => {
|
|
41
|
-
|
|
78
|
+
this.log(`Rate limit cleared for ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} ` +
|
|
42
79
|
`(waited ${event.waitedSeconds}s)`);
|
|
43
80
|
};
|
|
44
81
|
}
|
|
45
82
|
if (config.verbose && !callbacks.onWaiting) {
|
|
46
83
|
callbacks.onWaiting = (event) => {
|
|
47
|
-
|
|
84
|
+
this.log(`Still waiting for ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} - ` +
|
|
48
85
|
`${event.waitSeconds}s remaining (elapsed: ${event.elapsedSeconds}s)`);
|
|
49
86
|
};
|
|
50
87
|
}
|
|
@@ -53,33 +90,71 @@ export class MissionExecutor {
|
|
|
53
90
|
const cbCallbacks = config.circuitBreakerCallbacks ?? {};
|
|
54
91
|
if (config.verbose && !cbCallbacks.onOpen) {
|
|
55
92
|
cbCallbacks.onOpen = (event) => {
|
|
56
|
-
|
|
93
|
+
this.log(`Circuit breaker OPEN for ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} - ` +
|
|
57
94
|
`${event.failures} failures (${event.reason ?? 'threshold exceeded'})`);
|
|
58
95
|
};
|
|
59
96
|
}
|
|
60
97
|
if (config.verbose && !cbCallbacks.onHalfOpen) {
|
|
61
98
|
cbCallbacks.onHalfOpen = (event) => {
|
|
62
|
-
|
|
99
|
+
this.log(`Circuit breaker HALF-OPEN for ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} - ` +
|
|
63
100
|
`testing recovery`);
|
|
64
101
|
};
|
|
65
102
|
}
|
|
66
103
|
if (config.verbose && !cbCallbacks.onClose) {
|
|
67
104
|
cbCallbacks.onClose = (event) => {
|
|
68
|
-
|
|
105
|
+
this.log(`Circuit breaker CLOSED for ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} - ` +
|
|
69
106
|
`recovery successful`);
|
|
70
107
|
};
|
|
71
108
|
}
|
|
72
109
|
if (config.verbose && !cbCallbacks.onRejected) {
|
|
73
110
|
cbCallbacks.onRejected = (event) => {
|
|
74
|
-
|
|
111
|
+
this.log(`Request REJECTED by circuit breaker for ${event.source}${event.endpoint ? `:${event.endpoint}` : ''} - ` +
|
|
75
112
|
`retry in ${Math.ceil(event.nextAttemptIn / 1000)}s`);
|
|
76
113
|
};
|
|
77
114
|
}
|
|
78
115
|
this.circuitBreaker.setCallbacks(cbCallbacks);
|
|
79
116
|
// Initialize execution store if persistence enabled
|
|
80
117
|
if (config.persistState) {
|
|
81
|
-
this.executionStore =
|
|
118
|
+
this.executionStore =
|
|
119
|
+
config.executionStore ??
|
|
120
|
+
new FileExecutionStore(`${config.dataDir ?? '.reqon-data'}/executions`);
|
|
121
|
+
}
|
|
122
|
+
// Initialize event emitter if provided
|
|
123
|
+
this.eventEmitter = config.eventEmitter;
|
|
124
|
+
// Initialize logger if verbose or provided
|
|
125
|
+
if (config.logger) {
|
|
126
|
+
this.logger = config.logger;
|
|
127
|
+
}
|
|
128
|
+
else if (config.verbose) {
|
|
129
|
+
this.logger = createStructuredLogger({
|
|
130
|
+
prefix: 'Reqon',
|
|
131
|
+
level: 'debug',
|
|
132
|
+
context: {},
|
|
133
|
+
});
|
|
82
134
|
}
|
|
135
|
+
// Update managers with log function now that logger is configured
|
|
136
|
+
this.sourceManager = new SourceManager({ auth: config.auth, missionDir: config.missionDir, log: (msg) => this.log(msg) }, { rateLimiter: this.rateLimiter, circuitBreaker: this.circuitBreaker });
|
|
137
|
+
this.storeManager = new StoreManager({
|
|
138
|
+
customStores: config.stores,
|
|
139
|
+
developmentMode: config.developmentMode,
|
|
140
|
+
dataDir: config.dataDir,
|
|
141
|
+
log: (msg) => this.log(msg),
|
|
142
|
+
});
|
|
143
|
+
// Initialize debug controller if provided
|
|
144
|
+
this.debugController = config.debugController;
|
|
145
|
+
// Initialize trace store
|
|
146
|
+
this.traceStore =
|
|
147
|
+
config.traceStore ?? new FileTraceStore(`${config.dataDir ?? '.reqon-data'}/traces`);
|
|
148
|
+
// Initialize pause store and manager
|
|
149
|
+
this.pauseStore =
|
|
150
|
+
config.pauseStore ?? new FilePauseStore(`${config.dataDir ?? '.reqon-data'}/pauses`);
|
|
151
|
+
this.pauseManager =
|
|
152
|
+
config.pauseManager ??
|
|
153
|
+
createPauseManager({
|
|
154
|
+
store: this.pauseStore,
|
|
155
|
+
webhookServer: config.webhookServer,
|
|
156
|
+
log: (msg) => this.log(msg),
|
|
157
|
+
});
|
|
83
158
|
}
|
|
84
159
|
async execute(program) {
|
|
85
160
|
const startTime = Date.now();
|
|
@@ -96,6 +171,18 @@ export class MissionExecutor {
|
|
|
96
171
|
}
|
|
97
172
|
// Initialize or resume execution state
|
|
98
173
|
await this.initializeExecutionState(mission);
|
|
174
|
+
// Initialize trace recorder if tracing is enabled
|
|
175
|
+
if (mission.trace && this.traceStore && this.executionState) {
|
|
176
|
+
this.traceRecorder = createTraceRecorder({
|
|
177
|
+
executionId: this.executionState.id,
|
|
178
|
+
mission: mission.name,
|
|
179
|
+
mode: mission.trace.mode,
|
|
180
|
+
store: this.traceStore,
|
|
181
|
+
metadata: this.config.metadata,
|
|
182
|
+
streaming: true, // Stream snapshots as they happen
|
|
183
|
+
});
|
|
184
|
+
this.log(`Tracing enabled (mode: ${mission.trace.mode})`);
|
|
185
|
+
}
|
|
99
186
|
try {
|
|
100
187
|
await this.executeMission(mission);
|
|
101
188
|
// Mark execution as completed
|
|
@@ -107,22 +194,32 @@ export class MissionExecutor {
|
|
|
107
194
|
}
|
|
108
195
|
}
|
|
109
196
|
catch (error) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
197
|
+
// PauseSignal is not an error - execution was intentionally paused
|
|
198
|
+
if (error instanceof PauseSignal) {
|
|
199
|
+
this.log('Execution paused');
|
|
200
|
+
this.currentPauseId = error.pauseId;
|
|
201
|
+
// State is already set to 'paused' in checkPause() or pause handler
|
|
202
|
+
// Don't record as error, just let execution end
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
this.errors.push({
|
|
206
|
+
action: 'mission',
|
|
207
|
+
step: 'execute',
|
|
208
|
+
message: error.message,
|
|
209
|
+
details: error,
|
|
210
|
+
});
|
|
211
|
+
// Mark execution as failed
|
|
212
|
+
if (this.executionState) {
|
|
213
|
+
this.executionState.status = 'failed';
|
|
214
|
+
this.executionState.completedAt = new Date();
|
|
215
|
+
this.executionState.duration = Date.now() - startTime;
|
|
216
|
+
await this.saveExecutionState();
|
|
217
|
+
}
|
|
122
218
|
}
|
|
123
219
|
}
|
|
124
220
|
const duration = Date.now() - startTime;
|
|
125
|
-
const
|
|
221
|
+
const isPaused = this.executionState?.status === 'paused';
|
|
222
|
+
const success = this.errors.length === 0 && !isPaused;
|
|
126
223
|
// Emit onExecutionComplete callback - count stages in a single pass
|
|
127
224
|
const stageCounts = this.executionState?.stages.reduce((acc, s) => {
|
|
128
225
|
if (s.status === 'completed')
|
|
@@ -142,6 +239,34 @@ export class MissionExecutor {
|
|
|
142
239
|
stagesFailed,
|
|
143
240
|
errors: this.errors,
|
|
144
241
|
});
|
|
242
|
+
// Emit mission.complete, mission.paused, or mission.failed event
|
|
243
|
+
if (isPaused) {
|
|
244
|
+
this.eventEmitter?.emit('mission.paused', {
|
|
245
|
+
stagesCompleted,
|
|
246
|
+
executionId: this.executionState?.id,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
else if (success) {
|
|
250
|
+
this.eventEmitter?.emit('mission.complete', {
|
|
251
|
+
success: true,
|
|
252
|
+
stagesCompleted,
|
|
253
|
+
stagesFailed,
|
|
254
|
+
stagesSkipped: this.executionState?.stages.filter((s) => s.status === 'skipped').length ?? 0,
|
|
255
|
+
errorCount: this.errors.length,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
const failedStage = this.executionState?.stages.find((s) => s.status === 'failed');
|
|
260
|
+
this.eventEmitter?.emit('mission.failed', {
|
|
261
|
+
error: this.errors[0]?.message ?? 'Unknown error',
|
|
262
|
+
failedStage: failedStage?.action,
|
|
263
|
+
stagesCompleted,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// Finalize trace if enabled
|
|
267
|
+
if (this.traceRecorder) {
|
|
268
|
+
await this.traceRecorder.finalize(success);
|
|
269
|
+
}
|
|
145
270
|
return {
|
|
146
271
|
success,
|
|
147
272
|
duration,
|
|
@@ -150,6 +275,8 @@ export class MissionExecutor {
|
|
|
150
275
|
stores: this.ctx.stores,
|
|
151
276
|
executionId: this.executionState?.id,
|
|
152
277
|
state: this.executionState,
|
|
278
|
+
traceId: this.traceRecorder ? this.executionState?.id : undefined,
|
|
279
|
+
pauseId: this.currentPauseId,
|
|
153
280
|
};
|
|
154
281
|
}
|
|
155
282
|
async initializeExecutionState(mission) {
|
|
@@ -190,6 +317,13 @@ export class MissionExecutor {
|
|
|
190
317
|
isResume,
|
|
191
318
|
metadata: this.config.metadata,
|
|
192
319
|
});
|
|
320
|
+
// Emit mission.start event
|
|
321
|
+
this.eventEmitter?.emit('mission.start', {
|
|
322
|
+
stageCount: mission.pipeline.stages.length,
|
|
323
|
+
isResume,
|
|
324
|
+
resumeFromStage: isResume ? findResumePoint(this.executionState) : undefined,
|
|
325
|
+
metadata: this.config.metadata,
|
|
326
|
+
});
|
|
193
327
|
}
|
|
194
328
|
async saveExecutionState() {
|
|
195
329
|
if (this.executionStore && this.executionState) {
|
|
@@ -227,20 +361,23 @@ export class MissionExecutor {
|
|
|
227
361
|
this.log(`Executing mission: ${mission.name}`);
|
|
228
362
|
this.missionName = mission.name;
|
|
229
363
|
// Initialize sync store
|
|
230
|
-
this.syncStore =
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// Initialize stores
|
|
236
|
-
|
|
237
|
-
await this.initializeStore(store);
|
|
238
|
-
}
|
|
364
|
+
this.syncStore =
|
|
365
|
+
this.config.syncStore ??
|
|
366
|
+
new FileSyncStore(mission.name, `${this.config.dataDir ?? '.reqon-data'}/sync`);
|
|
367
|
+
// Initialize sources using SourceManager
|
|
368
|
+
await this.sourceManager.initializeSources(mission.sources, this.ctx);
|
|
369
|
+
// Initialize stores using StoreManager
|
|
370
|
+
await this.storeManager.initializeStores(mission.stores, this.ctx);
|
|
239
371
|
// Initialize schemas (for match step schema matching)
|
|
240
372
|
for (const schema of mission.schemas) {
|
|
241
373
|
this.ctx.schemas.set(schema.name, schema);
|
|
242
374
|
this.log(`Registered schema: ${schema.name}`);
|
|
243
375
|
}
|
|
376
|
+
// Initialize transforms
|
|
377
|
+
for (const transform of mission.transforms) {
|
|
378
|
+
this.transforms.set(transform.name, transform);
|
|
379
|
+
this.log(`Registered transform: ${transform.name}`);
|
|
380
|
+
}
|
|
244
381
|
// Build action lookup
|
|
245
382
|
const actions = new Map();
|
|
246
383
|
for (const action of mission.actions) {
|
|
@@ -256,6 +393,8 @@ export class MissionExecutor {
|
|
|
256
393
|
// Execute pipeline
|
|
257
394
|
for (let i = 0; i < mission.pipeline.stages.length; i++) {
|
|
258
395
|
const stage = mission.pipeline.stages[i];
|
|
396
|
+
// Check for pause request at safe point (between stages)
|
|
397
|
+
await this.checkPause();
|
|
259
398
|
// Skip already completed stages when resuming
|
|
260
399
|
if (i < resumeIndex) {
|
|
261
400
|
this.log(`Skipping ${this.getStageName(stage)} (already completed)`);
|
|
@@ -268,9 +407,12 @@ export class MissionExecutor {
|
|
|
268
407
|
this.log(`Skipping ${this.getStageName(stage)} (condition not met)`);
|
|
269
408
|
this.updateStageState(i, { status: 'skipped' });
|
|
270
409
|
await this.saveExecutionState();
|
|
410
|
+
this.updateControlServerState();
|
|
271
411
|
continue;
|
|
272
412
|
}
|
|
273
413
|
}
|
|
414
|
+
// Track current stage index for pause handler
|
|
415
|
+
this.currentStageIndex = i;
|
|
274
416
|
// Execute stage (parallel or sequential)
|
|
275
417
|
if (isParallelStage(stage)) {
|
|
276
418
|
await this.executeParallelStage(i, stage, actions, mission);
|
|
@@ -278,6 +420,8 @@ export class MissionExecutor {
|
|
|
278
420
|
else if (stage.action) {
|
|
279
421
|
await this.executeSequentialStage(i, stage.action, actions, mission);
|
|
280
422
|
}
|
|
423
|
+
// Update control server with latest state after each stage
|
|
424
|
+
this.updateControlServerState();
|
|
281
425
|
}
|
|
282
426
|
}
|
|
283
427
|
getStageName(stage) {
|
|
@@ -303,6 +447,13 @@ export class MissionExecutor {
|
|
|
303
447
|
stageName: actionName,
|
|
304
448
|
totalStages: mission.pipeline.stages.length,
|
|
305
449
|
});
|
|
450
|
+
// Emit stage.start event
|
|
451
|
+
this.eventEmitter?.emit('stage.start', {
|
|
452
|
+
stageIndex,
|
|
453
|
+
stageName: actionName,
|
|
454
|
+
totalStages: mission.pipeline.stages.length,
|
|
455
|
+
isParallel: false,
|
|
456
|
+
});
|
|
306
457
|
try {
|
|
307
458
|
await this.executeAction(action);
|
|
308
459
|
this.actionsRun.push(action.name);
|
|
@@ -319,6 +470,12 @@ export class MissionExecutor {
|
|
|
319
470
|
success: true,
|
|
320
471
|
duration: Date.now() - stageStartTime,
|
|
321
472
|
});
|
|
473
|
+
// Emit stage.complete event
|
|
474
|
+
this.eventEmitter?.emit('stage.complete', {
|
|
475
|
+
stageIndex,
|
|
476
|
+
stageName: actionName,
|
|
477
|
+
success: true,
|
|
478
|
+
});
|
|
322
479
|
}
|
|
323
480
|
catch (error) {
|
|
324
481
|
// Mark stage as failed
|
|
@@ -338,6 +495,13 @@ export class MissionExecutor {
|
|
|
338
495
|
duration: Date.now() - stageStartTime,
|
|
339
496
|
error: error.message,
|
|
340
497
|
});
|
|
498
|
+
// Emit stage.complete event (failure)
|
|
499
|
+
this.eventEmitter?.emit('stage.complete', {
|
|
500
|
+
stageIndex,
|
|
501
|
+
stageName: actionName,
|
|
502
|
+
success: false,
|
|
503
|
+
error: error.message,
|
|
504
|
+
});
|
|
341
505
|
throw error; // Re-throw to stop execution
|
|
342
506
|
}
|
|
343
507
|
}
|
|
@@ -365,10 +529,18 @@ export class MissionExecutor {
|
|
|
365
529
|
stageName,
|
|
366
530
|
totalStages: mission.pipeline.stages.length,
|
|
367
531
|
});
|
|
532
|
+
// Emit stage.start event (parallel)
|
|
533
|
+
this.eventEmitter?.emit('stage.start', {
|
|
534
|
+
stageIndex,
|
|
535
|
+
stageName,
|
|
536
|
+
totalStages: mission.pipeline.stages.length,
|
|
537
|
+
isParallel: true,
|
|
538
|
+
parallelActions: actionNames,
|
|
539
|
+
});
|
|
368
540
|
this.log(`Executing parallel stage: ${stageName}`);
|
|
369
541
|
try {
|
|
370
542
|
// Execute all actions in parallel
|
|
371
|
-
const results = await Promise.allSettled(actionDefs.map(action => this.executeAction(action)));
|
|
543
|
+
const results = await Promise.allSettled(actionDefs.map((action) => this.executeAction(action)));
|
|
372
544
|
// Check for failures
|
|
373
545
|
const failures = [];
|
|
374
546
|
for (let i = 0; i < results.length; i++) {
|
|
@@ -381,7 +553,7 @@ export class MissionExecutor {
|
|
|
381
553
|
}
|
|
382
554
|
}
|
|
383
555
|
if (failures.length > 0) {
|
|
384
|
-
const errorMsg = failures.map(f => `${f.name}: ${f.error.message}`).join('; ');
|
|
556
|
+
const errorMsg = failures.map((f) => `${f.name}: ${f.error.message}`).join('; ');
|
|
385
557
|
throw new Error(`Parallel stage failed: ${errorMsg}`);
|
|
386
558
|
}
|
|
387
559
|
// Mark stage as completed
|
|
@@ -397,6 +569,12 @@ export class MissionExecutor {
|
|
|
397
569
|
success: true,
|
|
398
570
|
duration: Date.now() - stageStartTime,
|
|
399
571
|
});
|
|
572
|
+
// Emit stage.complete event (success)
|
|
573
|
+
this.eventEmitter?.emit('stage.complete', {
|
|
574
|
+
stageIndex,
|
|
575
|
+
stageName,
|
|
576
|
+
success: true,
|
|
577
|
+
});
|
|
400
578
|
}
|
|
401
579
|
catch (error) {
|
|
402
580
|
// Mark stage as failed
|
|
@@ -416,154 +594,129 @@ export class MissionExecutor {
|
|
|
416
594
|
duration: Date.now() - stageStartTime,
|
|
417
595
|
error: error.message,
|
|
418
596
|
});
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const authConfig = this.config.auth?.[source.name];
|
|
426
|
-
let authProvider;
|
|
427
|
-
if (authConfig) {
|
|
428
|
-
if (authConfig.type === 'bearer' && authConfig.token) {
|
|
429
|
-
authProvider = new BearerAuthProvider(authConfig.token);
|
|
430
|
-
}
|
|
431
|
-
else if (authConfig.type === 'oauth2' && authConfig.accessToken) {
|
|
432
|
-
authProvider = new OAuth2AuthProvider({
|
|
433
|
-
accessToken: authConfig.accessToken,
|
|
434
|
-
refreshToken: authConfig.refreshToken,
|
|
435
|
-
tokenEndpoint: authConfig.tokenEndpoint,
|
|
436
|
-
clientId: authConfig.clientId,
|
|
437
|
-
clientSecret: authConfig.clientSecret,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
// If source has OAS spec, load it
|
|
442
|
-
let baseUrl = source.config.base;
|
|
443
|
-
if (source.specPath) {
|
|
444
|
-
try {
|
|
445
|
-
const oasSource = await loadOAS(source.specPath);
|
|
446
|
-
this.oasSources.set(source.name, oasSource);
|
|
447
|
-
// Use base URL from OAS if not explicitly provided
|
|
448
|
-
if (!baseUrl) {
|
|
449
|
-
baseUrl = oasSource.baseUrl;
|
|
450
|
-
}
|
|
451
|
-
this.log(`Loaded OAS spec for ${source.name}: ${oasSource.operations.size} operations`);
|
|
452
|
-
}
|
|
453
|
-
catch (error) {
|
|
454
|
-
throw new Error(`Failed to load OAS spec for ${source.name}: ${error.message}`);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
if (!baseUrl) {
|
|
458
|
-
throw new Error(`Source ${source.name} has no base URL (provide 'base' or OAS spec with servers)`);
|
|
459
|
-
}
|
|
460
|
-
// Configure rate limiter for this source
|
|
461
|
-
if (source.config.rateLimit) {
|
|
462
|
-
this.rateLimiter.configure(source.name, {
|
|
463
|
-
strategy: source.config.rateLimit.strategy,
|
|
464
|
-
maxWait: source.config.rateLimit.maxWait,
|
|
465
|
-
fallbackRpm: source.config.rateLimit.fallbackRpm,
|
|
466
|
-
});
|
|
467
|
-
this.log(`Rate limit config for ${source.name}: strategy=${source.config.rateLimit.strategy ?? 'pause'}, ` +
|
|
468
|
-
`maxWait=${source.config.rateLimit.maxWait ?? 300}s`);
|
|
469
|
-
}
|
|
470
|
-
// Configure circuit breaker for this source
|
|
471
|
-
if (source.config.circuitBreaker) {
|
|
472
|
-
this.circuitBreaker.configure(source.name, {
|
|
473
|
-
failureThreshold: source.config.circuitBreaker.failureThreshold,
|
|
474
|
-
// Convert seconds to milliseconds for the circuit breaker
|
|
475
|
-
resetTimeout: source.config.circuitBreaker.resetTimeout
|
|
476
|
-
? source.config.circuitBreaker.resetTimeout * 1000
|
|
477
|
-
: undefined,
|
|
478
|
-
successThreshold: source.config.circuitBreaker.successThreshold,
|
|
479
|
-
failureWindow: source.config.circuitBreaker.failureWindow
|
|
480
|
-
? source.config.circuitBreaker.failureWindow * 1000
|
|
481
|
-
: undefined,
|
|
597
|
+
// Emit stage.complete event (failure)
|
|
598
|
+
this.eventEmitter?.emit('stage.complete', {
|
|
599
|
+
stageIndex,
|
|
600
|
+
stageName,
|
|
601
|
+
success: false,
|
|
602
|
+
error: error.message,
|
|
482
603
|
});
|
|
483
|
-
|
|
484
|
-
`failureThreshold=${source.config.circuitBreaker.failureThreshold ?? 5}, ` +
|
|
485
|
-
`resetTimeout=${source.config.circuitBreaker.resetTimeout ?? 30}s`);
|
|
486
|
-
}
|
|
487
|
-
const client = new HttpClient({
|
|
488
|
-
baseUrl,
|
|
489
|
-
auth: authProvider,
|
|
490
|
-
rateLimiter: this.rateLimiter,
|
|
491
|
-
circuitBreaker: this.circuitBreaker,
|
|
492
|
-
sourceName: source.name,
|
|
493
|
-
});
|
|
494
|
-
this.ctx.sources.set(source.name, client);
|
|
495
|
-
this.log(`Initialized source: ${source.name}`);
|
|
496
|
-
}
|
|
497
|
-
async initializeStore(store) {
|
|
498
|
-
// Check for custom store adapter
|
|
499
|
-
if (this.config.stores?.[store.name]) {
|
|
500
|
-
this.ctx.stores.set(store.name, this.config.stores[store.name]);
|
|
501
|
-
this.log(`Initialized store: ${store.name} (custom adapter)`);
|
|
502
|
-
return;
|
|
604
|
+
throw error; // Re-throw to stop execution
|
|
503
605
|
}
|
|
504
|
-
// Use store factory to create appropriate adapter
|
|
505
|
-
const developmentMode = this.config.developmentMode ?? true;
|
|
506
|
-
const storeType = resolveStoreType(store.storeType, developmentMode);
|
|
507
|
-
const adapter = createStore({
|
|
508
|
-
type: storeType,
|
|
509
|
-
name: store.target,
|
|
510
|
-
baseDir: this.config.dataDir,
|
|
511
|
-
});
|
|
512
|
-
this.ctx.stores.set(store.name, adapter);
|
|
513
|
-
this.log(`Initialized store: ${store.name} (${storeType}${storeType !== store.storeType ? ` <- ${store.storeType}` : ''})`);
|
|
514
606
|
}
|
|
515
607
|
async executeAction(action) {
|
|
516
608
|
this.log(`Executing action: ${action.name}`);
|
|
609
|
+
// Create a child context for this action with its own response scope
|
|
610
|
+
// This allows parallel actions to have independent response values
|
|
611
|
+
const actionCtx = childContext(this.ctx);
|
|
517
612
|
for (const step of action.steps) {
|
|
518
|
-
await this.executeStep(step, action.name);
|
|
613
|
+
await this.executeStep(step, action.name, actionCtx);
|
|
519
614
|
}
|
|
520
615
|
}
|
|
521
616
|
async executeStep(step, actionName, ctx) {
|
|
522
617
|
// Use provided context or default to this.ctx
|
|
618
|
+
// NOTE: ctx is used for action-scoped operations (response, variables)
|
|
619
|
+
// this.ctx is still used for mission-level resources (stores, sources)
|
|
523
620
|
const execCtx = ctx ?? this.ctx;
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
621
|
+
// Track step index for events
|
|
622
|
+
const currentStepIndex = this.stepIndex++;
|
|
623
|
+
const stepType = this.getStepType(step.type);
|
|
624
|
+
// Emit step.start event
|
|
625
|
+
this.eventEmitter?.emit('step.start', {
|
|
626
|
+
actionName,
|
|
627
|
+
stepIndex: currentStepIndex,
|
|
628
|
+
stepType,
|
|
629
|
+
});
|
|
630
|
+
const stepStartTime = Date.now();
|
|
631
|
+
// Record trace snapshot before step
|
|
632
|
+
if (this.traceRecorder) {
|
|
633
|
+
await this.traceRecorder.recordBeforeStep(actionName, currentStepIndex, stepType, execCtx);
|
|
634
|
+
}
|
|
635
|
+
// Debug pause point - before executing step
|
|
636
|
+
if (this.debugController) {
|
|
637
|
+
const location = {
|
|
638
|
+
action: actionName,
|
|
639
|
+
stepIndex: currentStepIndex,
|
|
640
|
+
stepType,
|
|
641
|
+
};
|
|
642
|
+
if (this.debugController.shouldPause(location)) {
|
|
643
|
+
const snapshot = this.captureDebugSnapshot(actionName, currentStepIndex, stepType, { type: 'step' }, execCtx);
|
|
644
|
+
const command = await this.debugController.pause(snapshot);
|
|
645
|
+
this.handleDebugCommand(command);
|
|
646
|
+
}
|
|
528
647
|
}
|
|
529
648
|
try {
|
|
530
649
|
switch (step.type) {
|
|
531
650
|
case 'FetchStep':
|
|
532
|
-
await this.executeFetch(step);
|
|
651
|
+
await this.executeFetch(step, execCtx);
|
|
533
652
|
break;
|
|
534
653
|
case 'ForStep':
|
|
535
|
-
await this.executeFor(step, actionName);
|
|
654
|
+
await this.executeFor(step, actionName, execCtx);
|
|
536
655
|
break;
|
|
537
656
|
case 'MapStep':
|
|
538
|
-
await this.executeMap(step);
|
|
657
|
+
await this.executeMap(step, execCtx);
|
|
539
658
|
break;
|
|
540
659
|
case 'ValidateStep':
|
|
541
|
-
await this.executeValidate(step);
|
|
660
|
+
await this.executeValidate(step, execCtx);
|
|
542
661
|
break;
|
|
543
662
|
case 'StoreStep':
|
|
544
|
-
await this.executeStore(step);
|
|
663
|
+
await this.executeStore(step, execCtx);
|
|
545
664
|
break;
|
|
546
665
|
case 'MatchStep':
|
|
547
|
-
await this.executeMatch(step, actionName);
|
|
666
|
+
await this.executeMatch(step, actionName, execCtx);
|
|
548
667
|
break;
|
|
549
668
|
case 'LetStep':
|
|
550
|
-
await this.executeLet(step);
|
|
669
|
+
await this.executeLet(step, execCtx);
|
|
670
|
+
break;
|
|
671
|
+
case 'ApplyStep':
|
|
672
|
+
await this.executeApply(step, execCtx);
|
|
551
673
|
break;
|
|
552
674
|
case 'WebhookStep':
|
|
553
|
-
await this.executeWebhook(step);
|
|
675
|
+
await this.executeWebhook(step, execCtx);
|
|
676
|
+
break;
|
|
677
|
+
case 'PauseStep':
|
|
678
|
+
await this.executePause(step, actionName, currentStepIndex, execCtx);
|
|
554
679
|
break;
|
|
555
680
|
default:
|
|
556
681
|
throw new Error(`Unknown step type: ${step.type}`);
|
|
557
682
|
}
|
|
683
|
+
const stepDuration = Date.now() - stepStartTime;
|
|
684
|
+
// Record trace snapshot after step
|
|
685
|
+
if (this.traceRecorder) {
|
|
686
|
+
await this.traceRecorder.recordAfterStep(actionName, currentStepIndex, stepType, execCtx, stepDuration);
|
|
687
|
+
}
|
|
688
|
+
// Emit step.complete event (success)
|
|
689
|
+
this.eventEmitter?.emit('step.complete', {
|
|
690
|
+
actionName,
|
|
691
|
+
stepIndex: currentStepIndex,
|
|
692
|
+
stepType,
|
|
693
|
+
success: true,
|
|
694
|
+
});
|
|
558
695
|
}
|
|
559
696
|
catch (error) {
|
|
560
697
|
// Re-throw flow control signals without recording as errors
|
|
561
698
|
if (error instanceof SkipSignal ||
|
|
562
699
|
error instanceof RetrySignal ||
|
|
563
700
|
error instanceof JumpSignal ||
|
|
564
|
-
error instanceof QueueSignal
|
|
701
|
+
error instanceof QueueSignal ||
|
|
702
|
+
error instanceof PauseSignal) {
|
|
703
|
+
// Emit step.complete for flow control (not an error)
|
|
704
|
+
this.eventEmitter?.emit('step.complete', {
|
|
705
|
+
actionName,
|
|
706
|
+
stepIndex: currentStepIndex,
|
|
707
|
+
stepType,
|
|
708
|
+
success: true, // Flow control is not a failure
|
|
709
|
+
});
|
|
565
710
|
throw error;
|
|
566
711
|
}
|
|
712
|
+
// Emit step.complete event (failure)
|
|
713
|
+
this.eventEmitter?.emit('step.complete', {
|
|
714
|
+
actionName,
|
|
715
|
+
stepIndex: currentStepIndex,
|
|
716
|
+
stepType,
|
|
717
|
+
success: false,
|
|
718
|
+
error: error.message,
|
|
719
|
+
});
|
|
567
720
|
// AbortError is a controlled abort, still record it
|
|
568
721
|
this.errors.push({
|
|
569
722
|
action: actionName,
|
|
@@ -573,91 +726,267 @@ export class MissionExecutor {
|
|
|
573
726
|
});
|
|
574
727
|
throw error;
|
|
575
728
|
}
|
|
576
|
-
finally {
|
|
577
|
-
// Restore original context
|
|
578
|
-
if (ctx) {
|
|
579
|
-
this.ctx = originalCtx;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
729
|
}
|
|
583
|
-
async executeFetch(step) {
|
|
730
|
+
async executeFetch(step, ctx) {
|
|
584
731
|
const fetchHandler = new FetchHandler({
|
|
585
|
-
ctx
|
|
586
|
-
oasSources: this.
|
|
587
|
-
sourceConfigs: this.
|
|
732
|
+
ctx,
|
|
733
|
+
oasSources: this.sourceManager.getAllOASSources(),
|
|
734
|
+
sourceConfigs: this.sourceManager.getAllSourceConfigs(),
|
|
588
735
|
syncStore: this.syncStore,
|
|
589
736
|
missionName: this.missionName,
|
|
590
737
|
executionId: this.executionState?.id,
|
|
591
738
|
dryRun: this.config.dryRun,
|
|
592
739
|
log: (msg) => this.log(msg),
|
|
740
|
+
emit: this.eventEmitter
|
|
741
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
742
|
+
: undefined,
|
|
593
743
|
});
|
|
594
744
|
const result = await fetchHandler.execute(step);
|
|
595
|
-
|
|
745
|
+
ctx.response = result.data;
|
|
596
746
|
// Update sync checkpoint after successful fetch
|
|
597
747
|
if (result.checkpointKey && this.syncStore) {
|
|
598
748
|
await fetchHandler.recordCheckpoint(result.checkpointKey, step, result.data);
|
|
599
749
|
}
|
|
600
750
|
}
|
|
601
|
-
async executeFor(step, actionName) {
|
|
751
|
+
async executeFor(step, actionName, ctx) {
|
|
602
752
|
const handler = new ForHandler({
|
|
603
|
-
ctx
|
|
753
|
+
ctx,
|
|
604
754
|
log: (msg) => this.log(msg),
|
|
755
|
+
emit: this.eventEmitter
|
|
756
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
757
|
+
: undefined,
|
|
605
758
|
executeStep: (s, a, c) => this.executeStep(s, a, c),
|
|
606
759
|
actionName,
|
|
760
|
+
debugController: this.debugController,
|
|
761
|
+
captureDebugSnapshot: this.debugController
|
|
762
|
+
? (action, stepIndex, stepType, pauseReason, ctx) => this.captureDebugSnapshot(action, stepIndex, stepType, pauseReason, ctx)
|
|
763
|
+
: undefined,
|
|
764
|
+
handleDebugCommand: this.debugController
|
|
765
|
+
? (cmd) => this.handleDebugCommand(cmd)
|
|
766
|
+
: undefined,
|
|
767
|
+
checkPause: this.config.controlServer ? () => this.checkPause() : undefined,
|
|
607
768
|
});
|
|
608
769
|
await handler.execute(step);
|
|
609
770
|
}
|
|
610
|
-
async executeMap(step) {
|
|
771
|
+
async executeMap(step, ctx) {
|
|
611
772
|
const handler = new MapHandler({
|
|
612
|
-
ctx
|
|
773
|
+
ctx,
|
|
613
774
|
log: (msg) => this.log(msg),
|
|
775
|
+
emit: this.eventEmitter
|
|
776
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
777
|
+
: undefined,
|
|
614
778
|
});
|
|
615
779
|
await handler.execute(step);
|
|
616
780
|
}
|
|
617
|
-
async executeValidate(step) {
|
|
781
|
+
async executeValidate(step, ctx) {
|
|
618
782
|
const handler = new ValidateHandler({
|
|
619
|
-
ctx
|
|
783
|
+
ctx,
|
|
620
784
|
log: (msg) => this.log(msg),
|
|
785
|
+
emit: this.eventEmitter
|
|
786
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
787
|
+
: undefined,
|
|
621
788
|
});
|
|
622
789
|
await handler.execute(step);
|
|
623
790
|
}
|
|
624
|
-
async executeStore(step) {
|
|
791
|
+
async executeStore(step, ctx) {
|
|
625
792
|
const handler = new StoreHandler({
|
|
626
|
-
ctx
|
|
793
|
+
ctx,
|
|
627
794
|
log: (msg) => this.log(msg),
|
|
795
|
+
emit: this.eventEmitter
|
|
796
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
797
|
+
: undefined,
|
|
628
798
|
});
|
|
629
799
|
await handler.execute(step);
|
|
630
800
|
}
|
|
631
|
-
async executeMatch(step, actionName) {
|
|
801
|
+
async executeMatch(step, actionName, ctx) {
|
|
632
802
|
const handler = new MatchHandler({
|
|
633
|
-
ctx
|
|
803
|
+
ctx,
|
|
634
804
|
log: (msg) => this.log(msg),
|
|
805
|
+
emit: this.eventEmitter
|
|
806
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
807
|
+
: undefined,
|
|
635
808
|
executeStep: (s, a, c) => this.executeStep(s, a, c),
|
|
636
809
|
actionName,
|
|
810
|
+
debugController: this.debugController,
|
|
811
|
+
captureDebugSnapshot: this.debugController
|
|
812
|
+
? (action, stepIndex, stepType, pauseReason, execCtx) => this.captureDebugSnapshot(action, stepIndex, stepType, pauseReason, execCtx)
|
|
813
|
+
: undefined,
|
|
814
|
+
handleDebugCommand: this.debugController
|
|
815
|
+
? (cmd) => this.handleDebugCommand(cmd)
|
|
816
|
+
: undefined,
|
|
637
817
|
});
|
|
638
818
|
await handler.execute(step);
|
|
639
819
|
// Flow control signals (SkipSignal, RetrySignal, etc.) will propagate up
|
|
640
820
|
}
|
|
641
|
-
async executeLet(step) {
|
|
642
|
-
const value = evaluate(step.value,
|
|
643
|
-
setVariable(
|
|
821
|
+
async executeLet(step, ctx) {
|
|
822
|
+
const value = evaluate(step.value, ctx);
|
|
823
|
+
setVariable(ctx, step.name, value);
|
|
644
824
|
this.log(`Set variable '${step.name}' = ${JSON.stringify(value)}`);
|
|
645
825
|
}
|
|
646
|
-
async
|
|
826
|
+
async executeApply(step, ctx) {
|
|
827
|
+
const transform = this.transforms.get(step.transform);
|
|
828
|
+
if (!transform) {
|
|
829
|
+
throw new Error(`Transform '${step.transform}' not found`);
|
|
830
|
+
}
|
|
831
|
+
const handler = new ApplyHandler({
|
|
832
|
+
ctx,
|
|
833
|
+
log: (msg) => this.log(msg),
|
|
834
|
+
transform,
|
|
835
|
+
});
|
|
836
|
+
await handler.execute(step);
|
|
837
|
+
}
|
|
838
|
+
async executeWebhook(step, ctx) {
|
|
647
839
|
if (!this.config.webhookServer) {
|
|
648
840
|
throw new Error('Webhook server not configured. Use --webhook flag or configure webhookServer in executor config.');
|
|
649
841
|
}
|
|
650
842
|
const handler = new WebhookHandler({
|
|
651
|
-
ctx
|
|
843
|
+
ctx,
|
|
652
844
|
webhookServer: this.config.webhookServer,
|
|
653
845
|
executionId: this.executionState?.id ?? 'ephemeral',
|
|
654
846
|
log: (msg) => this.log(msg),
|
|
847
|
+
emit: this.eventEmitter
|
|
848
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
849
|
+
: undefined,
|
|
655
850
|
});
|
|
656
851
|
await handler.execute(step);
|
|
657
852
|
}
|
|
853
|
+
async executePause(step, actionName, stepIndex, ctx) {
|
|
854
|
+
if (!this.pauseManager) {
|
|
855
|
+
throw new Error('Pause manager not configured');
|
|
856
|
+
}
|
|
857
|
+
// Mark execution state as paused before creating pause
|
|
858
|
+
if (this.executionState) {
|
|
859
|
+
this.executionState.status = 'paused';
|
|
860
|
+
await this.saveExecutionState();
|
|
861
|
+
}
|
|
862
|
+
const handler = new PauseHandler({
|
|
863
|
+
ctx,
|
|
864
|
+
log: (msg) => this.log(msg),
|
|
865
|
+
emit: this.eventEmitter
|
|
866
|
+
? (type, payload) => this.eventEmitter.emit(type, payload)
|
|
867
|
+
: undefined,
|
|
868
|
+
pauseManager: this.pauseManager,
|
|
869
|
+
executionId: this.executionState?.id ?? 'ephemeral',
|
|
870
|
+
mission: this.missionName ?? 'unknown',
|
|
871
|
+
actionName,
|
|
872
|
+
stageIndex: this.currentStageIndex,
|
|
873
|
+
stepIndex,
|
|
874
|
+
});
|
|
875
|
+
// This will throw PauseSignal
|
|
876
|
+
await handler.execute(step);
|
|
877
|
+
}
|
|
658
878
|
log(message) {
|
|
659
|
-
if (this.
|
|
879
|
+
if (this.logger) {
|
|
880
|
+
this.logger.info(message);
|
|
881
|
+
}
|
|
882
|
+
else if (this.config.verbose) {
|
|
660
883
|
console.log(`[Reqon] ${message}`);
|
|
661
884
|
}
|
|
662
885
|
}
|
|
886
|
+
/**
|
|
887
|
+
* Check if pause has been requested and handle it
|
|
888
|
+
* Should be called at safe pause points (between stages, loop iterations)
|
|
889
|
+
*/
|
|
890
|
+
async checkPause() {
|
|
891
|
+
if (!this.config.controlServer?.isPauseRequested()) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
this.log('Pause requested - saving state and pausing execution');
|
|
895
|
+
// Save state as paused
|
|
896
|
+
if (this.executionState) {
|
|
897
|
+
this.executionState.status = 'paused';
|
|
898
|
+
await this.saveExecutionState();
|
|
899
|
+
}
|
|
900
|
+
// Clear the pause request (it's been handled)
|
|
901
|
+
this.config.controlServer.clearPauseRequest();
|
|
902
|
+
// Throw pause signal to stop execution
|
|
903
|
+
throw new PauseSignal();
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Update control server with current state
|
|
907
|
+
*/
|
|
908
|
+
updateControlServerState() {
|
|
909
|
+
if (this.config.controlServer && this.executionState) {
|
|
910
|
+
this.config.controlServer.updateState(this.executionState);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
getStepType(stepType) {
|
|
914
|
+
const mapping = {
|
|
915
|
+
FetchStep: 'fetch',
|
|
916
|
+
ForStep: 'for',
|
|
917
|
+
MapStep: 'map',
|
|
918
|
+
ValidateStep: 'validate',
|
|
919
|
+
StoreStep: 'store',
|
|
920
|
+
MatchStep: 'match',
|
|
921
|
+
LetStep: 'let',
|
|
922
|
+
WebhookStep: 'webhook',
|
|
923
|
+
PauseStep: 'pause',
|
|
924
|
+
};
|
|
925
|
+
return mapping[stepType] ?? 'fetch';
|
|
926
|
+
}
|
|
927
|
+
/** Get the event emitter (for external access) */
|
|
928
|
+
getEventEmitter() {
|
|
929
|
+
return this.eventEmitter;
|
|
930
|
+
}
|
|
931
|
+
/** Get the structured logger (for external access) */
|
|
932
|
+
getLogger() {
|
|
933
|
+
return this.logger;
|
|
934
|
+
}
|
|
935
|
+
/** Get the debug controller (for external access) */
|
|
936
|
+
getDebugController() {
|
|
937
|
+
return this.debugController;
|
|
938
|
+
}
|
|
939
|
+
/** Capture current execution state for debugging */
|
|
940
|
+
captureDebugSnapshot(action, stepIndex, stepType, pauseReason, ctx) {
|
|
941
|
+
// Collect variables from context chain
|
|
942
|
+
const variables = {};
|
|
943
|
+
let current = ctx;
|
|
944
|
+
while (current) {
|
|
945
|
+
for (const [key, value] of current.variables) {
|
|
946
|
+
if (!(key in variables)) {
|
|
947
|
+
variables[key] = value;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
current = current.parent;
|
|
951
|
+
}
|
|
952
|
+
// Collect store info
|
|
953
|
+
const stores = {};
|
|
954
|
+
for (const [name, _store] of ctx.stores) {
|
|
955
|
+
stores[name] = {
|
|
956
|
+
type: ctx.storeTypes.get(name) ?? 'unknown',
|
|
957
|
+
count: -1, // Would need async call to get count
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
return {
|
|
961
|
+
mission: this.missionName ?? 'unknown',
|
|
962
|
+
action,
|
|
963
|
+
stepIndex,
|
|
964
|
+
stepType,
|
|
965
|
+
pauseReason,
|
|
966
|
+
variables,
|
|
967
|
+
stores,
|
|
968
|
+
response: ctx.response,
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
/** Handle debug command and update state */
|
|
972
|
+
handleDebugCommand(cmd) {
|
|
973
|
+
if (!this.debugController)
|
|
974
|
+
return;
|
|
975
|
+
switch (cmd.type) {
|
|
976
|
+
case 'abort':
|
|
977
|
+
throw new AbortError('Execution aborted by debugger');
|
|
978
|
+
case 'continue':
|
|
979
|
+
this.debugController.mode = 'run';
|
|
980
|
+
break;
|
|
981
|
+
case 'step':
|
|
982
|
+
this.debugController.mode = 'step';
|
|
983
|
+
break;
|
|
984
|
+
case 'step-into':
|
|
985
|
+
this.debugController.mode = 'step-into';
|
|
986
|
+
break;
|
|
987
|
+
case 'step-over':
|
|
988
|
+
this.debugController.mode = 'step-over';
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
663
992
|
}
|