reqon-dsl 0.2.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/.claude/settings.local.json +31 -0
- package/.claude/skills/api-integration.md +125 -0
- package/.claude/skills/database-schema.md +51 -0
- package/.claude/skills/dsl-design.md +80 -0
- package/.claude/skills/property-testing.md +143 -0
- package/.claude/skills/reqon/SKILL.md +44 -0
- package/.claude/skills/reqon/references/examples.md +206 -0
- package/.claude/skills/reqon/references/syntax.md +263 -0
- package/.claude/skills/vscode-extension.md +113 -0
- package/.github/dependabot.yml +32 -0
- package/.github/pull_request_template.md +21 -0
- package/.github/workflows/ci.yml +174 -0
- package/.github/workflows/release.yml +73 -0
- package/CLAUDE.md +72 -0
- package/CONTRIBUTING.md +161 -0
- package/README.md +235 -0
- package/TODO.md +51 -0
- package/dist/ast/index.d.ts +1 -0
- package/dist/ast/index.js +1 -0
- package/dist/ast/nodes.d.ts +237 -0
- package/dist/ast/nodes.js +12 -0
- package/dist/auth/auth.test.d.ts +1 -0
- package/dist/auth/auth.test.js +255 -0
- package/dist/auth/circuit-breaker.d.ts +115 -0
- package/dist/auth/circuit-breaker.js +267 -0
- package/dist/auth/credentials.d.ts +91 -0
- package/dist/auth/credentials.js +169 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/oauth2-provider.d.ts +41 -0
- package/dist/auth/oauth2-provider.js +131 -0
- package/dist/auth/rate-limiter.d.ts +61 -0
- package/dist/auth/rate-limiter.js +380 -0
- package/dist/auth/token-store.d.ts +30 -0
- package/dist/auth/token-store.js +148 -0
- package/dist/auth/types.d.ts +142 -0
- package/dist/auth/types.js +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +270 -0
- package/dist/errors/errors.test.d.ts +1 -0
- package/dist/errors/errors.test.js +165 -0
- package/dist/errors/index.d.ts +83 -0
- package/dist/errors/index.js +159 -0
- package/dist/execution/execution.test.d.ts +1 -0
- package/dist/execution/execution.test.js +246 -0
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.js +2 -0
- package/dist/execution/state.d.ts +136 -0
- package/dist/execution/state.js +82 -0
- package/dist/execution/store.d.ts +52 -0
- package/dist/execution/store.js +120 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +57 -0
- package/dist/integration.test.d.ts +1 -0
- package/dist/integration.test.js +168 -0
- package/dist/interpreter/context.d.ts +15 -0
- package/dist/interpreter/context.js +29 -0
- package/dist/interpreter/evaluator.d.ts +5 -0
- package/dist/interpreter/evaluator.js +223 -0
- package/dist/interpreter/evaluator.test.d.ts +1 -0
- package/dist/interpreter/evaluator.test.js +512 -0
- package/dist/interpreter/executor.d.ts +131 -0
- package/dist/interpreter/executor.js +663 -0
- package/dist/interpreter/fetch-handler.d.ts +43 -0
- package/dist/interpreter/fetch-handler.js +203 -0
- package/dist/interpreter/http.d.ts +57 -0
- package/dist/interpreter/http.js +210 -0
- package/dist/interpreter/http.test.d.ts +1 -0
- package/dist/interpreter/http.test.js +299 -0
- package/dist/interpreter/index.d.ts +7 -0
- package/dist/interpreter/index.js +7 -0
- package/dist/interpreter/pagination.d.ts +63 -0
- package/dist/interpreter/pagination.js +155 -0
- package/dist/interpreter/progress.test.d.ts +1 -0
- package/dist/interpreter/progress.test.js +216 -0
- package/dist/interpreter/schema-matcher.d.ts +16 -0
- package/dist/interpreter/schema-matcher.js +136 -0
- package/dist/interpreter/schema-matcher.test.d.ts +1 -0
- package/dist/interpreter/schema-matcher.test.js +122 -0
- package/dist/interpreter/signals.d.ts +57 -0
- package/dist/interpreter/signals.js +73 -0
- package/dist/interpreter/step-handlers/for-handler.d.ts +17 -0
- package/dist/interpreter/step-handlers/for-handler.js +51 -0
- package/dist/interpreter/step-handlers/index.d.ts +8 -0
- package/dist/interpreter/step-handlers/index.js +8 -0
- package/dist/interpreter/step-handlers/map-handler.d.ts +10 -0
- package/dist/interpreter/step-handlers/map-handler.js +20 -0
- package/dist/interpreter/step-handlers/match-handler.d.ts +27 -0
- package/dist/interpreter/step-handlers/match-handler.js +61 -0
- package/dist/interpreter/step-handlers/store-handler.d.ts +13 -0
- package/dist/interpreter/step-handlers/store-handler.js +66 -0
- package/dist/interpreter/step-handlers/types.d.ts +15 -0
- package/dist/interpreter/step-handlers/types.js +1 -0
- package/dist/interpreter/step-handlers/validate-handler.d.ts +10 -0
- package/dist/interpreter/step-handlers/validate-handler.js +26 -0
- package/dist/interpreter/step-handlers/webhook-handler.d.ts +36 -0
- package/dist/interpreter/step-handlers/webhook-handler.js +104 -0
- package/dist/lexer/index.d.ts +10 -0
- package/dist/lexer/index.js +12 -0
- package/dist/lexer/lexer.d.ts +24 -0
- package/dist/lexer/lexer.js +264 -0
- package/dist/lexer/lexer.test.d.ts +1 -0
- package/dist/lexer/lexer.test.js +259 -0
- package/dist/lexer/tokens.d.ts +69 -0
- package/dist/lexer/tokens.js +146 -0
- package/dist/loader/index.d.ts +36 -0
- package/dist/loader/index.js +220 -0
- package/dist/loader/loader.test.d.ts +1 -0
- package/dist/loader/loader.test.js +287 -0
- package/dist/oas/index.d.ts +4 -0
- package/dist/oas/index.js +2 -0
- package/dist/oas/loader.d.ts +21 -0
- package/dist/oas/loader.js +82 -0
- package/dist/oas/oas.test.d.ts +1 -0
- package/dist/oas/oas.test.js +218 -0
- package/dist/oas/validator.d.ts +12 -0
- package/dist/oas/validator.js +227 -0
- package/dist/parser/base.d.ts +33 -0
- package/dist/parser/base.js +97 -0
- package/dist/parser/expressions.d.ts +27 -0
- package/dist/parser/expressions.js +248 -0
- package/dist/parser/expressions.test.d.ts +1 -0
- package/dist/parser/expressions.test.js +378 -0
- package/dist/parser/index.d.ts +3 -0
- package/dist/parser/index.js +3 -0
- package/dist/parser/match.test.d.ts +1 -0
- package/dist/parser/match.test.js +254 -0
- package/dist/parser/parser.d.ts +68 -0
- package/dist/parser/parser.js +1229 -0
- package/dist/parser/parser.test.d.ts +1 -0
- package/dist/parser/parser.test.js +333 -0
- package/dist/parser/schedule.test.d.ts +1 -0
- package/dist/parser/schedule.test.js +241 -0
- package/dist/plugin.d.ts +35 -0
- package/dist/plugin.js +68 -0
- package/dist/scheduler/cron-parser.d.ts +32 -0
- package/dist/scheduler/cron-parser.js +198 -0
- package/dist/scheduler/cron-parser.test.d.ts +1 -0
- package/dist/scheduler/cron-parser.test.js +188 -0
- package/dist/scheduler/index.d.ts +3 -0
- package/dist/scheduler/index.js +2 -0
- package/dist/scheduler/scheduler.d.ts +81 -0
- package/dist/scheduler/scheduler.js +376 -0
- package/dist/scheduler/types.d.ts +65 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/stores/factory.d.ts +36 -0
- package/dist/stores/factory.js +73 -0
- package/dist/stores/file.d.ts +60 -0
- package/dist/stores/file.js +173 -0
- package/dist/stores/file.test.d.ts +1 -0
- package/dist/stores/file.test.js +165 -0
- package/dist/stores/index.d.ts +6 -0
- package/dist/stores/index.js +5 -0
- package/dist/stores/memory.d.ts +19 -0
- package/dist/stores/memory.js +51 -0
- package/dist/stores/memory.test.d.ts +1 -0
- package/dist/stores/memory.test.js +157 -0
- package/dist/stores/postgrest.d.ts +55 -0
- package/dist/stores/postgrest.js +217 -0
- package/dist/stores/stores.test.d.ts +1 -0
- package/dist/stores/stores.test.js +158 -0
- package/dist/stores/types.d.ts +31 -0
- package/dist/stores/types.js +26 -0
- package/dist/sync/index.d.ts +4 -0
- package/dist/sync/index.js +2 -0
- package/dist/sync/state.d.ts +69 -0
- package/dist/sync/state.js +66 -0
- package/dist/sync/store.d.ts +49 -0
- package/dist/sync/store.js +93 -0
- package/dist/sync/sync.test.d.ts +1 -0
- package/dist/sync/sync.test.js +221 -0
- package/dist/utils/async.d.ts +7 -0
- package/dist/utils/async.js +9 -0
- package/dist/utils/file.d.ts +38 -0
- package/dist/utils/file.js +92 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.js +39 -0
- package/dist/utils/path.d.ts +12 -0
- package/dist/utils/path.js +41 -0
- package/dist/webhook/index.d.ts +8 -0
- package/dist/webhook/index.js +7 -0
- package/dist/webhook/server.d.ts +84 -0
- package/dist/webhook/server.js +319 -0
- package/dist/webhook/store.d.ts +67 -0
- package/dist/webhook/store.js +193 -0
- package/dist/webhook/types.d.ts +88 -0
- package/dist/webhook/types.js +6 -0
- package/docusaurus/README.md +41 -0
- package/docusaurus/docs/advanced/execution-state.md +283 -0
- package/docusaurus/docs/advanced/extending-reqon.md +388 -0
- package/docusaurus/docs/advanced/multi-file-missions.md +250 -0
- package/docusaurus/docs/advanced/parallel-execution.md +353 -0
- package/docusaurus/docs/api-reference.md +443 -0
- package/docusaurus/docs/authentication/api-key.md +339 -0
- package/docusaurus/docs/authentication/basic.md +276 -0
- package/docusaurus/docs/authentication/bearer.md +282 -0
- package/docusaurus/docs/authentication/oauth2.md +317 -0
- package/docusaurus/docs/authentication/overview.md +251 -0
- package/docusaurus/docs/cli.md +229 -0
- package/docusaurus/docs/core-concepts/actions.md +286 -0
- package/docusaurus/docs/core-concepts/missions.md +264 -0
- package/docusaurus/docs/core-concepts/schemas.md +353 -0
- package/docusaurus/docs/core-concepts/sources.md +339 -0
- package/docusaurus/docs/core-concepts/stores.md +332 -0
- package/docusaurus/docs/dsl-syntax/expressions.md +361 -0
- package/docusaurus/docs/dsl-syntax/fetch.md +293 -0
- package/docusaurus/docs/dsl-syntax/for-loops.md +324 -0
- package/docusaurus/docs/dsl-syntax/map.md +345 -0
- package/docusaurus/docs/dsl-syntax/match.md +387 -0
- package/docusaurus/docs/dsl-syntax/pipelines.md +397 -0
- package/docusaurus/docs/dsl-syntax/validate.md +401 -0
- package/docusaurus/docs/error-handling/dead-letter-queues.md +399 -0
- package/docusaurus/docs/error-handling/flow-control.md +337 -0
- package/docusaurus/docs/error-handling/retry-strategies.md +368 -0
- package/docusaurus/docs/examples.md +488 -0
- package/docusaurus/docs/getting-started.md +256 -0
- package/docusaurus/docs/http/circuit-breaker.md +401 -0
- package/docusaurus/docs/http/incremental-sync.md +394 -0
- package/docusaurus/docs/http/pagination.md +361 -0
- package/docusaurus/docs/http/rate-limiting.md +383 -0
- package/docusaurus/docs/http/requests.md +328 -0
- package/docusaurus/docs/http/retry.md +402 -0
- package/docusaurus/docs/intro.md +90 -0
- package/docusaurus/docs/openapi/loading-specs.md +305 -0
- package/docusaurus/docs/openapi/operation-calls.md +314 -0
- package/docusaurus/docs/openapi/overview.md +212 -0
- package/docusaurus/docs/openapi/response-validation.md +344 -0
- package/docusaurus/docs/scheduling/cron.md +305 -0
- package/docusaurus/docs/scheduling/daemon-mode.md +317 -0
- package/docusaurus/docs/scheduling/intervals.md +289 -0
- package/docusaurus/docs/scheduling/overview.md +231 -0
- package/docusaurus/docs/stores/custom-adapters.md +376 -0
- package/docusaurus/docs/stores/file.md +236 -0
- package/docusaurus/docs/stores/memory.md +193 -0
- package/docusaurus/docs/stores/overview.md +274 -0
- package/docusaurus/docs/stores/postgrest.md +316 -0
- package/docusaurus/docusaurus.config.ts +148 -0
- package/docusaurus/package-lock.json +18029 -0
- package/docusaurus/package.json +47 -0
- package/docusaurus/sidebars.ts +155 -0
- package/docusaurus/src/components/HomepageFeatures/index.tsx +105 -0
- package/docusaurus/src/components/HomepageFeatures/styles.module.css +12 -0
- package/docusaurus/src/css/custom.css +169 -0
- package/docusaurus/src/pages/index.module.css +48 -0
- package/docusaurus/src/pages/index.tsx +110 -0
- package/docusaurus/src/pages/markdown-page.md +7 -0
- 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 +10 -0
- package/docusaurus/static/img/undraw_docusaurus_mountain.svg +171 -0
- package/docusaurus/static/img/undraw_docusaurus_react.svg +170 -0
- package/docusaurus/static/img/undraw_docusaurus_tree.svg +40 -0
- package/docusaurus/tsconfig.json +8 -0
- package/examples/README.md +112 -0
- package/examples/error-handling/README.md +150 -0
- package/examples/error-handling/payment-processor.vague +287 -0
- package/examples/github-sync/README.md +74 -0
- package/examples/github-sync/fetch-issues.vague +47 -0
- package/examples/github-sync/fetch-prs.vague +40 -0
- package/examples/github-sync/mission.vague +101 -0
- package/examples/github-sync/normalize.vague +70 -0
- package/examples/jsonplaceholder/README.md +28 -0
- package/examples/jsonplaceholder/posts.vague +48 -0
- package/examples/petstore/README.md +35 -0
- package/examples/petstore/openapi.yaml +97 -0
- package/examples/petstore/sync.vague +52 -0
- package/examples/temporal-comparison/README.md +297 -0
- package/examples/temporal-comparison/reconciliation.vague +355 -0
- package/examples/temporal-comparison/temporal/activities/index.ts +8 -0
- package/examples/temporal-comparison/temporal/activities/shipstation.ts +225 -0
- package/examples/temporal-comparison/temporal/activities/shopify.ts +257 -0
- package/examples/temporal-comparison/temporal/activities/storage.ts +198 -0
- package/examples/temporal-comparison/temporal/activities/stripe.ts +169 -0
- package/examples/temporal-comparison/temporal/activities/validation.ts +205 -0
- package/examples/temporal-comparison/temporal/client/schedule.ts +218 -0
- package/examples/temporal-comparison/temporal/config/retry.ts +63 -0
- package/examples/temporal-comparison/temporal/types/index.ts +129 -0
- package/examples/temporal-comparison/temporal/workers/main.ts +130 -0
- package/examples/temporal-comparison/temporal/workflows/orderReconciliation.ts +262 -0
- package/examples/xero/README.md +88 -0
- package/examples/xero/invoices.vague +189 -0
- package/package.json +40 -0
- package/src/api-integration.test.ts +954 -0
- package/src/ast/index.ts +1 -0
- package/src/ast/nodes.ts +310 -0
- package/src/auth/auth.test.ts +326 -0
- package/src/auth/circuit-breaker.test.ts +390 -0
- package/src/auth/circuit-breaker.ts +379 -0
- package/src/auth/credentials.test.ts +273 -0
- package/src/auth/credentials.ts +246 -0
- package/src/auth/index.ts +40 -0
- package/src/auth/oauth2-provider.ts +177 -0
- package/src/auth/rate-limiter.ts +459 -0
- package/src/auth/token-store.ts +177 -0
- package/src/auth/types.ts +159 -0
- package/src/benchmark/e2e.bench.ts +288 -0
- package/src/benchmark/evaluator.bench.ts +331 -0
- package/src/benchmark/fixtures.ts +295 -0
- package/src/benchmark/index.ts +108 -0
- package/src/benchmark/lexer.bench.ts +69 -0
- package/src/benchmark/parser.bench.ts +103 -0
- package/src/benchmark/resilience.bench.ts +193 -0
- package/src/benchmark/store.bench.ts +147 -0
- package/src/benchmark/utils.ts +230 -0
- package/src/cli.ts +313 -0
- package/src/errors/errors.test.ts +234 -0
- package/src/errors/index.ts +223 -0
- package/src/execution/execution.test.ts +307 -0
- package/src/execution/index.ts +21 -0
- package/src/execution/state.ts +207 -0
- package/src/execution/store.ts +188 -0
- package/src/index.ts +169 -0
- package/src/integration.test.ts +192 -0
- package/src/interpreter/context.ts +57 -0
- package/src/interpreter/evaluator.test.ts +796 -0
- package/src/interpreter/evaluator.ts +245 -0
- package/src/interpreter/executor.ts +946 -0
- package/src/interpreter/fetch-handler.ts +302 -0
- package/src/interpreter/http.test.ts +423 -0
- package/src/interpreter/http.ts +308 -0
- package/src/interpreter/index.ts +32 -0
- package/src/interpreter/pagination.ts +207 -0
- package/src/interpreter/progress.test.ts +276 -0
- package/src/interpreter/schema-matcher.test.ts +160 -0
- package/src/interpreter/schema-matcher.ts +168 -0
- package/src/interpreter/signals.ts +73 -0
- package/src/interpreter/step-handlers/for-handler.ts +65 -0
- package/src/interpreter/step-handlers/index.ts +17 -0
- package/src/interpreter/step-handlers/map-handler.ts +24 -0
- package/src/interpreter/step-handlers/match-handler.ts +101 -0
- package/src/interpreter/step-handlers/store-handler.ts +78 -0
- package/src/interpreter/step-handlers/types.ts +17 -0
- package/src/interpreter/step-handlers/validate-handler.ts +30 -0
- package/src/interpreter/step-handlers/webhook-handler.ts +142 -0
- package/src/lexer/index.ts +18 -0
- package/src/lexer/lexer.test.ts +316 -0
- package/src/lexer/tokens.ts +179 -0
- package/src/loader/index.ts +288 -0
- package/src/loader/loader.test.ts +360 -0
- package/src/oas/index.ts +4 -0
- package/src/oas/loader.ts +126 -0
- package/src/oas/oas.test.ts +254 -0
- package/src/oas/validator.ts +299 -0
- package/src/parser/base.ts +124 -0
- package/src/parser/expressions.test.ts +525 -0
- package/src/parser/expressions.ts +314 -0
- package/src/parser/index.ts +3 -0
- package/src/parser/match.test.ts +296 -0
- package/src/parser/parser.test.ts +739 -0
- package/src/parser/parser.ts +1469 -0
- package/src/parser/schedule.test.ts +287 -0
- package/src/parser/webhook.test.ts +248 -0
- package/src/plugin.ts +83 -0
- package/src/scheduler/cron-parser.test.ts +236 -0
- package/src/scheduler/cron-parser.ts +236 -0
- package/src/scheduler/index.ts +10 -0
- package/src/scheduler/scheduler.ts +443 -0
- package/src/scheduler/types.ts +71 -0
- package/src/stores/factory.ts +104 -0
- package/src/stores/file.test.ts +276 -0
- package/src/stores/file.ts +211 -0
- package/src/stores/index.ts +6 -0
- package/src/stores/memory.test.ts +238 -0
- package/src/stores/memory.ts +63 -0
- package/src/stores/postgrest.test.ts +488 -0
- package/src/stores/postgrest.ts +263 -0
- package/src/stores/stores.test.ts +197 -0
- package/src/stores/types.ts +58 -0
- package/src/sync/index.ts +16 -0
- package/src/sync/state.ts +126 -0
- package/src/sync/store.ts +139 -0
- package/src/sync/sync.test.ts +271 -0
- package/src/utils/async.ts +10 -0
- package/src/utils/file.ts +106 -0
- package/src/utils/index.ts +14 -0
- package/src/utils/logger.ts +53 -0
- package/src/utils/path.ts +47 -0
- package/src/webhook/index.ts +15 -0
- package/src/webhook/server.test.ts +253 -0
- package/src/webhook/server.ts +389 -0
- package/src/webhook/store.ts +239 -0
- package/src/webhook/types.ts +93 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +39 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook Store
|
|
3
|
+
*
|
|
4
|
+
* Stores webhook registrations and received events.
|
|
5
|
+
* Supports both in-memory and file-based persistence.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { mkdir, readFile, writeFile, readdir, unlink } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import type { WebhookRegistration, WebhookEvent } from './types.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Interface for webhook storage
|
|
14
|
+
*/
|
|
15
|
+
export interface WebhookStore {
|
|
16
|
+
/** Save a webhook registration */
|
|
17
|
+
saveRegistration(registration: WebhookRegistration): Promise<void>;
|
|
18
|
+
/** Get a registration by ID */
|
|
19
|
+
getRegistration(id: string): Promise<WebhookRegistration | undefined>;
|
|
20
|
+
/** Get a registration by path */
|
|
21
|
+
getRegistrationByPath(path: string): Promise<WebhookRegistration | undefined>;
|
|
22
|
+
/** Delete a registration */
|
|
23
|
+
deleteRegistration(id: string): Promise<void>;
|
|
24
|
+
/** List all registrations */
|
|
25
|
+
listRegistrations(): Promise<WebhookRegistration[]>;
|
|
26
|
+
/** Save a webhook event */
|
|
27
|
+
saveEvent(event: WebhookEvent): Promise<void>;
|
|
28
|
+
/** Get events for a registration */
|
|
29
|
+
getEvents(registrationId: string): Promise<WebhookEvent[]>;
|
|
30
|
+
/** Delete events for a registration */
|
|
31
|
+
deleteEvents(registrationId: string): Promise<void>;
|
|
32
|
+
/** Clean up expired registrations */
|
|
33
|
+
cleanupExpired(): Promise<number>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* In-memory webhook store
|
|
38
|
+
*/
|
|
39
|
+
export class MemoryWebhookStore implements WebhookStore {
|
|
40
|
+
private registrations: Map<string, WebhookRegistration> = new Map();
|
|
41
|
+
private events: Map<string, WebhookEvent[]> = new Map();
|
|
42
|
+
private pathIndex: Map<string, string> = new Map(); // path -> registrationId
|
|
43
|
+
|
|
44
|
+
async saveRegistration(registration: WebhookRegistration): Promise<void> {
|
|
45
|
+
this.registrations.set(registration.id, registration);
|
|
46
|
+
this.pathIndex.set(registration.path, registration.id);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async getRegistration(id: string): Promise<WebhookRegistration | undefined> {
|
|
50
|
+
return this.registrations.get(id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async getRegistrationByPath(path: string): Promise<WebhookRegistration | undefined> {
|
|
54
|
+
const id = this.pathIndex.get(path);
|
|
55
|
+
if (!id) return undefined;
|
|
56
|
+
return this.registrations.get(id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async deleteRegistration(id: string): Promise<void> {
|
|
60
|
+
const reg = this.registrations.get(id);
|
|
61
|
+
if (reg) {
|
|
62
|
+
this.pathIndex.delete(reg.path);
|
|
63
|
+
}
|
|
64
|
+
this.registrations.delete(id);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async listRegistrations(): Promise<WebhookRegistration[]> {
|
|
68
|
+
return Array.from(this.registrations.values());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async saveEvent(event: WebhookEvent): Promise<void> {
|
|
72
|
+
const events = this.events.get(event.registrationId) ?? [];
|
|
73
|
+
events.push(event);
|
|
74
|
+
this.events.set(event.registrationId, events);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async getEvents(registrationId: string): Promise<WebhookEvent[]> {
|
|
78
|
+
return this.events.get(registrationId) ?? [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async deleteEvents(registrationId: string): Promise<void> {
|
|
82
|
+
this.events.delete(registrationId);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async cleanupExpired(): Promise<number> {
|
|
86
|
+
const now = new Date();
|
|
87
|
+
let cleaned = 0;
|
|
88
|
+
|
|
89
|
+
for (const [id, reg] of this.registrations) {
|
|
90
|
+
if (reg.expiresAt < now) {
|
|
91
|
+
await this.deleteRegistration(id);
|
|
92
|
+
await this.deleteEvents(id);
|
|
93
|
+
cleaned++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return cleaned;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* File-based webhook store for persistence across restarts
|
|
103
|
+
*/
|
|
104
|
+
export class FileWebhookStore implements WebhookStore {
|
|
105
|
+
private baseDir: string;
|
|
106
|
+
private registrationsDir: string;
|
|
107
|
+
private eventsDir: string;
|
|
108
|
+
private initialized = false;
|
|
109
|
+
|
|
110
|
+
constructor(baseDir = '.reqon-data/webhooks') {
|
|
111
|
+
this.baseDir = baseDir;
|
|
112
|
+
this.registrationsDir = join(baseDir, 'registrations');
|
|
113
|
+
this.eventsDir = join(baseDir, 'events');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private async ensureInit(): Promise<void> {
|
|
117
|
+
if (this.initialized) return;
|
|
118
|
+
await mkdir(this.registrationsDir, { recursive: true });
|
|
119
|
+
await mkdir(this.eventsDir, { recursive: true });
|
|
120
|
+
this.initialized = true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async saveRegistration(registration: WebhookRegistration): Promise<void> {
|
|
124
|
+
await this.ensureInit();
|
|
125
|
+
const filePath = join(this.registrationsDir, `${registration.id}.json`);
|
|
126
|
+
await writeFile(filePath, JSON.stringify(registration, null, 2));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async getRegistration(id: string): Promise<WebhookRegistration | undefined> {
|
|
130
|
+
await this.ensureInit();
|
|
131
|
+
try {
|
|
132
|
+
const filePath = join(this.registrationsDir, `${id}.json`);
|
|
133
|
+
const content = await readFile(filePath, 'utf-8');
|
|
134
|
+
const data = JSON.parse(content);
|
|
135
|
+
return {
|
|
136
|
+
...data,
|
|
137
|
+
createdAt: new Date(data.createdAt),
|
|
138
|
+
expiresAt: new Date(data.expiresAt),
|
|
139
|
+
};
|
|
140
|
+
} catch {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async getRegistrationByPath(path: string): Promise<WebhookRegistration | undefined> {
|
|
146
|
+
const registrations = await this.listRegistrations();
|
|
147
|
+
return registrations.find((r) => r.path === path);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async deleteRegistration(id: string): Promise<void> {
|
|
151
|
+
await this.ensureInit();
|
|
152
|
+
try {
|
|
153
|
+
const filePath = join(this.registrationsDir, `${id}.json`);
|
|
154
|
+
await unlink(filePath);
|
|
155
|
+
} catch {
|
|
156
|
+
// Ignore if file doesn't exist
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async listRegistrations(): Promise<WebhookRegistration[]> {
|
|
161
|
+
await this.ensureInit();
|
|
162
|
+
try {
|
|
163
|
+
const files = await readdir(this.registrationsDir);
|
|
164
|
+
const registrations: WebhookRegistration[] = [];
|
|
165
|
+
|
|
166
|
+
for (const file of files) {
|
|
167
|
+
if (!file.endsWith('.json')) continue;
|
|
168
|
+
const id = file.replace('.json', '');
|
|
169
|
+
const reg = await this.getRegistration(id);
|
|
170
|
+
if (reg) registrations.push(reg);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return registrations;
|
|
174
|
+
} catch {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async saveEvent(event: WebhookEvent): Promise<void> {
|
|
180
|
+
await this.ensureInit();
|
|
181
|
+
const eventDir = join(this.eventsDir, event.registrationId);
|
|
182
|
+
await mkdir(eventDir, { recursive: true });
|
|
183
|
+
const filePath = join(eventDir, `${event.id}.json`);
|
|
184
|
+
await writeFile(filePath, JSON.stringify(event, null, 2));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async getEvents(registrationId: string): Promise<WebhookEvent[]> {
|
|
188
|
+
await this.ensureInit();
|
|
189
|
+
try {
|
|
190
|
+
const eventDir = join(this.eventsDir, registrationId);
|
|
191
|
+
const files = await readdir(eventDir);
|
|
192
|
+
const events: WebhookEvent[] = [];
|
|
193
|
+
|
|
194
|
+
for (const file of files) {
|
|
195
|
+
if (!file.endsWith('.json')) continue;
|
|
196
|
+
const filePath = join(eventDir, file);
|
|
197
|
+
const content = await readFile(filePath, 'utf-8');
|
|
198
|
+
const data = JSON.parse(content);
|
|
199
|
+
events.push({
|
|
200
|
+
...data,
|
|
201
|
+
receivedAt: new Date(data.receivedAt),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return events.sort((a, b) => a.receivedAt.getTime() - b.receivedAt.getTime());
|
|
206
|
+
} catch {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async deleteEvents(registrationId: string): Promise<void> {
|
|
212
|
+
await this.ensureInit();
|
|
213
|
+
try {
|
|
214
|
+
const eventDir = join(this.eventsDir, registrationId);
|
|
215
|
+
const files = await readdir(eventDir);
|
|
216
|
+
for (const file of files) {
|
|
217
|
+
await unlink(join(eventDir, file));
|
|
218
|
+
}
|
|
219
|
+
} catch {
|
|
220
|
+
// Ignore if directory doesn't exist
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async cleanupExpired(): Promise<number> {
|
|
225
|
+
const now = new Date();
|
|
226
|
+
const registrations = await this.listRegistrations();
|
|
227
|
+
let cleaned = 0;
|
|
228
|
+
|
|
229
|
+
for (const reg of registrations) {
|
|
230
|
+
if (reg.expiresAt < now) {
|
|
231
|
+
await this.deleteRegistration(reg.id);
|
|
232
|
+
await this.deleteEvents(reg.id);
|
|
233
|
+
cleaned++;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return cleaned;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook Module Types
|
|
3
|
+
*
|
|
4
|
+
* Types for webhook server and storage components.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a pending webhook registration
|
|
9
|
+
*/
|
|
10
|
+
export interface WebhookRegistration {
|
|
11
|
+
/** Unique ID for this webhook registration */
|
|
12
|
+
id: string;
|
|
13
|
+
/** Execution ID that registered this webhook */
|
|
14
|
+
executionId: string;
|
|
15
|
+
/** Path for the webhook endpoint */
|
|
16
|
+
path: string;
|
|
17
|
+
/** When the registration was created */
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
/** When the registration expires */
|
|
20
|
+
expiresAt: Date;
|
|
21
|
+
/** Number of events expected */
|
|
22
|
+
expectedEvents: number;
|
|
23
|
+
/** Number of events received so far */
|
|
24
|
+
receivedEvents: number;
|
|
25
|
+
/** Filter expression (serialized) */
|
|
26
|
+
filter?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Represents a received webhook event
|
|
31
|
+
*/
|
|
32
|
+
export interface WebhookEvent {
|
|
33
|
+
/** Unique ID for this event */
|
|
34
|
+
id: string;
|
|
35
|
+
/** Registration ID this event belongs to */
|
|
36
|
+
registrationId: string;
|
|
37
|
+
/** Received timestamp */
|
|
38
|
+
receivedAt: Date;
|
|
39
|
+
/** HTTP method used */
|
|
40
|
+
method: string;
|
|
41
|
+
/** Request headers */
|
|
42
|
+
headers: Record<string, string>;
|
|
43
|
+
/** Request body (parsed if JSON) */
|
|
44
|
+
body: unknown;
|
|
45
|
+
/** Raw body string */
|
|
46
|
+
rawBody: string;
|
|
47
|
+
/** Query parameters */
|
|
48
|
+
query: Record<string, string>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Configuration for the webhook server
|
|
53
|
+
*/
|
|
54
|
+
export interface WebhookServerConfig {
|
|
55
|
+
/** Port to listen on (default: 3000) */
|
|
56
|
+
port?: number;
|
|
57
|
+
/** Host to bind to (default: '0.0.0.0') */
|
|
58
|
+
host?: string;
|
|
59
|
+
/** Base URL for webhook endpoints (e.g., 'https://example.com/webhooks') */
|
|
60
|
+
baseUrl?: string;
|
|
61
|
+
/** Default timeout for webhook registrations in ms (default: 300000 = 5 min) */
|
|
62
|
+
defaultTimeout?: number;
|
|
63
|
+
/** Enable verbose logging */
|
|
64
|
+
verbose?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Callbacks for webhook server events
|
|
69
|
+
*/
|
|
70
|
+
export interface WebhookServerCallbacks {
|
|
71
|
+
/** Called when a webhook is received */
|
|
72
|
+
onWebhookReceived?: (event: WebhookEvent) => void;
|
|
73
|
+
/** Called when a registration is created */
|
|
74
|
+
onRegistrationCreated?: (registration: WebhookRegistration) => void;
|
|
75
|
+
/** Called when a registration expires */
|
|
76
|
+
onRegistrationExpired?: (registration: WebhookRegistration) => void;
|
|
77
|
+
/** Called when all expected events are received */
|
|
78
|
+
onRegistrationComplete?: (registration: WebhookRegistration, events: WebhookEvent[]) => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Result of waiting for webhook events
|
|
83
|
+
*/
|
|
84
|
+
export interface WaitResult {
|
|
85
|
+
/** Whether the wait was successful */
|
|
86
|
+
success: boolean;
|
|
87
|
+
/** Events received */
|
|
88
|
+
events: WebhookEvent[];
|
|
89
|
+
/** Error message if failed */
|
|
90
|
+
error?: string;
|
|
91
|
+
/** Whether timed out */
|
|
92
|
+
timedOut?: boolean;
|
|
93
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist", "src/benchmark/**/*", "src/**/*.test.ts"]
|
|
17
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
// Test file patterns
|
|
6
|
+
include: ['src/**/*.test.ts'],
|
|
7
|
+
|
|
8
|
+
// Coverage configuration
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: 'v8',
|
|
11
|
+
reporter: ['text', 'text-summary', 'html'],
|
|
12
|
+
reportsDirectory: './coverage',
|
|
13
|
+
|
|
14
|
+
// Include all source files
|
|
15
|
+
include: ['src/**/*.ts'],
|
|
16
|
+
|
|
17
|
+
// Exclude test files and index re-exports
|
|
18
|
+
exclude: [
|
|
19
|
+
'src/**/*.test.ts',
|
|
20
|
+
'src/**/index.ts',
|
|
21
|
+
'src/cli.ts', // CLI is hard to test
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
// Thresholds (can be made stricter over time)
|
|
25
|
+
thresholds: {
|
|
26
|
+
statements: 50,
|
|
27
|
+
branches: 40,
|
|
28
|
+
functions: 50,
|
|
29
|
+
lines: 50,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// Global test timeout
|
|
34
|
+
testTimeout: 10000,
|
|
35
|
+
|
|
36
|
+
// Environment
|
|
37
|
+
environment: 'node',
|
|
38
|
+
},
|
|
39
|
+
});
|