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,256 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
sidebar_position: 2
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Getting Started
|
|
6
|
-
|
|
7
|
-
This guide will help you install Reqon and run your first data pipeline.
|
|
8
|
-
|
|
9
|
-
## Prerequisites
|
|
10
|
-
|
|
11
|
-
- Node.js 18 or later
|
|
12
|
-
- npm or yarn
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install reqon
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Or if you prefer yarn:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
yarn add reqon
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Your First Mission
|
|
27
|
-
|
|
28
|
-
Create a file called `hello.vague`:
|
|
29
|
-
|
|
30
|
-
```vague
|
|
31
|
-
mission HelloWorld {
|
|
32
|
-
source JSONPlaceholder {
|
|
33
|
-
auth: none,
|
|
34
|
-
base: "https://jsonplaceholder.typicode.com"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
store posts: memory("posts")
|
|
38
|
-
|
|
39
|
-
action FetchPosts {
|
|
40
|
-
get "/posts"
|
|
41
|
-
|
|
42
|
-
for post in response {
|
|
43
|
-
map post -> Post {
|
|
44
|
-
id: .id,
|
|
45
|
-
title: .title,
|
|
46
|
-
body: .body,
|
|
47
|
-
userId: .userId
|
|
48
|
-
}
|
|
49
|
-
store post -> posts { key: .id }
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
run FetchPosts
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Running Your Mission
|
|
58
|
-
|
|
59
|
-
### Using the CLI
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
npx reqon hello.vague
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
With verbose output:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
npx reqon hello.vague --verbose
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Using the API
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { execute } from 'reqon';
|
|
75
|
-
|
|
76
|
-
const result = await execute(`
|
|
77
|
-
mission HelloWorld {
|
|
78
|
-
source JSONPlaceholder { auth: none, base: "https://jsonplaceholder.typicode.com" }
|
|
79
|
-
store posts: memory("posts")
|
|
80
|
-
|
|
81
|
-
action FetchPosts {
|
|
82
|
-
get "/posts"
|
|
83
|
-
store response -> posts { key: .id }
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
run FetchPosts
|
|
87
|
-
}
|
|
88
|
-
`);
|
|
89
|
-
|
|
90
|
-
console.log(`Fetched ${result.stores.get('posts')?.list().length} posts`);
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Understanding the Output
|
|
94
|
-
|
|
95
|
-
When you run a mission, Reqon provides detailed execution information:
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
[Reqon] Starting mission: HelloWorld
|
|
99
|
-
[Reqon] Running action: FetchPosts
|
|
100
|
-
[Reqon] GET https://jsonplaceholder.typicode.com/posts
|
|
101
|
-
[Reqon] Stored 100 items to posts
|
|
102
|
-
[Reqon] Mission completed in 234ms
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Mission Structure
|
|
106
|
-
|
|
107
|
-
Every Reqon mission follows this structure:
|
|
108
|
-
|
|
109
|
-
```vague
|
|
110
|
-
mission MissionName {
|
|
111
|
-
// 1. Define data sources (APIs)
|
|
112
|
-
source SourceName { auth: type, base: "url" }
|
|
113
|
-
|
|
114
|
-
// 2. Define storage targets
|
|
115
|
-
store storeName: adapter("name")
|
|
116
|
-
|
|
117
|
-
// 3. Define schemas (optional, for validation)
|
|
118
|
-
schema SchemaName { field: type }
|
|
119
|
-
|
|
120
|
-
// 4. Define actions (processing steps)
|
|
121
|
-
action ActionName {
|
|
122
|
-
// Steps: fetch, map, validate, store, for, match
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 5. Define the pipeline
|
|
126
|
-
run ActionName then AnotherAction
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Adding Transformations
|
|
131
|
-
|
|
132
|
-
Use `map` to transform data:
|
|
133
|
-
|
|
134
|
-
```vague
|
|
135
|
-
action TransformPosts {
|
|
136
|
-
get "/posts"
|
|
137
|
-
|
|
138
|
-
for post in response {
|
|
139
|
-
map post -> BlogPost {
|
|
140
|
-
id: .id,
|
|
141
|
-
title: .title,
|
|
142
|
-
excerpt: substring(.body, 0, 100),
|
|
143
|
-
author: concat("User ", toString(.userId))
|
|
144
|
-
}
|
|
145
|
-
store post -> posts { key: .id }
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Adding Validation
|
|
151
|
-
|
|
152
|
-
Use `validate` to check constraints:
|
|
153
|
-
|
|
154
|
-
```vague
|
|
155
|
-
action ValidatedFetch {
|
|
156
|
-
get "/posts"
|
|
157
|
-
|
|
158
|
-
for post in response {
|
|
159
|
-
validate post {
|
|
160
|
-
assume .id > 0,
|
|
161
|
-
assume length(.title) > 0,
|
|
162
|
-
assume .userId is number
|
|
163
|
-
}
|
|
164
|
-
store post -> posts { key: .id }
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## Handling Pagination
|
|
170
|
-
|
|
171
|
-
Most APIs require pagination. Reqon makes this easy:
|
|
172
|
-
|
|
173
|
-
```vague
|
|
174
|
-
action FetchAllPosts {
|
|
175
|
-
get "/posts" {
|
|
176
|
-
paginate: offset(page, 20),
|
|
177
|
-
until: length(response) == 0
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
store response -> posts { key: .id }
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Error Handling
|
|
185
|
-
|
|
186
|
-
Use `match` for pattern-based error handling:
|
|
187
|
-
|
|
188
|
-
```vague
|
|
189
|
-
action RobustFetch {
|
|
190
|
-
get "/posts"
|
|
191
|
-
|
|
192
|
-
match response {
|
|
193
|
-
{ error: _ } -> abort "API returned error",
|
|
194
|
-
{ data: _ } -> continue,
|
|
195
|
-
_ -> store response -> posts { key: .id }
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Next Steps
|
|
201
|
-
|
|
202
|
-
Now that you've run your first mission, explore these topics:
|
|
203
|
-
|
|
204
|
-
- [Core Concepts](./category/core-concepts) - Understand missions, actions, sources, and stores
|
|
205
|
-
- [DSL Syntax](./category/dsl-syntax) - Learn the complete Reqon syntax
|
|
206
|
-
- [Authentication](./category/authentication) - Connect to authenticated APIs
|
|
207
|
-
- [Examples](./examples) - See more complex examples
|
|
208
|
-
|
|
209
|
-
## Common Issues
|
|
210
|
-
|
|
211
|
-
### "Source not found" Error
|
|
212
|
-
|
|
213
|
-
Make sure you've defined the source before using it in an action:
|
|
214
|
-
|
|
215
|
-
```vague
|
|
216
|
-
mission Example {
|
|
217
|
-
source API { auth: none, base: "https://api.example.com" } // Define first
|
|
218
|
-
|
|
219
|
-
action FetchData {
|
|
220
|
-
get "/data" // Uses the default source
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
run FetchData
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### "Store not found" Error
|
|
228
|
-
|
|
229
|
-
Ensure stores are defined at the mission level:
|
|
230
|
-
|
|
231
|
-
```vague
|
|
232
|
-
mission Example {
|
|
233
|
-
store myData: memory("data") // Define at mission level
|
|
234
|
-
|
|
235
|
-
action SaveData {
|
|
236
|
-
get "/data"
|
|
237
|
-
store response -> myData { key: .id } // Use in actions
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
run SaveData
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Network Errors
|
|
245
|
-
|
|
246
|
-
Add retry configuration for unreliable networks:
|
|
247
|
-
|
|
248
|
-
```vague
|
|
249
|
-
get "/data" {
|
|
250
|
-
retry: {
|
|
251
|
-
maxAttempts: 3,
|
|
252
|
-
backoff: exponential,
|
|
253
|
-
initialDelay: 1000
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
```
|
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
sidebar_position: 6
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Circuit Breaker
|
|
6
|
-
|
|
7
|
-
The circuit breaker pattern prevents cascading failures when an API is experiencing problems. Reqon includes a built-in circuit breaker for robust error handling.
|
|
8
|
-
|
|
9
|
-
## How It Works
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
┌────────────────────────────────────────┐
|
|
13
|
-
│ │
|
|
14
|
-
▼ │
|
|
15
|
-
┌─────────┐ failures > threshold ┌─────────┐ │
|
|
16
|
-
│ CLOSED │ ───────────────────────│ OPEN │ │
|
|
17
|
-
│ (normal)│ │ (fail) │ │
|
|
18
|
-
└────┬────┘ └────┬────┘ │
|
|
19
|
-
│ │ │
|
|
20
|
-
│ ┌───────────┐ │ │
|
|
21
|
-
│ │ HALF_OPEN │◄────────────┘ │
|
|
22
|
-
│ │ (test) │ after timeout │
|
|
23
|
-
│ └─────┬─────┘ │
|
|
24
|
-
│ │ │
|
|
25
|
-
│ successes > threshold │
|
|
26
|
-
└──────────────┴──────────────────────────┘
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**States:**
|
|
30
|
-
- **CLOSED**: Normal operation, requests pass through
|
|
31
|
-
- **OPEN**: Circuit tripped, requests fail immediately
|
|
32
|
-
- **HALF_OPEN**: Testing if service recovered
|
|
33
|
-
|
|
34
|
-
## Configuration
|
|
35
|
-
|
|
36
|
-
```vague
|
|
37
|
-
source API {
|
|
38
|
-
auth: bearer,
|
|
39
|
-
base: "https://api.example.com",
|
|
40
|
-
circuitBreaker: {
|
|
41
|
-
failureThreshold: 5,
|
|
42
|
-
resetTimeout: 30000,
|
|
43
|
-
successThreshold: 2,
|
|
44
|
-
failureWindow: 60000
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Options
|
|
50
|
-
|
|
51
|
-
| Option | Description | Default |
|
|
52
|
-
|--------|-------------|---------|
|
|
53
|
-
| `failureThreshold` | Failures before opening circuit | 5 |
|
|
54
|
-
| `resetTimeout` | Time before trying half-open (ms) | 30000 |
|
|
55
|
-
| `successThreshold` | Successes needed to close circuit | 2 |
|
|
56
|
-
| `failureWindow` | Window for counting failures (ms) | 60000 |
|
|
57
|
-
|
|
58
|
-
## States Explained
|
|
59
|
-
|
|
60
|
-
### Closed State
|
|
61
|
-
|
|
62
|
-
Normal operation:
|
|
63
|
-
|
|
64
|
-
```vague
|
|
65
|
-
// All requests pass through normally
|
|
66
|
-
get "/data" // Success
|
|
67
|
-
get "/data" // Success
|
|
68
|
-
get "/data" // Failure (1)
|
|
69
|
-
get "/data" // Failure (2)
|
|
70
|
-
get "/data" // Success - counter resets
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Failures are counted within the `failureWindow`. Successes reset the counter.
|
|
74
|
-
|
|
75
|
-
### Open State
|
|
76
|
-
|
|
77
|
-
When `failureThreshold` is reached:
|
|
78
|
-
|
|
79
|
-
```vague
|
|
80
|
-
// After 5 consecutive failures...
|
|
81
|
-
get "/data" // Immediately fails - circuit is OPEN
|
|
82
|
-
get "/data" // Immediately fails - no actual request made
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
All requests fail fast without calling the API.
|
|
86
|
-
|
|
87
|
-
### Half-Open State
|
|
88
|
-
|
|
89
|
-
After `resetTimeout`:
|
|
90
|
-
|
|
91
|
-
```vague
|
|
92
|
-
// After 30 seconds...
|
|
93
|
-
get "/data" // Actually sent - testing if API is back
|
|
94
|
-
|
|
95
|
-
// If success:
|
|
96
|
-
get "/data" // Sent - need 2 successes total
|
|
97
|
-
// After 2 successes, circuit CLOSES
|
|
98
|
-
|
|
99
|
-
// If failure:
|
|
100
|
-
// Circuit goes back to OPEN
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Error Handling with Circuit Breaker
|
|
104
|
-
|
|
105
|
-
```vague
|
|
106
|
-
action FetchWithCircuitBreaker {
|
|
107
|
-
get "/data"
|
|
108
|
-
|
|
109
|
-
match response {
|
|
110
|
-
{ error: "circuit_open" } -> {
|
|
111
|
-
// Circuit is open - API is down
|
|
112
|
-
store { status: "api_down", timestamp: now() } -> statusLog
|
|
113
|
-
abort "API unavailable - circuit breaker open"
|
|
114
|
-
},
|
|
115
|
-
{ error: e } -> {
|
|
116
|
-
// Other errors - may trip circuit
|
|
117
|
-
abort e
|
|
118
|
-
},
|
|
119
|
-
_ -> continue
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Combining with Retry
|
|
125
|
-
|
|
126
|
-
```vague
|
|
127
|
-
source API {
|
|
128
|
-
auth: bearer,
|
|
129
|
-
base: "https://api.example.com",
|
|
130
|
-
circuitBreaker: {
|
|
131
|
-
failureThreshold: 5,
|
|
132
|
-
resetTimeout: 30000
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
action RobustFetch {
|
|
137
|
-
get "/data" {
|
|
138
|
-
retry: {
|
|
139
|
-
maxAttempts: 3,
|
|
140
|
-
backoff: exponential
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
match response {
|
|
145
|
-
{ error: "circuit_open" } -> skip, // Don't retry if circuit is open
|
|
146
|
-
{ error: _ } -> abort "Request failed",
|
|
147
|
-
_ -> store response -> data { key: .id }
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Order of operations:
|
|
153
|
-
1. Check if circuit is open → fail fast if yes
|
|
154
|
-
2. Make request
|
|
155
|
-
3. If fails, retry logic kicks in
|
|
156
|
-
4. Each failure counts toward circuit breaker
|
|
157
|
-
5. After max retries, may trip circuit
|
|
158
|
-
|
|
159
|
-
## Combining with Rate Limiting
|
|
160
|
-
|
|
161
|
-
```vague
|
|
162
|
-
source API {
|
|
163
|
-
auth: bearer,
|
|
164
|
-
base: "https://api.example.com",
|
|
165
|
-
rateLimit: {
|
|
166
|
-
requestsPerMinute: 60,
|
|
167
|
-
strategy: "pause"
|
|
168
|
-
},
|
|
169
|
-
circuitBreaker: {
|
|
170
|
-
failureThreshold: 5,
|
|
171
|
-
resetTimeout: 30000
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Both work together:
|
|
177
|
-
- Rate limiter controls request pacing
|
|
178
|
-
- Circuit breaker handles API failures
|
|
179
|
-
|
|
180
|
-
## Per-Source Circuit Breakers
|
|
181
|
-
|
|
182
|
-
Each source has its own circuit breaker:
|
|
183
|
-
|
|
184
|
-
```vague
|
|
185
|
-
mission MultiSourceSync {
|
|
186
|
-
source ReliableAPI {
|
|
187
|
-
auth: bearer,
|
|
188
|
-
base: "https://reliable.api.com",
|
|
189
|
-
circuitBreaker: {
|
|
190
|
-
failureThreshold: 10 // More tolerant
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
source FlakyAPI {
|
|
195
|
-
auth: bearer,
|
|
196
|
-
base: "https://flaky.api.com",
|
|
197
|
-
circuitBreaker: {
|
|
198
|
-
failureThreshold: 3, // Trip quickly
|
|
199
|
-
resetTimeout: 60000 // Wait longer before retry
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
action FetchBoth {
|
|
204
|
-
// Each source's circuit is independent
|
|
205
|
-
get ReliableAPI "/data"
|
|
206
|
-
get FlakyAPI "/data"
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
## Monitoring Circuit State
|
|
212
|
-
|
|
213
|
-
```vague
|
|
214
|
-
action MonitoredFetch {
|
|
215
|
-
get "/data"
|
|
216
|
-
|
|
217
|
-
match response {
|
|
218
|
-
{ error: "circuit_open" } -> {
|
|
219
|
-
store {
|
|
220
|
-
event: "circuit_open",
|
|
221
|
-
source: "API",
|
|
222
|
-
timestamp: now()
|
|
223
|
-
} -> circuitEvents
|
|
224
|
-
skip
|
|
225
|
-
},
|
|
226
|
-
{ error: e } -> {
|
|
227
|
-
store {
|
|
228
|
-
event: "failure",
|
|
229
|
-
error: e,
|
|
230
|
-
timestamp: now()
|
|
231
|
-
} -> circuitEvents
|
|
232
|
-
abort e
|
|
233
|
-
},
|
|
234
|
-
_ -> {
|
|
235
|
-
store {
|
|
236
|
-
event: "success",
|
|
237
|
-
timestamp: now()
|
|
238
|
-
} -> circuitEvents
|
|
239
|
-
continue
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Fallback Patterns
|
|
246
|
-
|
|
247
|
-
### Fallback to Cache
|
|
248
|
-
|
|
249
|
-
```vague
|
|
250
|
-
action FetchWithFallback {
|
|
251
|
-
get "/data"
|
|
252
|
-
|
|
253
|
-
match response {
|
|
254
|
-
{ error: "circuit_open" } -> {
|
|
255
|
-
// Use cached data
|
|
256
|
-
for item in cachedData {
|
|
257
|
-
store item -> data { key: .id }
|
|
258
|
-
}
|
|
259
|
-
continue
|
|
260
|
-
},
|
|
261
|
-
{ data: items } -> {
|
|
262
|
-
// Update cache
|
|
263
|
-
for item in items {
|
|
264
|
-
store item -> cachedData { key: .id }
|
|
265
|
-
store item -> data { key: .id }
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
_ -> abort "Unexpected response"
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Fallback to Secondary Source
|
|
274
|
-
|
|
275
|
-
```vague
|
|
276
|
-
mission FallbackSync {
|
|
277
|
-
source Primary { circuitBreaker: { failureThreshold: 3 } }
|
|
278
|
-
source Secondary { circuitBreaker: { failureThreshold: 5 } }
|
|
279
|
-
|
|
280
|
-
action FetchWithFallback {
|
|
281
|
-
get Primary "/data"
|
|
282
|
-
|
|
283
|
-
match response {
|
|
284
|
-
{ error: "circuit_open" } -> {
|
|
285
|
-
// Primary is down, try secondary
|
|
286
|
-
get Secondary "/data"
|
|
287
|
-
store response -> data { key: .id }
|
|
288
|
-
},
|
|
289
|
-
{ data: _ } -> store response.data -> data { key: .id },
|
|
290
|
-
_ -> abort "Both sources failed"
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
## Best Practices
|
|
297
|
-
|
|
298
|
-
### Configure Based on API Behavior
|
|
299
|
-
|
|
300
|
-
```vague
|
|
301
|
-
// For stable APIs
|
|
302
|
-
circuitBreaker: {
|
|
303
|
-
failureThreshold: 10,
|
|
304
|
-
resetTimeout: 30000
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// For flaky APIs
|
|
308
|
-
circuitBreaker: {
|
|
309
|
-
failureThreshold: 3,
|
|
310
|
-
resetTimeout: 60000
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// For critical APIs (fail fast)
|
|
314
|
-
circuitBreaker: {
|
|
315
|
-
failureThreshold: 2,
|
|
316
|
-
resetTimeout: 10000
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### Use with Error Handling
|
|
321
|
-
|
|
322
|
-
```vague
|
|
323
|
-
action RobustFetch {
|
|
324
|
-
get "/data"
|
|
325
|
-
|
|
326
|
-
match response {
|
|
327
|
-
{ error: "circuit_open" } -> {
|
|
328
|
-
// Log and handle gracefully
|
|
329
|
-
store { event: "circuit_open" } -> logs
|
|
330
|
-
skip
|
|
331
|
-
},
|
|
332
|
-
_ -> continue
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Set Appropriate Timeouts
|
|
338
|
-
|
|
339
|
-
```vague
|
|
340
|
-
// For fast recovery APIs
|
|
341
|
-
circuitBreaker: {
|
|
342
|
-
resetTimeout: 10000 // 10 seconds
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// For slow recovery APIs
|
|
346
|
-
circuitBreaker: {
|
|
347
|
-
resetTimeout: 300000 // 5 minutes
|
|
348
|
-
}
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### Consider Failure Window
|
|
352
|
-
|
|
353
|
-
```vague
|
|
354
|
-
// For burst-tolerant scenarios
|
|
355
|
-
circuitBreaker: {
|
|
356
|
-
failureThreshold: 5,
|
|
357
|
-
failureWindow: 60000 // 1 minute window
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// For strict scenarios
|
|
361
|
-
circuitBreaker: {
|
|
362
|
-
failureThreshold: 3,
|
|
363
|
-
failureWindow: 10000 // 10 second window
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
## Troubleshooting
|
|
368
|
-
|
|
369
|
-
### Circuit Trips Too Often
|
|
370
|
-
|
|
371
|
-
Increase threshold or window:
|
|
372
|
-
|
|
373
|
-
```vague
|
|
374
|
-
circuitBreaker: {
|
|
375
|
-
failureThreshold: 10, // More tolerance
|
|
376
|
-
failureWindow: 120000 // Longer window
|
|
377
|
-
}
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### Circuit Stays Open Too Long
|
|
381
|
-
|
|
382
|
-
Decrease reset timeout:
|
|
383
|
-
|
|
384
|
-
```vague
|
|
385
|
-
circuitBreaker: {
|
|
386
|
-
resetTimeout: 10000 // Try sooner
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
### False Positives
|
|
391
|
-
|
|
392
|
-
Ensure only real failures count:
|
|
393
|
-
|
|
394
|
-
```vague
|
|
395
|
-
match response {
|
|
396
|
-
{ code: 404 } -> skip, // Not a failure
|
|
397
|
-
{ code: 400 } -> abort "Bad request", // Not a failure
|
|
398
|
-
{ code: 500 } -> abort "Server error", // This counts as failure
|
|
399
|
-
_ -> continue
|
|
400
|
-
}
|
|
401
|
-
```
|