reqon-dsl 0.2.0 → 0.4.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 +45 -3
- package/dist/ast/nodes.d.ts +91 -4
- package/dist/ast/nodes.js +14 -0
- package/dist/auth/circuit-breaker.d.ts +11 -0
- package/dist/auth/circuit-breaker.js +90 -18
- package/dist/auth/credentials.d.ts +6 -1
- package/dist/auth/credentials.js +12 -4
- package/dist/auth/oauth2-provider.js +13 -3
- package/dist/auth/rate-limiter.d.ts +12 -1
- package/dist/auth/rate-limiter.js +39 -26
- package/dist/auth/token-store.js +8 -1
- package/dist/cli.d.ts +24 -1
- package/dist/cli.js +149 -10
- package/dist/config/constants.d.ts +152 -0
- package/dist/config/constants.js +139 -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 +105 -0
- package/dist/control/server.js +315 -0
- package/dist/control/types.d.ts +61 -0
- package/dist/control/types.js +7 -0
- package/dist/debug/cli-debugger.d.ts +17 -0
- package/dist/debug/cli-debugger.js +185 -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/execution/store.js +2 -2
- package/dist/execution-log/events.d.ts +125 -0
- package/dist/execution-log/events.js +17 -0
- package/dist/execution-log/fold.d.ts +38 -0
- package/dist/execution-log/fold.js +54 -0
- package/dist/execution-log/index.d.ts +18 -0
- package/dist/execution-log/index.js +6 -0
- package/dist/execution-log/postgres-store.d.ts +36 -0
- package/dist/execution-log/postgres-store.js +108 -0
- package/dist/execution-log/resume.d.ts +11 -0
- package/dist/execution-log/resume.js +5 -0
- package/dist/execution-log/sqlite-store.d.ts +16 -0
- package/dist/execution-log/sqlite-store.js +101 -0
- package/dist/execution-log/store.d.ts +72 -0
- package/dist/execution-log/store.js +182 -0
- package/dist/index.d.ts +23 -2
- package/dist/index.js +35 -3
- package/dist/interpreter/context.d.ts +29 -0
- package/dist/interpreter/context.js +18 -0
- package/dist/interpreter/evaluator.d.ts +63 -1
- package/dist/interpreter/evaluator.js +219 -42
- package/dist/interpreter/executor.d.ts +132 -14
- package/dist/interpreter/executor.js +883 -178
- package/dist/interpreter/fetch-handler.d.ts +48 -1
- package/dist/interpreter/fetch-handler.js +216 -38
- package/dist/interpreter/http.d.ts +34 -0
- package/dist/interpreter/http.js +203 -28
- package/dist/interpreter/index.d.ts +5 -3
- package/dist/interpreter/index.js +4 -2
- package/dist/interpreter/pagination.d.ts +12 -3
- package/dist/interpreter/pagination.js +102 -32
- 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 +16 -0
- package/dist/interpreter/step-handlers/for-handler.js +89 -7
- 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 +47 -17
- 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 +17 -1
- package/dist/interpreter/step-handlers/store-handler.js +61 -20
- 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 +7 -2
- package/dist/interpreter/step-handlers/webhook-handler.d.ts +4 -0
- package/dist/interpreter/step-handlers/webhook-handler.js +31 -5
- package/dist/interpreter/store-manager.d.ts +46 -0
- package/dist/interpreter/store-manager.js +70 -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/loader/index.js +5 -8
- package/dist/mcp/index.d.ts +11 -0
- package/dist/mcp/index.js +11 -0
- package/dist/mcp/sandbox.d.ts +41 -0
- package/dist/mcp/sandbox.js +76 -0
- package/dist/mcp/server.d.ts +17 -0
- package/dist/mcp/server.js +504 -0
- package/dist/oas/index.d.ts +2 -0
- package/dist/oas/index.js +1 -0
- package/dist/oas/loader.d.ts +13 -1
- package/dist/oas/loader.js +25 -3
- package/dist/oas/mock-generator.d.ts +12 -0
- package/dist/oas/mock-generator.js +196 -0
- package/dist/oas/validator.js +45 -5
- package/dist/observability/events.d.ts +248 -0
- package/dist/observability/events.js +85 -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 +266 -0
- package/dist/observability/otel.d.ts +143 -0
- package/dist/observability/otel.js +421 -0
- package/dist/parser/action-parser.d.ts +105 -0
- package/dist/parser/action-parser.js +645 -0
- package/dist/parser/base.d.ts +7 -0
- package/dist/parser/base.js +11 -0
- package/dist/parser/expressions.d.ts +14 -0
- package/dist/parser/expressions.js +89 -6
- package/dist/parser/fetch-parser.d.ts +27 -0
- package/dist/parser/fetch-parser.js +280 -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 +15 -0
- package/dist/pause/index.js +12 -0
- package/dist/pause/log-store.d.ts +33 -0
- package/dist/pause/log-store.js +98 -0
- package/dist/pause/manager.d.ts +130 -0
- package/dist/pause/manager.js +294 -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 +158 -0
- package/dist/plugin.d.ts +9 -12
- package/dist/plugin.js +10 -13
- package/dist/scheduler/cron-parser.d.ts +10 -3
- package/dist/scheduler/cron-parser.js +227 -48
- package/dist/scheduler/scheduler.js +56 -22
- package/dist/stores/factory.d.ts +7 -1
- package/dist/stores/factory.js +14 -3
- package/dist/stores/file.d.ts +26 -0
- package/dist/stores/file.js +67 -21
- 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 +8 -6
- package/dist/stores/postgrest.d.ts +28 -0
- package/dist/stores/postgrest.js +84 -37
- package/dist/stores/types.d.ts +17 -0
- package/dist/stores/types.js +12 -0
- package/dist/sync/index.d.ts +3 -2
- package/dist/sync/index.js +2 -1
- package/dist/sync/log-store.d.ts +30 -0
- package/dist/sync/log-store.js +45 -0
- package/dist/sync/store.js +1 -1
- package/dist/trace/index.d.ts +18 -0
- package/dist/trace/index.js +13 -0
- package/dist/trace/log-view.d.ts +57 -0
- package/dist/trace/log-view.js +76 -0
- package/dist/trace/recorder.d.ts +75 -0
- package/dist/trace/recorder.js +157 -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 +75 -0
- package/dist/trace/store.js +250 -0
- package/dist/utils/deep-merge.d.ts +10 -0
- package/dist/utils/deep-merge.js +23 -0
- package/dist/utils/file.d.ts +13 -4
- package/dist/utils/file.js +70 -12
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/long-timeout.d.ts +19 -0
- package/dist/utils/long-timeout.js +33 -0
- package/dist/utils/path.d.ts +22 -1
- package/dist/utils/path.js +46 -1
- package/dist/utils/redact.d.ts +22 -0
- package/dist/utils/redact.js +42 -0
- package/dist/utils/type-guards.d.ts +58 -0
- package/dist/utils/type-guards.js +92 -0
- package/dist/webhook/server.d.ts +9 -0
- package/dist/webhook/server.js +122 -36
- package/dist/webhook/types.d.ts +9 -1
- package/package.json +76 -9
- 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
|
@@ -2,6 +2,7 @@ import type { FetchStep } from '../ast/nodes.js';
|
|
|
2
2
|
import type { ExecutionContext } from './context.js';
|
|
3
3
|
import type { OASSource } from '../oas/index.js';
|
|
4
4
|
import { type SyncStore } from '../sync/index.js';
|
|
5
|
+
import type { EventType } from '../observability/index.js';
|
|
5
6
|
export interface FetchHandlerDeps {
|
|
6
7
|
ctx: ExecutionContext;
|
|
7
8
|
oasSources: Map<string, OASSource>;
|
|
@@ -15,6 +16,37 @@ export interface FetchHandlerDeps {
|
|
|
15
16
|
executionId?: string;
|
|
16
17
|
dryRun?: boolean;
|
|
17
18
|
log: (message: string) => void;
|
|
19
|
+
/** Optional event emitter for observability */
|
|
20
|
+
emit?: <T>(type: EventType, payload: T) => void;
|
|
21
|
+
/**
|
|
22
|
+
* When set (durable mode), mutating requests carry a stable Idempotency-Key
|
|
23
|
+
* derived from (executionId, stepId, request signature) so retries and
|
|
24
|
+
* replays don't double-apply server-side where the API honours the header.
|
|
25
|
+
*/
|
|
26
|
+
idempotency?: {
|
|
27
|
+
executionId: string;
|
|
28
|
+
stepId: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Resumable (backfill) pagination, wired in durable mode. `resume` seeds the
|
|
32
|
+
* starting page/cursor from the folded log; `onPage` records each completed
|
|
33
|
+
* page back to the log; `maxItemsPerRun` bounds memory per run (a backfill
|
|
34
|
+
* that exceeds it stops cleanly and continues on the next resume).
|
|
35
|
+
*/
|
|
36
|
+
pagination?: {
|
|
37
|
+
resume?: {
|
|
38
|
+
page: number;
|
|
39
|
+
cursor?: string;
|
|
40
|
+
done: boolean;
|
|
41
|
+
};
|
|
42
|
+
onPage?: (progress: {
|
|
43
|
+
page: number;
|
|
44
|
+
cursor?: string;
|
|
45
|
+
recordCount: number;
|
|
46
|
+
done: boolean;
|
|
47
|
+
}) => Promise<void>;
|
|
48
|
+
maxItemsPerRun?: number;
|
|
49
|
+
};
|
|
18
50
|
}
|
|
19
51
|
export interface FetchResult {
|
|
20
52
|
data: unknown;
|
|
@@ -31,13 +63,28 @@ export declare class FetchHandler {
|
|
|
31
63
|
* Execute a fetch step, handling OAS resolution, pagination, and sync checkpoints.
|
|
32
64
|
*/
|
|
33
65
|
execute(step: FetchStep): Promise<FetchResult>;
|
|
66
|
+
private isRetryableError;
|
|
34
67
|
/**
|
|
35
68
|
* Record a sync checkpoint after successful fetch.
|
|
36
69
|
*/
|
|
37
|
-
recordCheckpoint(key: string, step: FetchStep, data: unknown): Promise<
|
|
70
|
+
recordCheckpoint(key: string, step: FetchStep, data: unknown, fallbackTime?: Date): Promise<Date | undefined>;
|
|
38
71
|
private resolveFetchTarget;
|
|
39
72
|
private resolveSinceParams;
|
|
73
|
+
/**
|
|
74
|
+
* Idempotency-Key header for a mutating request, when durable mode is on.
|
|
75
|
+
*
|
|
76
|
+
* GET is safe and gets no key. The key is a hash of
|
|
77
|
+
* (executionId, stepId, method, path, body) so it is stable across retries
|
|
78
|
+
* and replays of the same request, yet distinct per loop iteration (different
|
|
79
|
+
* path/body) — letting a cooperating API dedupe re-issued effects.
|
|
80
|
+
*/
|
|
81
|
+
private idempotencyKeyFor;
|
|
40
82
|
private executePaginated;
|
|
41
83
|
private countRecords;
|
|
42
84
|
private validateOASResponse;
|
|
85
|
+
/**
|
|
86
|
+
* Generate mock data for dry run mode.
|
|
87
|
+
* Uses OAS response schema if available, otherwise returns a simple placeholder.
|
|
88
|
+
*/
|
|
89
|
+
private generateDryRunMockData;
|
|
43
90
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { evaluate, interpolatePath } from './evaluator.js';
|
|
2
|
-
import { resolveOperation, getResponseSchema, validateResponse } from '../oas/index.js';
|
|
3
|
+
import { resolveOperation, getResponseSchema, validateResponse, generateMockData, } from '../oas/index.js';
|
|
3
4
|
import { generateCheckpointKey, formatSinceDate } from '../sync/index.js';
|
|
4
5
|
import { extractNestedValue } from '../utils/path.js';
|
|
5
6
|
import { createPaginationStrategy } from './pagination.js';
|
|
6
7
|
/** Maximum pages to fetch to prevent infinite loops */
|
|
7
8
|
const MAX_PAGINATION_PAGES = 100;
|
|
9
|
+
/**
|
|
10
|
+
* Maximum items to accumulate in memory across all pages. Results are buffered
|
|
11
|
+
* in one array (no per-page streaming yet), so this caps memory regardless of
|
|
12
|
+
* page size. Hitting it stops pagination with a warning.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_PAGINATION_ITEMS = 100_000;
|
|
8
15
|
/**
|
|
9
16
|
* Handles HTTP fetch operations including pagination and incremental sync.
|
|
10
17
|
* Extracted from MissionExecutor for better separation of concerns.
|
|
@@ -23,36 +30,92 @@ export class FetchHandler {
|
|
|
23
30
|
if (!client) {
|
|
24
31
|
throw new Error(`Source not found: ${resolved.sourceName}`);
|
|
25
32
|
}
|
|
26
|
-
// Resolve "since" query parameter for incremental sync
|
|
27
|
-
const { query: sinceQuery, checkpointKey } = await this.resolveSinceParams(step, resolved.sourceName, resolved.operationId, resolved.path);
|
|
33
|
+
// Resolve "since" query parameter and/or header for incremental sync
|
|
34
|
+
const { query: sinceQuery, headers: sinceHeaders, checkpointKey, } = await this.resolveSinceParams(step, resolved.sourceName, resolved.operationId, resolved.path);
|
|
35
|
+
// Emit fetch.start event
|
|
36
|
+
this.deps.emit?.('fetch.start', {
|
|
37
|
+
source: resolved.sourceName,
|
|
38
|
+
method: resolved.method,
|
|
39
|
+
path: resolved.path,
|
|
40
|
+
isOAS: !!resolved.operationId,
|
|
41
|
+
operationId: resolved.operationId,
|
|
42
|
+
hasPagination: !!step.paginate,
|
|
43
|
+
hasSince: !!step.since,
|
|
44
|
+
});
|
|
45
|
+
const _fetchStartTime = Date.now(); // Reserved for fetch duration tracking
|
|
28
46
|
if (this.deps.dryRun) {
|
|
47
|
+
const mockData = this.generateDryRunMockData(resolved.sourceName, resolved.operationId);
|
|
29
48
|
this.deps.log('(dry run - skipping actual request)');
|
|
30
|
-
return { data:
|
|
49
|
+
return { data: mockData, checkpointKey };
|
|
31
50
|
}
|
|
32
51
|
// Execute with or without pagination
|
|
33
52
|
let data;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
53
|
+
let pagesFetched;
|
|
54
|
+
let statusCode = 200;
|
|
55
|
+
try {
|
|
56
|
+
if (step.paginate) {
|
|
57
|
+
const result = await this.executePaginated(step, client, resolved.path, resolved.method, resolved.sourceName, resolved.operationId, sinceQuery, sinceHeaders);
|
|
58
|
+
data = result;
|
|
59
|
+
pagesFetched = Array.isArray(result) ? undefined : 1; // Will be set by executePaginated
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const body = step.body ? evaluate(step.body, this.deps.ctx) : undefined;
|
|
63
|
+
const response = await client.request({
|
|
64
|
+
method: resolved.method,
|
|
65
|
+
path: resolved.path,
|
|
66
|
+
query: Object.keys(sinceQuery).length > 0 ? sinceQuery : undefined,
|
|
67
|
+
headers: Object.keys(sinceHeaders).length > 0 ? sinceHeaders : undefined,
|
|
68
|
+
body,
|
|
69
|
+
idempotencyKey: this.idempotencyKeyFor(resolved.method, resolved.path, body),
|
|
70
|
+
}, step.retry);
|
|
71
|
+
await this.validateOASResponse(resolved.sourceName, resolved.operationId, response.data);
|
|
72
|
+
data = response.data;
|
|
73
|
+
statusCode = response.status ?? 200;
|
|
74
|
+
}
|
|
75
|
+
// Emit fetch.complete event
|
|
76
|
+
this.deps.emit?.('fetch.complete', {
|
|
77
|
+
source: resolved.sourceName,
|
|
39
78
|
method: resolved.method,
|
|
40
79
|
path: resolved.path,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
80
|
+
statusCode,
|
|
81
|
+
recordCount: this.countRecords(data) ?? 0,
|
|
82
|
+
pagesFetched,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Emit fetch.error event
|
|
87
|
+
this.deps.emit?.('fetch.error', {
|
|
88
|
+
source: resolved.sourceName,
|
|
89
|
+
path: resolved.path,
|
|
90
|
+
error: error.message,
|
|
91
|
+
retryable: this.isRetryableError(error),
|
|
92
|
+
});
|
|
93
|
+
throw error;
|
|
46
94
|
}
|
|
47
95
|
return { data, checkpointKey };
|
|
48
96
|
}
|
|
97
|
+
isRetryableError(error) {
|
|
98
|
+
if (error instanceof Error) {
|
|
99
|
+
const message = error.message.toLowerCase();
|
|
100
|
+
return (message.includes('timeout') ||
|
|
101
|
+
message.includes('network') ||
|
|
102
|
+
message.includes('rate limit') ||
|
|
103
|
+
message.includes('429') ||
|
|
104
|
+
message.includes('503') ||
|
|
105
|
+
message.includes('502'));
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
49
109
|
/**
|
|
50
110
|
* Record a sync checkpoint after successful fetch.
|
|
51
111
|
*/
|
|
52
|
-
async recordCheckpoint(key, step, data) {
|
|
112
|
+
async recordCheckpoint(key, step, data, fallbackTime) {
|
|
53
113
|
if (!this.deps.syncStore)
|
|
54
|
-
return;
|
|
55
|
-
|
|
114
|
+
return undefined;
|
|
115
|
+
// Prefer the data's own clock; otherwise fall back to when the request was
|
|
116
|
+
// issued (not now), so records written server-side during the fetch are
|
|
117
|
+
// re-fetched next run rather than skipped on clock skew.
|
|
118
|
+
let syncedAt = fallbackTime ?? new Date();
|
|
56
119
|
// If updateFrom is specified, extract the timestamp from response
|
|
57
120
|
if (step.since?.updateFrom && data && typeof data === 'object') {
|
|
58
121
|
const extracted = extractNestedValue(data, step.since.updateFrom);
|
|
@@ -76,6 +139,14 @@ export class FetchHandler {
|
|
|
76
139
|
executionId: this.deps.executionId,
|
|
77
140
|
});
|
|
78
141
|
this.deps.log(`Recorded sync checkpoint: ${key} at ${syncedAt.toISOString()}`);
|
|
142
|
+
// Emit sync.checkpoint event
|
|
143
|
+
this.deps.emit?.('sync.checkpoint', {
|
|
144
|
+
checkpointKey: key,
|
|
145
|
+
lastSyncTime: syncedAt.toISOString(),
|
|
146
|
+
recordsFetched: recordCount ?? 0,
|
|
147
|
+
isIncremental: true,
|
|
148
|
+
});
|
|
149
|
+
return syncedAt;
|
|
79
150
|
}
|
|
80
151
|
resolveFetchTarget(step) {
|
|
81
152
|
if (step.operationRef) {
|
|
@@ -92,7 +163,15 @@ export class FetchHandler {
|
|
|
92
163
|
return { sourceName, method: operation.method, path, operationId };
|
|
93
164
|
}
|
|
94
165
|
// Traditional: explicit method + path
|
|
95
|
-
|
|
166
|
+
let sourceName = step.source;
|
|
167
|
+
if (!sourceName) {
|
|
168
|
+
// Use the first available source as default
|
|
169
|
+
const firstSource = this.deps.ctx.sources.keys().next();
|
|
170
|
+
if (firstSource.done) {
|
|
171
|
+
throw new Error('No sources defined. Add a source to your mission before making fetch requests.');
|
|
172
|
+
}
|
|
173
|
+
sourceName = firstSource.value;
|
|
174
|
+
}
|
|
96
175
|
const method = step.method;
|
|
97
176
|
let path;
|
|
98
177
|
if (step.path.type === 'Literal' && step.path.dataType === 'string') {
|
|
@@ -106,25 +185,55 @@ export class FetchHandler {
|
|
|
106
185
|
}
|
|
107
186
|
async resolveSinceParams(step, sourceName, operationId, path) {
|
|
108
187
|
const query = {};
|
|
188
|
+
const headers = {};
|
|
109
189
|
if (!step.since || !this.deps.syncStore) {
|
|
110
|
-
return { query };
|
|
190
|
+
return { query, headers };
|
|
111
191
|
}
|
|
112
192
|
const checkpointKey = step.since.key ?? generateCheckpointKey(sourceName, operationId, path);
|
|
113
193
|
if (step.since.type === 'lastSync') {
|
|
114
194
|
const lastSync = await this.deps.syncStore.getLastSync(checkpointKey);
|
|
115
|
-
const paramName = step.since.param ?? 'since';
|
|
116
195
|
const format = step.since.format ?? 'iso';
|
|
117
|
-
|
|
118
|
-
|
|
196
|
+
const formattedDate = formatSinceDate(lastSync, format);
|
|
197
|
+
if (step.since.header) {
|
|
198
|
+
// Send as header (e.g., If-Modified-Since)
|
|
199
|
+
headers[step.since.header] = formattedDate;
|
|
200
|
+
this.deps.log(`Incremental sync: header ${step.since.header}=${formattedDate} (key: ${checkpointKey})`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// Send as query parameter (default behavior)
|
|
204
|
+
const paramName = step.since.param ?? 'since';
|
|
205
|
+
query[paramName] = formattedDate;
|
|
206
|
+
this.deps.log(`Incremental sync: ${paramName}=${formattedDate} (key: ${checkpointKey})`);
|
|
207
|
+
}
|
|
119
208
|
}
|
|
120
209
|
else if (step.since.type === 'expression' && step.since.expression) {
|
|
121
210
|
const value = evaluate(step.since.expression, this.deps.ctx);
|
|
122
|
-
|
|
123
|
-
|
|
211
|
+
if (step.since.header) {
|
|
212
|
+
headers[step.since.header] = String(value);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const paramName = step.since.param ?? 'since';
|
|
216
|
+
query[paramName] = String(value);
|
|
217
|
+
}
|
|
124
218
|
}
|
|
125
|
-
return { query, checkpointKey };
|
|
219
|
+
return { query, headers, checkpointKey };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Idempotency-Key header for a mutating request, when durable mode is on.
|
|
223
|
+
*
|
|
224
|
+
* GET is safe and gets no key. The key is a hash of
|
|
225
|
+
* (executionId, stepId, method, path, body) so it is stable across retries
|
|
226
|
+
* and replays of the same request, yet distinct per loop iteration (different
|
|
227
|
+
* path/body) — letting a cooperating API dedupe re-issued effects.
|
|
228
|
+
*/
|
|
229
|
+
idempotencyKeyFor(method, path, body) {
|
|
230
|
+
if (!this.deps.idempotency || method === 'GET')
|
|
231
|
+
return undefined;
|
|
232
|
+
const { executionId, stepId } = this.deps.idempotency;
|
|
233
|
+
const signature = `${executionId}${stepId}${method}${path}${JSON.stringify(body ?? null)}`;
|
|
234
|
+
return createHash('sha256').update(signature).digest('hex').slice(0, 32);
|
|
126
235
|
}
|
|
127
|
-
async executePaginated(step, client, basePath, method, sourceName, operationId, sinceQuery = {}) {
|
|
236
|
+
async executePaginated(step, client, basePath, method, sourceName, operationId, sinceQuery = {}, sinceHeaders = {}) {
|
|
128
237
|
const allResults = [];
|
|
129
238
|
const paginate = step.paginate;
|
|
130
239
|
const strategy = createPaginationStrategy(paginate);
|
|
@@ -132,32 +241,82 @@ export class FetchHandler {
|
|
|
132
241
|
page: 0,
|
|
133
242
|
pageSize: paginate.pageSize,
|
|
134
243
|
};
|
|
244
|
+
// Resumable (backfill) pagination: seed the cursor/page from the last
|
|
245
|
+
// persisted position so a restart continues from where it stopped.
|
|
246
|
+
const backfill = this.deps.pagination;
|
|
247
|
+
if (step.backfill && backfill?.resume) {
|
|
248
|
+
if (backfill.resume.done) {
|
|
249
|
+
this.deps.log('Backfill already complete; nothing to fetch.');
|
|
250
|
+
return [];
|
|
251
|
+
}
|
|
252
|
+
ctx.page = backfill.resume.page;
|
|
253
|
+
ctx.cursor = backfill.resume.cursor;
|
|
254
|
+
this.deps.log(`Resuming backfill from page ${ctx.page + 1}`);
|
|
255
|
+
}
|
|
256
|
+
// Per-run item cap. For a backfill this bounds memory per run: when hit, the
|
|
257
|
+
// run stops *incomplete* and a later resume continues — so an arbitrarily
|
|
258
|
+
// large backfill completes across runs without buffering it all at once.
|
|
259
|
+
const itemCap = backfill?.maxItemsPerRun ?? MAX_PAGINATION_ITEMS;
|
|
135
260
|
let hasMore = true;
|
|
261
|
+
let stoppedByCap = false;
|
|
136
262
|
while (hasMore) {
|
|
137
263
|
// Build query with pagination params
|
|
138
264
|
const paginationQuery = strategy.buildQuery(ctx);
|
|
139
265
|
const query = { ...sinceQuery, ...paginationQuery };
|
|
266
|
+
const headers = Object.keys(sinceHeaders).length > 0 ? sinceHeaders : undefined;
|
|
140
267
|
this.deps.log(`Fetching page ${ctx.page + 1}...`);
|
|
141
|
-
const response = await client.request({ method, path: basePath, query }, step.retry);
|
|
268
|
+
const response = await client.request({ method, path: basePath, query, headers }, step.retry);
|
|
142
269
|
await this.validateOASResponse(sourceName, operationId, response.data);
|
|
143
270
|
// Temporarily set response for until condition evaluation
|
|
144
271
|
this.deps.ctx.response = response.data;
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
const shouldStop = evaluate(step.until, this.deps.ctx);
|
|
148
|
-
if (shouldStop) {
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
// Extract results using strategy
|
|
272
|
+
// Extract and append the current page BEFORE deciding whether to stop, so
|
|
273
|
+
// the page that satisfies `until` is not silently dropped.
|
|
153
274
|
const pageResult = strategy.extractResults(response.data, ctx);
|
|
154
275
|
allResults.push(...pageResult.items);
|
|
155
276
|
hasMore = pageResult.hasMore;
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
277
|
+
// Advance the cursor. If the API echoes the cursor we just used, stop
|
|
278
|
+
// instead of looping to the page cap and duplicating items each round.
|
|
279
|
+
if (pageResult.nextCursor !== undefined) {
|
|
280
|
+
if (pageResult.nextCursor === ctx.cursor) {
|
|
281
|
+
this.deps.log(`Pagination cursor did not advance ('${pageResult.nextCursor}'); stopping.`);
|
|
282
|
+
hasMore = false;
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
ctx.cursor = pageResult.nextCursor;
|
|
286
|
+
}
|
|
159
287
|
}
|
|
160
288
|
ctx.page++;
|
|
289
|
+
// `until` is checked after the current page has been appended.
|
|
290
|
+
if (hasMore && step.until && evaluate(step.until, this.deps.ctx)) {
|
|
291
|
+
hasMore = false;
|
|
292
|
+
}
|
|
293
|
+
// Memory safety: cap total accumulated items, not just page count. For a
|
|
294
|
+
// backfill this is a clean stop-and-resume boundary, not an end of data.
|
|
295
|
+
if (allResults.length >= itemCap) {
|
|
296
|
+
this.deps.log(`Pagination item limit (${itemCap}) reached`);
|
|
297
|
+
if (hasMore)
|
|
298
|
+
stoppedByCap = true;
|
|
299
|
+
hasMore = false;
|
|
300
|
+
}
|
|
301
|
+
// Record this page's position for a resumable backfill. `done` is the
|
|
302
|
+
// natural end of pagination — never set when we stopped on the item cap,
|
|
303
|
+
// so a resume knows to continue rather than treat the backfill as finished.
|
|
304
|
+
if (step.backfill && backfill?.onPage) {
|
|
305
|
+
await backfill.onPage({
|
|
306
|
+
page: ctx.page,
|
|
307
|
+
cursor: ctx.cursor,
|
|
308
|
+
recordCount: pageResult.items.length,
|
|
309
|
+
done: !hasMore && !stoppedByCap,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
// Emit heartbeat after each page
|
|
313
|
+
this.deps.emit?.('fetch.heartbeat', {
|
|
314
|
+
source: sourceName,
|
|
315
|
+
path: basePath,
|
|
316
|
+
pagesProcessed: ctx.page,
|
|
317
|
+
itemsFetched: allResults.length,
|
|
318
|
+
hasMore,
|
|
319
|
+
});
|
|
161
320
|
// Safety limit
|
|
162
321
|
if (ctx.page >= MAX_PAGINATION_PAGES) {
|
|
163
322
|
this.deps.log(`Warning: pagination limit (${MAX_PAGINATION_PAGES}) reached`);
|
|
@@ -200,4 +359,23 @@ export class FetchHandler {
|
|
|
200
359
|
this.deps.log(`Response validation warnings for ${operationId}:\n${errorMessages}`);
|
|
201
360
|
}
|
|
202
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Generate mock data for dry run mode.
|
|
364
|
+
* Uses OAS response schema if available, otherwise returns a simple placeholder.
|
|
365
|
+
*/
|
|
366
|
+
generateDryRunMockData(sourceName, operationId) {
|
|
367
|
+
// Try to get schema from OAS source
|
|
368
|
+
if (operationId) {
|
|
369
|
+
const oasSource = this.deps.oasSources.get(sourceName);
|
|
370
|
+
if (oasSource) {
|
|
371
|
+
const schema = getResponseSchema(oasSource, operationId);
|
|
372
|
+
if (schema) {
|
|
373
|
+
this.deps.log(`Generating mock data from OAS schema for ${operationId}`);
|
|
374
|
+
return generateMockData(schema);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// Fallback to simple placeholder
|
|
379
|
+
return { _dryRun: true, _message: 'No OAS schema available for mock generation' };
|
|
380
|
+
}
|
|
203
381
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { RetryConfig } from '../ast/nodes.js';
|
|
2
2
|
import type { RateLimiter } from '../auth/types.js';
|
|
3
3
|
import { CircuitBreaker } from '../auth/circuit-breaker.js';
|
|
4
|
+
/**
|
|
5
|
+
* Parse a `Retry-After` header into a delay in ms, clamped to `maxDelayMs`.
|
|
6
|
+
* The header may be delta-seconds (`120`) or an HTTP-date; a date in the past or
|
|
7
|
+
* an unparseable value yields 0 and `undefined` respectively. Clamping stops a
|
|
8
|
+
* hostile/broken server from pinning the client for hours, and the date branch
|
|
9
|
+
* stops `parseInt` from turning a date into `NaN` → `sleep(NaN)` → a tight loop.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseRetryAfterMs(value: string | null | undefined, maxDelayMs: number): number | undefined;
|
|
4
12
|
export interface HttpClientConfig {
|
|
5
13
|
baseUrl: string;
|
|
6
14
|
headers?: Record<string, string>;
|
|
@@ -9,6 +17,8 @@ export interface HttpClientConfig {
|
|
|
9
17
|
circuitBreaker?: CircuitBreaker;
|
|
10
18
|
/** Source name for rate limit and circuit breaker tracking */
|
|
11
19
|
sourceName?: string;
|
|
20
|
+
/** Default per-request timeout in ms (overridden by RetryConfig.timeout) */
|
|
21
|
+
timeout?: number;
|
|
12
22
|
}
|
|
13
23
|
export interface AuthProvider {
|
|
14
24
|
getToken(): Promise<string>;
|
|
@@ -20,6 +30,12 @@ export interface HttpRequest {
|
|
|
20
30
|
body?: unknown;
|
|
21
31
|
headers?: Record<string, string>;
|
|
22
32
|
query?: Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Opt a non-idempotent request (POST/PATCH) into automatic retries by
|
|
35
|
+
* supplying an idempotency key. Sent as the `Idempotency-Key` header so the
|
|
36
|
+
* server can dedup a re-sent write.
|
|
37
|
+
*/
|
|
38
|
+
idempotencyKey?: string;
|
|
23
39
|
}
|
|
24
40
|
export interface HttpResponse<T = unknown> {
|
|
25
41
|
status: number;
|
|
@@ -30,6 +46,21 @@ export declare class HttpClient {
|
|
|
30
46
|
private config;
|
|
31
47
|
constructor(config: HttpClientConfig);
|
|
32
48
|
request<T = unknown>(req: HttpRequest, retry?: RetryConfig): Promise<HttpResponse<T>>;
|
|
49
|
+
/**
|
|
50
|
+
* Run a fetch with a per-attempt timeout. Aborts the request (freeing the
|
|
51
|
+
* connection and rate-limiter slot) if it exceeds `timeoutMs`, surfacing a
|
|
52
|
+
* retryable FetchError rather than hanging forever.
|
|
53
|
+
*/
|
|
54
|
+
private fetchWithTimeout;
|
|
55
|
+
/**
|
|
56
|
+
* Parse a successful (2xx) response body. Handles empty/204 responses,
|
|
57
|
+
* returns non-JSON content as raw text, and caps the buffered size.
|
|
58
|
+
*/
|
|
59
|
+
private parseResponseBody;
|
|
60
|
+
/** Read a response body to text, rejecting once it exceeds MAX_RESPONSE_BYTES. */
|
|
61
|
+
private readCappedText;
|
|
62
|
+
/** Read a short snippet of a body for an error message (best-effort). */
|
|
63
|
+
private safeReadSnippet;
|
|
33
64
|
private buildUrl;
|
|
34
65
|
private buildHeaders;
|
|
35
66
|
private calculateDelay;
|
|
@@ -45,6 +76,8 @@ export declare class OAuth2AuthProvider implements AuthProvider {
|
|
|
45
76
|
private tokenEndpoint?;
|
|
46
77
|
private clientId?;
|
|
47
78
|
private clientSecret?;
|
|
79
|
+
/** Single-flight guard: coalesces concurrent refreshes into one in-flight request */
|
|
80
|
+
private refreshPromise;
|
|
48
81
|
constructor(config: {
|
|
49
82
|
accessToken: string;
|
|
50
83
|
refreshToken?: string;
|
|
@@ -54,4 +87,5 @@ export declare class OAuth2AuthProvider implements AuthProvider {
|
|
|
54
87
|
});
|
|
55
88
|
getToken(): Promise<string>;
|
|
56
89
|
refreshToken(): Promise<string>;
|
|
90
|
+
private doRefresh;
|
|
57
91
|
}
|