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
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pause Manager - Orchestrates resource-free long pauses
|
|
3
|
+
*
|
|
4
|
+
* Handles pause creation, monitoring, and resume coordination.
|
|
5
|
+
* Integrates with webhook server for webhook-based resume triggers.
|
|
6
|
+
*/
|
|
7
|
+
import { createPauseState, parseDuration, isPauseExpired, getRemainingTime, formatDuration, } from './state.js';
|
|
8
|
+
/**
|
|
9
|
+
* Manages resource-free long pauses
|
|
10
|
+
*/
|
|
11
|
+
export class PauseManager {
|
|
12
|
+
config;
|
|
13
|
+
pollTimer;
|
|
14
|
+
isRunning = false;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a new pause and persist state
|
|
20
|
+
*/
|
|
21
|
+
async createPause(options) {
|
|
22
|
+
const duration = parseDuration(options.duration);
|
|
23
|
+
// Build resume trigger states
|
|
24
|
+
const resumeTriggers = [];
|
|
25
|
+
// Always include timeout by default
|
|
26
|
+
const triggers = options.resumeTriggers ?? [{ type: 'timeout' }];
|
|
27
|
+
const hasTimeout = triggers.some((t) => t.type === 'timeout');
|
|
28
|
+
if (!hasTimeout) {
|
|
29
|
+
triggers.push({ type: 'timeout' });
|
|
30
|
+
}
|
|
31
|
+
for (const trigger of triggers) {
|
|
32
|
+
if (trigger.type === 'timeout') {
|
|
33
|
+
resumeTriggers.push({ type: 'timeout', active: true });
|
|
34
|
+
}
|
|
35
|
+
else if (trigger.type === 'webhook') {
|
|
36
|
+
const triggerState = {
|
|
37
|
+
type: 'webhook',
|
|
38
|
+
path: trigger.path,
|
|
39
|
+
active: true,
|
|
40
|
+
};
|
|
41
|
+
// Register webhook if server available
|
|
42
|
+
if (this.config.webhookServer) {
|
|
43
|
+
const registration = await this.registerWebhookTrigger(options.executionId, trigger.path, duration);
|
|
44
|
+
triggerState.registrationId = registration.id;
|
|
45
|
+
}
|
|
46
|
+
resumeTriggers.push(triggerState);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Create pause state
|
|
50
|
+
const pause = createPauseState(options.executionId, options.mission, duration, options.checkpoint, resumeTriggers);
|
|
51
|
+
// Persist
|
|
52
|
+
await this.config.store.save(pause);
|
|
53
|
+
this.log(`Created pause ${pause.id} for ${formatDuration(duration)}`);
|
|
54
|
+
return pause;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resume a pause manually
|
|
58
|
+
*/
|
|
59
|
+
async resumeManually(pauseId) {
|
|
60
|
+
const pause = await this.config.store.load(pauseId);
|
|
61
|
+
if (!pause) {
|
|
62
|
+
throw new Error(`Pause not found: ${pauseId}`);
|
|
63
|
+
}
|
|
64
|
+
if (pause.status !== 'waiting') {
|
|
65
|
+
throw new Error(`Pause ${pauseId} is not waiting (status: ${pause.status})`);
|
|
66
|
+
}
|
|
67
|
+
return this.markResumed(pause, 'manual');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Resume a pause by execution ID
|
|
71
|
+
*/
|
|
72
|
+
async resumeByExecution(executionId) {
|
|
73
|
+
const pause = await this.config.store.loadByExecution(executionId);
|
|
74
|
+
if (!pause) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return this.resumeManually(pause.id);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Cancel a pause (without resuming execution)
|
|
81
|
+
*/
|
|
82
|
+
async cancelPause(pauseId) {
|
|
83
|
+
const pause = await this.config.store.load(pauseId);
|
|
84
|
+
if (!pause) {
|
|
85
|
+
throw new Error(`Pause not found: ${pauseId}`);
|
|
86
|
+
}
|
|
87
|
+
if (pause.status !== 'waiting') {
|
|
88
|
+
return; // Already not waiting
|
|
89
|
+
}
|
|
90
|
+
await this.config.store.update(pauseId, {
|
|
91
|
+
status: 'cancelled',
|
|
92
|
+
resumedAt: new Date(),
|
|
93
|
+
resumedBy: 'cancelled',
|
|
94
|
+
});
|
|
95
|
+
// Cleanup webhook registrations
|
|
96
|
+
await this.cleanupWebhooks(pause);
|
|
97
|
+
this.log(`Cancelled pause ${pauseId}`);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Handle webhook callback for a pause
|
|
101
|
+
*/
|
|
102
|
+
async handleWebhook(pauseId, payload) {
|
|
103
|
+
const pause = await this.config.store.load(pauseId);
|
|
104
|
+
if (!pause || pause.status !== 'waiting') {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
// Check if this pause has an active webhook trigger
|
|
108
|
+
const webhookTrigger = pause.resumeTriggers.find((t) => t.type === 'webhook' && t.active);
|
|
109
|
+
if (!webhookTrigger) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
// Mark resumed with webhook payload
|
|
113
|
+
await this.markResumed(pause, 'webhook', payload);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Start monitoring for expired pauses
|
|
118
|
+
*/
|
|
119
|
+
startMonitoring() {
|
|
120
|
+
if (this.isRunning)
|
|
121
|
+
return;
|
|
122
|
+
this.isRunning = true;
|
|
123
|
+
const interval = this.config.pollInterval ?? 60000; // Default: 1 minute
|
|
124
|
+
this.pollTimer = setInterval(async () => {
|
|
125
|
+
await this.checkExpiredPauses();
|
|
126
|
+
}, interval);
|
|
127
|
+
this.log(`Started pause monitoring (interval: ${formatDuration(interval)})`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Stop monitoring
|
|
131
|
+
*/
|
|
132
|
+
stopMonitoring() {
|
|
133
|
+
if (this.pollTimer) {
|
|
134
|
+
clearInterval(this.pollTimer);
|
|
135
|
+
this.pollTimer = undefined;
|
|
136
|
+
}
|
|
137
|
+
this.isRunning = false;
|
|
138
|
+
this.log('Stopped pause monitoring');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check for and process expired pauses
|
|
142
|
+
*/
|
|
143
|
+
async checkExpiredPauses() {
|
|
144
|
+
const expired = await this.config.store.findExpired();
|
|
145
|
+
const resumed = [];
|
|
146
|
+
for (const pause of expired) {
|
|
147
|
+
const updated = await this.markResumed(pause, 'timeout');
|
|
148
|
+
resumed.push(updated);
|
|
149
|
+
}
|
|
150
|
+
return resumed;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get all active pauses
|
|
154
|
+
*/
|
|
155
|
+
async getActivePauses() {
|
|
156
|
+
return this.config.store.listActive();
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get pause by ID
|
|
160
|
+
*/
|
|
161
|
+
async getPause(pauseId) {
|
|
162
|
+
return this.config.store.load(pauseId);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get pause status summary
|
|
166
|
+
*/
|
|
167
|
+
async getStatus() {
|
|
168
|
+
const active = await this.config.store.listActive();
|
|
169
|
+
const expired = active.filter((p) => isPauseExpired(p));
|
|
170
|
+
const waiting = active.filter((p) => !isPauseExpired(p));
|
|
171
|
+
return {
|
|
172
|
+
totalActive: active.length,
|
|
173
|
+
waiting: waiting.length,
|
|
174
|
+
expired: expired.length,
|
|
175
|
+
nextExpiration: waiting.length > 0
|
|
176
|
+
? waiting.reduce((min, p) => (p.expiresAt < min ? p.expiresAt : min), waiting[0].expiresAt)
|
|
177
|
+
: undefined,
|
|
178
|
+
pauses: active.map((p) => ({
|
|
179
|
+
id: p.id,
|
|
180
|
+
mission: p.mission,
|
|
181
|
+
executionId: p.executionId,
|
|
182
|
+
remaining: getRemainingTime(p),
|
|
183
|
+
remainingFormatted: formatDuration(getRemainingTime(p)),
|
|
184
|
+
})),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
async markResumed(pause, resumedBy, webhookPayload) {
|
|
188
|
+
const updates = {
|
|
189
|
+
status: 'resumed',
|
|
190
|
+
resumedAt: new Date(),
|
|
191
|
+
resumedBy,
|
|
192
|
+
};
|
|
193
|
+
if (webhookPayload !== undefined) {
|
|
194
|
+
updates.webhookPayload = webhookPayload;
|
|
195
|
+
}
|
|
196
|
+
await this.config.store.update(pause.id, updates);
|
|
197
|
+
// Cleanup webhook registrations
|
|
198
|
+
await this.cleanupWebhooks(pause);
|
|
199
|
+
const updated = await this.config.store.load(pause.id);
|
|
200
|
+
if (!updated) {
|
|
201
|
+
throw new Error(`Failed to load updated pause: ${pause.id}`);
|
|
202
|
+
}
|
|
203
|
+
this.log(`Pause ${pause.id} resumed by ${resumedBy}`);
|
|
204
|
+
// Trigger callback
|
|
205
|
+
if (this.config.onResume) {
|
|
206
|
+
await this.config.onResume(updated);
|
|
207
|
+
}
|
|
208
|
+
return updated;
|
|
209
|
+
}
|
|
210
|
+
async registerWebhookTrigger(executionId, path, timeout) {
|
|
211
|
+
if (!this.config.webhookServer) {
|
|
212
|
+
throw new Error('Webhook server not configured for webhook triggers');
|
|
213
|
+
}
|
|
214
|
+
// Register a webhook listener that will call handleWebhook
|
|
215
|
+
const registration = await this.config.webhookServer.register(executionId, {
|
|
216
|
+
path,
|
|
217
|
+
timeout,
|
|
218
|
+
expectedEvents: 1,
|
|
219
|
+
});
|
|
220
|
+
return { id: registration.id };
|
|
221
|
+
}
|
|
222
|
+
async cleanupWebhooks(pause) {
|
|
223
|
+
if (!this.config.webhookServer)
|
|
224
|
+
return;
|
|
225
|
+
for (const trigger of pause.resumeTriggers) {
|
|
226
|
+
if (trigger.type === 'webhook' && trigger.registrationId) {
|
|
227
|
+
try {
|
|
228
|
+
await this.config.webhookServer.unregister(trigger.registrationId);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Ignore cleanup errors
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
log(message) {
|
|
237
|
+
this.config.log?.(`[PauseManager] ${message}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Create a pause manager
|
|
242
|
+
*/
|
|
243
|
+
export function createPauseManager(config) {
|
|
244
|
+
return new PauseManager(config);
|
|
245
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pause State - Types for resource-free long pauses
|
|
3
|
+
*
|
|
4
|
+
* Supports pausing execution for extended periods (days/weeks)
|
|
5
|
+
* while persisting state and releasing resources.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Persisted pause state
|
|
9
|
+
*/
|
|
10
|
+
export interface PauseState {
|
|
11
|
+
/** Unique pause ID */
|
|
12
|
+
id: string;
|
|
13
|
+
/** Execution ID this pause belongs to */
|
|
14
|
+
executionId: string;
|
|
15
|
+
/** Mission name */
|
|
16
|
+
mission: string;
|
|
17
|
+
/** When the pause started */
|
|
18
|
+
pausedAt: Date;
|
|
19
|
+
/** When the pause will expire (resume due to timeout) */
|
|
20
|
+
expiresAt: Date;
|
|
21
|
+
/** Original duration specified (in milliseconds) */
|
|
22
|
+
duration: number;
|
|
23
|
+
/** Current status */
|
|
24
|
+
status: 'waiting' | 'resumed' | 'expired' | 'cancelled';
|
|
25
|
+
/** How the pause was resumed (if resumed) */
|
|
26
|
+
resumedBy?: 'timeout' | 'webhook' | 'manual' | 'cancelled';
|
|
27
|
+
/** When resumed */
|
|
28
|
+
resumedAt?: Date;
|
|
29
|
+
/** Resume trigger configuration */
|
|
30
|
+
resumeTriggers: PauseResumeTriggerState[];
|
|
31
|
+
/** Checkpoint data for resuming execution */
|
|
32
|
+
checkpoint: PauseCheckpoint;
|
|
33
|
+
/** Webhook data if resumed by webhook */
|
|
34
|
+
webhookPayload?: unknown;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resume trigger state
|
|
38
|
+
*/
|
|
39
|
+
export interface PauseResumeTriggerState {
|
|
40
|
+
type: 'timeout' | 'webhook';
|
|
41
|
+
/** For webhook: the registered path */
|
|
42
|
+
path?: string;
|
|
43
|
+
/** For webhook: registration ID */
|
|
44
|
+
registrationId?: string;
|
|
45
|
+
/** Whether this trigger is active */
|
|
46
|
+
active: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Checkpoint data for resuming after pause
|
|
50
|
+
*/
|
|
51
|
+
export interface PauseCheckpoint {
|
|
52
|
+
/** Stage index to resume from */
|
|
53
|
+
stageIndex: number;
|
|
54
|
+
/** Step index within action to resume from (after pause step) */
|
|
55
|
+
stepIndex: number;
|
|
56
|
+
/** Current action name */
|
|
57
|
+
action: string;
|
|
58
|
+
/** For loops: current item index */
|
|
59
|
+
itemIndex?: number;
|
|
60
|
+
/** Saved context variables */
|
|
61
|
+
variables: Record<string, unknown>;
|
|
62
|
+
/** Saved response value */
|
|
63
|
+
response?: unknown;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generate a unique pause ID
|
|
67
|
+
*/
|
|
68
|
+
export declare function generatePauseId(executionId: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Parse duration string to milliseconds
|
|
71
|
+
* Supports: "7d", "1d", "12h", "30m", "45s", or raw milliseconds
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseDuration(duration: string | number): number;
|
|
74
|
+
/**
|
|
75
|
+
* Format duration for display
|
|
76
|
+
*/
|
|
77
|
+
export declare function formatDuration(ms: number): string;
|
|
78
|
+
/**
|
|
79
|
+
* Create initial pause state
|
|
80
|
+
*/
|
|
81
|
+
export declare function createPauseState(executionId: string, mission: string, duration: number, checkpoint: PauseCheckpoint, resumeTriggers: PauseResumeTriggerState[]): PauseState;
|
|
82
|
+
/**
|
|
83
|
+
* Check if a pause has expired
|
|
84
|
+
*/
|
|
85
|
+
export declare function isPauseExpired(pause: PauseState): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Get remaining time for a pause (in milliseconds)
|
|
88
|
+
*/
|
|
89
|
+
export declare function getRemainingTime(pause: PauseState): number;
|
|
90
|
+
/**
|
|
91
|
+
* Get pause summary for display
|
|
92
|
+
*/
|
|
93
|
+
export declare function getPauseSummary(pause: PauseState): string;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pause State - Types for resource-free long pauses
|
|
3
|
+
*
|
|
4
|
+
* Supports pausing execution for extended periods (days/weeks)
|
|
5
|
+
* while persisting state and releasing resources.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generate a unique pause ID
|
|
9
|
+
*/
|
|
10
|
+
export function generatePauseId(executionId) {
|
|
11
|
+
const timestamp = Date.now().toString(36);
|
|
12
|
+
const random = Math.random().toString(36).substring(2, 6);
|
|
13
|
+
return `pause_${executionId}_${timestamp}_${random}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse duration string to milliseconds
|
|
17
|
+
* Supports: "7d", "1d", "12h", "30m", "45s", or raw milliseconds
|
|
18
|
+
*/
|
|
19
|
+
export function parseDuration(duration) {
|
|
20
|
+
if (typeof duration === 'number') {
|
|
21
|
+
return duration;
|
|
22
|
+
}
|
|
23
|
+
const match = duration.match(/^(\d+(?:\.\d+)?)\s*(d|h|m|s|ms)?$/i);
|
|
24
|
+
if (!match) {
|
|
25
|
+
throw new Error(`Invalid duration format: ${duration}. Use "7d", "12h", "30m", "45s", or milliseconds.`);
|
|
26
|
+
}
|
|
27
|
+
const value = parseFloat(match[1]);
|
|
28
|
+
const unit = (match[2] || 'ms').toLowerCase();
|
|
29
|
+
const multipliers = {
|
|
30
|
+
ms: 1,
|
|
31
|
+
s: 1000,
|
|
32
|
+
m: 60 * 1000,
|
|
33
|
+
h: 60 * 60 * 1000,
|
|
34
|
+
d: 24 * 60 * 60 * 1000,
|
|
35
|
+
};
|
|
36
|
+
const multiplier = multipliers[unit];
|
|
37
|
+
if (multiplier === undefined) {
|
|
38
|
+
throw new Error(`Unknown duration unit: ${unit}`);
|
|
39
|
+
}
|
|
40
|
+
return Math.round(value * multiplier);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Format duration for display
|
|
44
|
+
*/
|
|
45
|
+
export function formatDuration(ms) {
|
|
46
|
+
if (ms < 1000)
|
|
47
|
+
return `${ms}ms`;
|
|
48
|
+
if (ms < 60 * 1000)
|
|
49
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
50
|
+
if (ms < 60 * 60 * 1000)
|
|
51
|
+
return `${(ms / (60 * 1000)).toFixed(1)}m`;
|
|
52
|
+
if (ms < 24 * 60 * 60 * 1000)
|
|
53
|
+
return `${(ms / (60 * 60 * 1000)).toFixed(1)}h`;
|
|
54
|
+
return `${(ms / (24 * 60 * 60 * 1000)).toFixed(1)}d`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create initial pause state
|
|
58
|
+
*/
|
|
59
|
+
export function createPauseState(executionId, mission, duration, checkpoint, resumeTriggers) {
|
|
60
|
+
const now = new Date();
|
|
61
|
+
return {
|
|
62
|
+
id: generatePauseId(executionId),
|
|
63
|
+
executionId,
|
|
64
|
+
mission,
|
|
65
|
+
pausedAt: now,
|
|
66
|
+
expiresAt: new Date(now.getTime() + duration),
|
|
67
|
+
duration,
|
|
68
|
+
status: 'waiting',
|
|
69
|
+
resumeTriggers,
|
|
70
|
+
checkpoint,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a pause has expired
|
|
75
|
+
*/
|
|
76
|
+
export function isPauseExpired(pause) {
|
|
77
|
+
return pause.status === 'waiting' && new Date() >= pause.expiresAt;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get remaining time for a pause (in milliseconds)
|
|
81
|
+
*/
|
|
82
|
+
export function getRemainingTime(pause) {
|
|
83
|
+
if (pause.status !== 'waiting')
|
|
84
|
+
return 0;
|
|
85
|
+
const remaining = pause.expiresAt.getTime() - Date.now();
|
|
86
|
+
return Math.max(0, remaining);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get pause summary for display
|
|
90
|
+
*/
|
|
91
|
+
export function getPauseSummary(pause) {
|
|
92
|
+
const remaining = getRemainingTime(pause);
|
|
93
|
+
if (pause.status === 'resumed') {
|
|
94
|
+
return `Pause ${pause.id}: resumed by ${pause.resumedBy} at ${pause.resumedAt?.toISOString()}`;
|
|
95
|
+
}
|
|
96
|
+
if (pause.status === 'expired') {
|
|
97
|
+
return `Pause ${pause.id}: expired at ${pause.expiresAt.toISOString()}`;
|
|
98
|
+
}
|
|
99
|
+
if (pause.status === 'cancelled') {
|
|
100
|
+
return `Pause ${pause.id}: cancelled`;
|
|
101
|
+
}
|
|
102
|
+
return `Pause ${pause.id}: waiting (${formatDuration(remaining)} remaining)`;
|
|
103
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pause Store - Persistence for pause states
|
|
3
|
+
*
|
|
4
|
+
* Stores pause state for resource-free long pauses,
|
|
5
|
+
* enabling resumption after extended periods.
|
|
6
|
+
*/
|
|
7
|
+
import type { PauseState } from './state.js';
|
|
8
|
+
/**
|
|
9
|
+
* Pause store interface
|
|
10
|
+
*/
|
|
11
|
+
export interface PauseStore {
|
|
12
|
+
/** Save a pause state */
|
|
13
|
+
save(pause: PauseState): Promise<void>;
|
|
14
|
+
/** Load a pause by ID */
|
|
15
|
+
load(id: string): Promise<PauseState | null>;
|
|
16
|
+
/** Load pause by execution ID */
|
|
17
|
+
loadByExecution(executionId: string): Promise<PauseState | null>;
|
|
18
|
+
/** List all active (waiting) pauses */
|
|
19
|
+
listActive(): Promise<PauseState[]>;
|
|
20
|
+
/** List pauses for a mission */
|
|
21
|
+
listByMission(mission: string): Promise<PauseState[]>;
|
|
22
|
+
/** Delete a pause state */
|
|
23
|
+
delete(id: string): Promise<void>;
|
|
24
|
+
/** Find pauses that have expired but not yet processed */
|
|
25
|
+
findExpired(): Promise<PauseState[]>;
|
|
26
|
+
/** Update pause state (e.g., when resumed) */
|
|
27
|
+
update(id: string, updates: Partial<PauseState>): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* File-based pause store
|
|
31
|
+
*/
|
|
32
|
+
export declare class FilePauseStore implements PauseStore {
|
|
33
|
+
private baseDir;
|
|
34
|
+
private initialized;
|
|
35
|
+
constructor(baseDir?: string);
|
|
36
|
+
private getFilePath;
|
|
37
|
+
private deserialize;
|
|
38
|
+
save(pause: PauseState): Promise<void>;
|
|
39
|
+
load(id: string): Promise<PauseState | null>;
|
|
40
|
+
loadByExecution(executionId: string): Promise<PauseState | null>;
|
|
41
|
+
listActive(): Promise<PauseState[]>;
|
|
42
|
+
listByMission(mission: string): Promise<PauseState[]>;
|
|
43
|
+
delete(id: string): Promise<void>;
|
|
44
|
+
findExpired(): Promise<PauseState[]>;
|
|
45
|
+
update(id: string, updates: Partial<PauseState>): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* In-memory pause store (for testing)
|
|
49
|
+
*/
|
|
50
|
+
export declare class MemoryPauseStore implements PauseStore {
|
|
51
|
+
private pauses;
|
|
52
|
+
save(pause: PauseState): Promise<void>;
|
|
53
|
+
load(id: string): Promise<PauseState | null>;
|
|
54
|
+
loadByExecution(executionId: string): Promise<PauseState | null>;
|
|
55
|
+
listActive(): Promise<PauseState[]>;
|
|
56
|
+
listByMission(mission: string): Promise<PauseState[]>;
|
|
57
|
+
delete(id: string): Promise<void>;
|
|
58
|
+
findExpired(): Promise<PauseState[]>;
|
|
59
|
+
update(id: string, updates: Partial<PauseState>): Promise<void>;
|
|
60
|
+
clear(): void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pause Store - Persistence for pause states
|
|
3
|
+
*
|
|
4
|
+
* Stores pause state for resource-free long pauses,
|
|
5
|
+
* enabling resumption after extended periods.
|
|
6
|
+
*/
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { ensureDirectory, writeJsonFile, readJsonFile, listFiles, deleteFile, restoreDates, } from '../utils/file.js';
|
|
9
|
+
/**
|
|
10
|
+
* File-based pause store
|
|
11
|
+
*/
|
|
12
|
+
export class FilePauseStore {
|
|
13
|
+
baseDir;
|
|
14
|
+
initialized;
|
|
15
|
+
constructor(baseDir = '.reqon-data/pauses') {
|
|
16
|
+
this.baseDir = baseDir;
|
|
17
|
+
this.initialized = ensureDirectory(this.baseDir);
|
|
18
|
+
}
|
|
19
|
+
getFilePath(id) {
|
|
20
|
+
return join(this.baseDir, `${id}.json`);
|
|
21
|
+
}
|
|
22
|
+
deserialize(parsed) {
|
|
23
|
+
restoreDates(parsed, ['pausedAt', 'expiresAt', 'resumedAt']);
|
|
24
|
+
return parsed;
|
|
25
|
+
}
|
|
26
|
+
async save(pause) {
|
|
27
|
+
await this.initialized;
|
|
28
|
+
await writeJsonFile(this.getFilePath(pause.id), pause);
|
|
29
|
+
}
|
|
30
|
+
async load(id) {
|
|
31
|
+
await this.initialized;
|
|
32
|
+
const parsed = await readJsonFile(this.getFilePath(id));
|
|
33
|
+
return parsed ? this.deserialize(parsed) : null;
|
|
34
|
+
}
|
|
35
|
+
async loadByExecution(executionId) {
|
|
36
|
+
const all = await this.listActive();
|
|
37
|
+
return all.find((p) => p.executionId === executionId) ?? null;
|
|
38
|
+
}
|
|
39
|
+
async listActive() {
|
|
40
|
+
await this.initialized;
|
|
41
|
+
const files = await listFiles(this.baseDir, '.json');
|
|
42
|
+
const pauses = [];
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
const parsed = await readJsonFile(file);
|
|
45
|
+
if (parsed) {
|
|
46
|
+
const pause = this.deserialize(parsed);
|
|
47
|
+
if (pause.status === 'waiting') {
|
|
48
|
+
pauses.push(pause);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return pauses.sort((a, b) => a.expiresAt.getTime() - b.expiresAt.getTime());
|
|
53
|
+
}
|
|
54
|
+
async listByMission(mission) {
|
|
55
|
+
await this.initialized;
|
|
56
|
+
const files = await listFiles(this.baseDir, '.json');
|
|
57
|
+
const pauses = [];
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
const parsed = await readJsonFile(file);
|
|
60
|
+
if (parsed) {
|
|
61
|
+
const pause = this.deserialize(parsed);
|
|
62
|
+
if (pause.mission === mission) {
|
|
63
|
+
pauses.push(pause);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return pauses.sort((a, b) => b.pausedAt.getTime() - a.pausedAt.getTime());
|
|
68
|
+
}
|
|
69
|
+
async delete(id) {
|
|
70
|
+
await this.initialized;
|
|
71
|
+
await deleteFile(this.getFilePath(id));
|
|
72
|
+
}
|
|
73
|
+
async findExpired() {
|
|
74
|
+
const active = await this.listActive();
|
|
75
|
+
const now = new Date();
|
|
76
|
+
return active.filter((p) => p.expiresAt <= now);
|
|
77
|
+
}
|
|
78
|
+
async update(id, updates) {
|
|
79
|
+
const pause = await this.load(id);
|
|
80
|
+
if (!pause) {
|
|
81
|
+
throw new Error(`Pause not found: ${id}`);
|
|
82
|
+
}
|
|
83
|
+
const updated = { ...pause, ...updates };
|
|
84
|
+
await this.save(updated);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* In-memory pause store (for testing)
|
|
89
|
+
*/
|
|
90
|
+
export class MemoryPauseStore {
|
|
91
|
+
pauses = new Map();
|
|
92
|
+
async save(pause) {
|
|
93
|
+
this.pauses.set(pause.id, JSON.parse(JSON.stringify(pause)));
|
|
94
|
+
}
|
|
95
|
+
async load(id) {
|
|
96
|
+
const pause = this.pauses.get(id);
|
|
97
|
+
if (!pause)
|
|
98
|
+
return null;
|
|
99
|
+
const restored = JSON.parse(JSON.stringify(pause));
|
|
100
|
+
restored.pausedAt = new Date(restored.pausedAt);
|
|
101
|
+
restored.expiresAt = new Date(restored.expiresAt);
|
|
102
|
+
if (restored.resumedAt) {
|
|
103
|
+
restored.resumedAt = new Date(restored.resumedAt);
|
|
104
|
+
}
|
|
105
|
+
return restored;
|
|
106
|
+
}
|
|
107
|
+
async loadByExecution(executionId) {
|
|
108
|
+
for (const pause of this.pauses.values()) {
|
|
109
|
+
if (pause.executionId === executionId && pause.status === 'waiting') {
|
|
110
|
+
return this.load(pause.id);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
async listActive() {
|
|
116
|
+
const pauses = [];
|
|
117
|
+
for (const pause of this.pauses.values()) {
|
|
118
|
+
if (pause.status === 'waiting') {
|
|
119
|
+
const loaded = await this.load(pause.id);
|
|
120
|
+
if (loaded)
|
|
121
|
+
pauses.push(loaded);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return pauses.sort((a, b) => a.expiresAt.getTime() - b.expiresAt.getTime());
|
|
125
|
+
}
|
|
126
|
+
async listByMission(mission) {
|
|
127
|
+
const pauses = [];
|
|
128
|
+
for (const pause of this.pauses.values()) {
|
|
129
|
+
if (pause.mission === mission) {
|
|
130
|
+
const loaded = await this.load(pause.id);
|
|
131
|
+
if (loaded)
|
|
132
|
+
pauses.push(loaded);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return pauses.sort((a, b) => b.pausedAt.getTime() - a.pausedAt.getTime());
|
|
136
|
+
}
|
|
137
|
+
async delete(id) {
|
|
138
|
+
this.pauses.delete(id);
|
|
139
|
+
}
|
|
140
|
+
async findExpired() {
|
|
141
|
+
const active = await this.listActive();
|
|
142
|
+
const now = new Date();
|
|
143
|
+
return active.filter((p) => p.expiresAt <= now);
|
|
144
|
+
}
|
|
145
|
+
async update(id, updates) {
|
|
146
|
+
const pause = await this.load(id);
|
|
147
|
+
if (!pause) {
|
|
148
|
+
throw new Error(`Pause not found: ${id}`);
|
|
149
|
+
}
|
|
150
|
+
const updated = { ...pause, ...updates };
|
|
151
|
+
await this.save(updated);
|
|
152
|
+
}
|
|
153
|
+
clear() {
|
|
154
|
+
this.pauses.clear();
|
|
155
|
+
}
|
|
156
|
+
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Or simply import the plugin module to auto-register:
|
|
13
|
-
* import 'reqon/plugin';
|
|
2
|
+
* ---
|
|
3
|
+
* purpose: Vague plugin - registers Reqon keywords with Vague's lexer
|
|
4
|
+
* exports:
|
|
5
|
+
* - reqonPlugin - plugin object for manual registration
|
|
6
|
+
* - registerReqonPlugin, unregisterReqonPlugin - registration helpers
|
|
7
|
+
* related:
|
|
8
|
+
* - ./lexer/tokens.ts - REQON_KEYWORDS map
|
|
9
|
+
* - vague-lang - parent DSL framework
|
|
10
|
+
* ---
|
|
14
11
|
*/
|
|
15
12
|
import { type VaguePlugin } from 'vague-lang';
|
|
16
13
|
/**
|