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.
Files changed (388) hide show
  1. package/.claude/settings.local.json +31 -0
  2. package/.claude/skills/api-integration.md +125 -0
  3. package/.claude/skills/database-schema.md +51 -0
  4. package/.claude/skills/dsl-design.md +80 -0
  5. package/.claude/skills/property-testing.md +143 -0
  6. package/.claude/skills/reqon/SKILL.md +44 -0
  7. package/.claude/skills/reqon/references/examples.md +206 -0
  8. package/.claude/skills/reqon/references/syntax.md +263 -0
  9. package/.claude/skills/vscode-extension.md +113 -0
  10. package/.github/dependabot.yml +32 -0
  11. package/.github/pull_request_template.md +21 -0
  12. package/.github/workflows/ci.yml +174 -0
  13. package/.github/workflows/release.yml +73 -0
  14. package/CLAUDE.md +72 -0
  15. package/CONTRIBUTING.md +161 -0
  16. package/README.md +235 -0
  17. package/TODO.md +51 -0
  18. package/dist/ast/index.d.ts +1 -0
  19. package/dist/ast/index.js +1 -0
  20. package/dist/ast/nodes.d.ts +237 -0
  21. package/dist/ast/nodes.js +12 -0
  22. package/dist/auth/auth.test.d.ts +1 -0
  23. package/dist/auth/auth.test.js +255 -0
  24. package/dist/auth/circuit-breaker.d.ts +115 -0
  25. package/dist/auth/circuit-breaker.js +267 -0
  26. package/dist/auth/credentials.d.ts +91 -0
  27. package/dist/auth/credentials.js +169 -0
  28. package/dist/auth/index.d.ts +5 -0
  29. package/dist/auth/index.js +8 -0
  30. package/dist/auth/oauth2-provider.d.ts +41 -0
  31. package/dist/auth/oauth2-provider.js +131 -0
  32. package/dist/auth/rate-limiter.d.ts +61 -0
  33. package/dist/auth/rate-limiter.js +380 -0
  34. package/dist/auth/token-store.d.ts +30 -0
  35. package/dist/auth/token-store.js +148 -0
  36. package/dist/auth/types.d.ts +142 -0
  37. package/dist/auth/types.js +1 -0
  38. package/dist/cli.d.ts +2 -0
  39. package/dist/cli.js +270 -0
  40. package/dist/errors/errors.test.d.ts +1 -0
  41. package/dist/errors/errors.test.js +165 -0
  42. package/dist/errors/index.d.ts +83 -0
  43. package/dist/errors/index.js +159 -0
  44. package/dist/execution/execution.test.d.ts +1 -0
  45. package/dist/execution/execution.test.js +246 -0
  46. package/dist/execution/index.d.ts +4 -0
  47. package/dist/execution/index.js +2 -0
  48. package/dist/execution/state.d.ts +136 -0
  49. package/dist/execution/state.js +82 -0
  50. package/dist/execution/store.d.ts +52 -0
  51. package/dist/execution/store.js +120 -0
  52. package/dist/index.d.ts +27 -0
  53. package/dist/index.js +57 -0
  54. package/dist/integration.test.d.ts +1 -0
  55. package/dist/integration.test.js +168 -0
  56. package/dist/interpreter/context.d.ts +15 -0
  57. package/dist/interpreter/context.js +29 -0
  58. package/dist/interpreter/evaluator.d.ts +5 -0
  59. package/dist/interpreter/evaluator.js +223 -0
  60. package/dist/interpreter/evaluator.test.d.ts +1 -0
  61. package/dist/interpreter/evaluator.test.js +512 -0
  62. package/dist/interpreter/executor.d.ts +131 -0
  63. package/dist/interpreter/executor.js +663 -0
  64. package/dist/interpreter/fetch-handler.d.ts +43 -0
  65. package/dist/interpreter/fetch-handler.js +203 -0
  66. package/dist/interpreter/http.d.ts +57 -0
  67. package/dist/interpreter/http.js +210 -0
  68. package/dist/interpreter/http.test.d.ts +1 -0
  69. package/dist/interpreter/http.test.js +299 -0
  70. package/dist/interpreter/index.d.ts +7 -0
  71. package/dist/interpreter/index.js +7 -0
  72. package/dist/interpreter/pagination.d.ts +63 -0
  73. package/dist/interpreter/pagination.js +155 -0
  74. package/dist/interpreter/progress.test.d.ts +1 -0
  75. package/dist/interpreter/progress.test.js +216 -0
  76. package/dist/interpreter/schema-matcher.d.ts +16 -0
  77. package/dist/interpreter/schema-matcher.js +136 -0
  78. package/dist/interpreter/schema-matcher.test.d.ts +1 -0
  79. package/dist/interpreter/schema-matcher.test.js +122 -0
  80. package/dist/interpreter/signals.d.ts +57 -0
  81. package/dist/interpreter/signals.js +73 -0
  82. package/dist/interpreter/step-handlers/for-handler.d.ts +17 -0
  83. package/dist/interpreter/step-handlers/for-handler.js +51 -0
  84. package/dist/interpreter/step-handlers/index.d.ts +8 -0
  85. package/dist/interpreter/step-handlers/index.js +8 -0
  86. package/dist/interpreter/step-handlers/map-handler.d.ts +10 -0
  87. package/dist/interpreter/step-handlers/map-handler.js +20 -0
  88. package/dist/interpreter/step-handlers/match-handler.d.ts +27 -0
  89. package/dist/interpreter/step-handlers/match-handler.js +61 -0
  90. package/dist/interpreter/step-handlers/store-handler.d.ts +13 -0
  91. package/dist/interpreter/step-handlers/store-handler.js +66 -0
  92. package/dist/interpreter/step-handlers/types.d.ts +15 -0
  93. package/dist/interpreter/step-handlers/types.js +1 -0
  94. package/dist/interpreter/step-handlers/validate-handler.d.ts +10 -0
  95. package/dist/interpreter/step-handlers/validate-handler.js +26 -0
  96. package/dist/interpreter/step-handlers/webhook-handler.d.ts +36 -0
  97. package/dist/interpreter/step-handlers/webhook-handler.js +104 -0
  98. package/dist/lexer/index.d.ts +10 -0
  99. package/dist/lexer/index.js +12 -0
  100. package/dist/lexer/lexer.d.ts +24 -0
  101. package/dist/lexer/lexer.js +264 -0
  102. package/dist/lexer/lexer.test.d.ts +1 -0
  103. package/dist/lexer/lexer.test.js +259 -0
  104. package/dist/lexer/tokens.d.ts +69 -0
  105. package/dist/lexer/tokens.js +146 -0
  106. package/dist/loader/index.d.ts +36 -0
  107. package/dist/loader/index.js +220 -0
  108. package/dist/loader/loader.test.d.ts +1 -0
  109. package/dist/loader/loader.test.js +287 -0
  110. package/dist/oas/index.d.ts +4 -0
  111. package/dist/oas/index.js +2 -0
  112. package/dist/oas/loader.d.ts +21 -0
  113. package/dist/oas/loader.js +82 -0
  114. package/dist/oas/oas.test.d.ts +1 -0
  115. package/dist/oas/oas.test.js +218 -0
  116. package/dist/oas/validator.d.ts +12 -0
  117. package/dist/oas/validator.js +227 -0
  118. package/dist/parser/base.d.ts +33 -0
  119. package/dist/parser/base.js +97 -0
  120. package/dist/parser/expressions.d.ts +27 -0
  121. package/dist/parser/expressions.js +248 -0
  122. package/dist/parser/expressions.test.d.ts +1 -0
  123. package/dist/parser/expressions.test.js +378 -0
  124. package/dist/parser/index.d.ts +3 -0
  125. package/dist/parser/index.js +3 -0
  126. package/dist/parser/match.test.d.ts +1 -0
  127. package/dist/parser/match.test.js +254 -0
  128. package/dist/parser/parser.d.ts +68 -0
  129. package/dist/parser/parser.js +1229 -0
  130. package/dist/parser/parser.test.d.ts +1 -0
  131. package/dist/parser/parser.test.js +333 -0
  132. package/dist/parser/schedule.test.d.ts +1 -0
  133. package/dist/parser/schedule.test.js +241 -0
  134. package/dist/plugin.d.ts +35 -0
  135. package/dist/plugin.js +68 -0
  136. package/dist/scheduler/cron-parser.d.ts +32 -0
  137. package/dist/scheduler/cron-parser.js +198 -0
  138. package/dist/scheduler/cron-parser.test.d.ts +1 -0
  139. package/dist/scheduler/cron-parser.test.js +188 -0
  140. package/dist/scheduler/index.d.ts +3 -0
  141. package/dist/scheduler/index.js +2 -0
  142. package/dist/scheduler/scheduler.d.ts +81 -0
  143. package/dist/scheduler/scheduler.js +376 -0
  144. package/dist/scheduler/types.d.ts +65 -0
  145. package/dist/scheduler/types.js +1 -0
  146. package/dist/stores/factory.d.ts +36 -0
  147. package/dist/stores/factory.js +73 -0
  148. package/dist/stores/file.d.ts +60 -0
  149. package/dist/stores/file.js +173 -0
  150. package/dist/stores/file.test.d.ts +1 -0
  151. package/dist/stores/file.test.js +165 -0
  152. package/dist/stores/index.d.ts +6 -0
  153. package/dist/stores/index.js +5 -0
  154. package/dist/stores/memory.d.ts +19 -0
  155. package/dist/stores/memory.js +51 -0
  156. package/dist/stores/memory.test.d.ts +1 -0
  157. package/dist/stores/memory.test.js +157 -0
  158. package/dist/stores/postgrest.d.ts +55 -0
  159. package/dist/stores/postgrest.js +217 -0
  160. package/dist/stores/stores.test.d.ts +1 -0
  161. package/dist/stores/stores.test.js +158 -0
  162. package/dist/stores/types.d.ts +31 -0
  163. package/dist/stores/types.js +26 -0
  164. package/dist/sync/index.d.ts +4 -0
  165. package/dist/sync/index.js +2 -0
  166. package/dist/sync/state.d.ts +69 -0
  167. package/dist/sync/state.js +66 -0
  168. package/dist/sync/store.d.ts +49 -0
  169. package/dist/sync/store.js +93 -0
  170. package/dist/sync/sync.test.d.ts +1 -0
  171. package/dist/sync/sync.test.js +221 -0
  172. package/dist/utils/async.d.ts +7 -0
  173. package/dist/utils/async.js +9 -0
  174. package/dist/utils/file.d.ts +38 -0
  175. package/dist/utils/file.js +92 -0
  176. package/dist/utils/index.d.ts +4 -0
  177. package/dist/utils/index.js +4 -0
  178. package/dist/utils/logger.d.ts +34 -0
  179. package/dist/utils/logger.js +39 -0
  180. package/dist/utils/path.d.ts +12 -0
  181. package/dist/utils/path.js +41 -0
  182. package/dist/webhook/index.d.ts +8 -0
  183. package/dist/webhook/index.js +7 -0
  184. package/dist/webhook/server.d.ts +84 -0
  185. package/dist/webhook/server.js +319 -0
  186. package/dist/webhook/store.d.ts +67 -0
  187. package/dist/webhook/store.js +193 -0
  188. package/dist/webhook/types.d.ts +88 -0
  189. package/dist/webhook/types.js +6 -0
  190. package/docusaurus/README.md +41 -0
  191. package/docusaurus/docs/advanced/execution-state.md +283 -0
  192. package/docusaurus/docs/advanced/extending-reqon.md +388 -0
  193. package/docusaurus/docs/advanced/multi-file-missions.md +250 -0
  194. package/docusaurus/docs/advanced/parallel-execution.md +353 -0
  195. package/docusaurus/docs/api-reference.md +443 -0
  196. package/docusaurus/docs/authentication/api-key.md +339 -0
  197. package/docusaurus/docs/authentication/basic.md +276 -0
  198. package/docusaurus/docs/authentication/bearer.md +282 -0
  199. package/docusaurus/docs/authentication/oauth2.md +317 -0
  200. package/docusaurus/docs/authentication/overview.md +251 -0
  201. package/docusaurus/docs/cli.md +229 -0
  202. package/docusaurus/docs/core-concepts/actions.md +286 -0
  203. package/docusaurus/docs/core-concepts/missions.md +264 -0
  204. package/docusaurus/docs/core-concepts/schemas.md +353 -0
  205. package/docusaurus/docs/core-concepts/sources.md +339 -0
  206. package/docusaurus/docs/core-concepts/stores.md +332 -0
  207. package/docusaurus/docs/dsl-syntax/expressions.md +361 -0
  208. package/docusaurus/docs/dsl-syntax/fetch.md +293 -0
  209. package/docusaurus/docs/dsl-syntax/for-loops.md +324 -0
  210. package/docusaurus/docs/dsl-syntax/map.md +345 -0
  211. package/docusaurus/docs/dsl-syntax/match.md +387 -0
  212. package/docusaurus/docs/dsl-syntax/pipelines.md +397 -0
  213. package/docusaurus/docs/dsl-syntax/validate.md +401 -0
  214. package/docusaurus/docs/error-handling/dead-letter-queues.md +399 -0
  215. package/docusaurus/docs/error-handling/flow-control.md +337 -0
  216. package/docusaurus/docs/error-handling/retry-strategies.md +368 -0
  217. package/docusaurus/docs/examples.md +488 -0
  218. package/docusaurus/docs/getting-started.md +256 -0
  219. package/docusaurus/docs/http/circuit-breaker.md +401 -0
  220. package/docusaurus/docs/http/incremental-sync.md +394 -0
  221. package/docusaurus/docs/http/pagination.md +361 -0
  222. package/docusaurus/docs/http/rate-limiting.md +383 -0
  223. package/docusaurus/docs/http/requests.md +328 -0
  224. package/docusaurus/docs/http/retry.md +402 -0
  225. package/docusaurus/docs/intro.md +90 -0
  226. package/docusaurus/docs/openapi/loading-specs.md +305 -0
  227. package/docusaurus/docs/openapi/operation-calls.md +314 -0
  228. package/docusaurus/docs/openapi/overview.md +212 -0
  229. package/docusaurus/docs/openapi/response-validation.md +344 -0
  230. package/docusaurus/docs/scheduling/cron.md +305 -0
  231. package/docusaurus/docs/scheduling/daemon-mode.md +317 -0
  232. package/docusaurus/docs/scheduling/intervals.md +289 -0
  233. package/docusaurus/docs/scheduling/overview.md +231 -0
  234. package/docusaurus/docs/stores/custom-adapters.md +376 -0
  235. package/docusaurus/docs/stores/file.md +236 -0
  236. package/docusaurus/docs/stores/memory.md +193 -0
  237. package/docusaurus/docs/stores/overview.md +274 -0
  238. package/docusaurus/docs/stores/postgrest.md +316 -0
  239. package/docusaurus/docusaurus.config.ts +148 -0
  240. package/docusaurus/package-lock.json +18029 -0
  241. package/docusaurus/package.json +47 -0
  242. package/docusaurus/sidebars.ts +155 -0
  243. package/docusaurus/src/components/HomepageFeatures/index.tsx +105 -0
  244. package/docusaurus/src/components/HomepageFeatures/styles.module.css +12 -0
  245. package/docusaurus/src/css/custom.css +169 -0
  246. package/docusaurus/src/pages/index.module.css +48 -0
  247. package/docusaurus/src/pages/index.tsx +110 -0
  248. package/docusaurus/src/pages/markdown-page.md +7 -0
  249. package/docusaurus/static/.nojekyll +0 -0
  250. package/docusaurus/static/img/docusaurus-social-card.jpg +0 -0
  251. package/docusaurus/static/img/docusaurus.png +0 -0
  252. package/docusaurus/static/img/favicon.ico +0 -0
  253. package/docusaurus/static/img/logo.svg +10 -0
  254. package/docusaurus/static/img/undraw_docusaurus_mountain.svg +171 -0
  255. package/docusaurus/static/img/undraw_docusaurus_react.svg +170 -0
  256. package/docusaurus/static/img/undraw_docusaurus_tree.svg +40 -0
  257. package/docusaurus/tsconfig.json +8 -0
  258. package/examples/README.md +112 -0
  259. package/examples/error-handling/README.md +150 -0
  260. package/examples/error-handling/payment-processor.vague +287 -0
  261. package/examples/github-sync/README.md +74 -0
  262. package/examples/github-sync/fetch-issues.vague +47 -0
  263. package/examples/github-sync/fetch-prs.vague +40 -0
  264. package/examples/github-sync/mission.vague +101 -0
  265. package/examples/github-sync/normalize.vague +70 -0
  266. package/examples/jsonplaceholder/README.md +28 -0
  267. package/examples/jsonplaceholder/posts.vague +48 -0
  268. package/examples/petstore/README.md +35 -0
  269. package/examples/petstore/openapi.yaml +97 -0
  270. package/examples/petstore/sync.vague +52 -0
  271. package/examples/temporal-comparison/README.md +297 -0
  272. package/examples/temporal-comparison/reconciliation.vague +355 -0
  273. package/examples/temporal-comparison/temporal/activities/index.ts +8 -0
  274. package/examples/temporal-comparison/temporal/activities/shipstation.ts +225 -0
  275. package/examples/temporal-comparison/temporal/activities/shopify.ts +257 -0
  276. package/examples/temporal-comparison/temporal/activities/storage.ts +198 -0
  277. package/examples/temporal-comparison/temporal/activities/stripe.ts +169 -0
  278. package/examples/temporal-comparison/temporal/activities/validation.ts +205 -0
  279. package/examples/temporal-comparison/temporal/client/schedule.ts +218 -0
  280. package/examples/temporal-comparison/temporal/config/retry.ts +63 -0
  281. package/examples/temporal-comparison/temporal/types/index.ts +129 -0
  282. package/examples/temporal-comparison/temporal/workers/main.ts +130 -0
  283. package/examples/temporal-comparison/temporal/workflows/orderReconciliation.ts +262 -0
  284. package/examples/xero/README.md +88 -0
  285. package/examples/xero/invoices.vague +189 -0
  286. package/package.json +40 -0
  287. package/src/api-integration.test.ts +954 -0
  288. package/src/ast/index.ts +1 -0
  289. package/src/ast/nodes.ts +310 -0
  290. package/src/auth/auth.test.ts +326 -0
  291. package/src/auth/circuit-breaker.test.ts +390 -0
  292. package/src/auth/circuit-breaker.ts +379 -0
  293. package/src/auth/credentials.test.ts +273 -0
  294. package/src/auth/credentials.ts +246 -0
  295. package/src/auth/index.ts +40 -0
  296. package/src/auth/oauth2-provider.ts +177 -0
  297. package/src/auth/rate-limiter.ts +459 -0
  298. package/src/auth/token-store.ts +177 -0
  299. package/src/auth/types.ts +159 -0
  300. package/src/benchmark/e2e.bench.ts +288 -0
  301. package/src/benchmark/evaluator.bench.ts +331 -0
  302. package/src/benchmark/fixtures.ts +295 -0
  303. package/src/benchmark/index.ts +108 -0
  304. package/src/benchmark/lexer.bench.ts +69 -0
  305. package/src/benchmark/parser.bench.ts +103 -0
  306. package/src/benchmark/resilience.bench.ts +193 -0
  307. package/src/benchmark/store.bench.ts +147 -0
  308. package/src/benchmark/utils.ts +230 -0
  309. package/src/cli.ts +313 -0
  310. package/src/errors/errors.test.ts +234 -0
  311. package/src/errors/index.ts +223 -0
  312. package/src/execution/execution.test.ts +307 -0
  313. package/src/execution/index.ts +21 -0
  314. package/src/execution/state.ts +207 -0
  315. package/src/execution/store.ts +188 -0
  316. package/src/index.ts +169 -0
  317. package/src/integration.test.ts +192 -0
  318. package/src/interpreter/context.ts +57 -0
  319. package/src/interpreter/evaluator.test.ts +796 -0
  320. package/src/interpreter/evaluator.ts +245 -0
  321. package/src/interpreter/executor.ts +946 -0
  322. package/src/interpreter/fetch-handler.ts +302 -0
  323. package/src/interpreter/http.test.ts +423 -0
  324. package/src/interpreter/http.ts +308 -0
  325. package/src/interpreter/index.ts +32 -0
  326. package/src/interpreter/pagination.ts +207 -0
  327. package/src/interpreter/progress.test.ts +276 -0
  328. package/src/interpreter/schema-matcher.test.ts +160 -0
  329. package/src/interpreter/schema-matcher.ts +168 -0
  330. package/src/interpreter/signals.ts +73 -0
  331. package/src/interpreter/step-handlers/for-handler.ts +65 -0
  332. package/src/interpreter/step-handlers/index.ts +17 -0
  333. package/src/interpreter/step-handlers/map-handler.ts +24 -0
  334. package/src/interpreter/step-handlers/match-handler.ts +101 -0
  335. package/src/interpreter/step-handlers/store-handler.ts +78 -0
  336. package/src/interpreter/step-handlers/types.ts +17 -0
  337. package/src/interpreter/step-handlers/validate-handler.ts +30 -0
  338. package/src/interpreter/step-handlers/webhook-handler.ts +142 -0
  339. package/src/lexer/index.ts +18 -0
  340. package/src/lexer/lexer.test.ts +316 -0
  341. package/src/lexer/tokens.ts +179 -0
  342. package/src/loader/index.ts +288 -0
  343. package/src/loader/loader.test.ts +360 -0
  344. package/src/oas/index.ts +4 -0
  345. package/src/oas/loader.ts +126 -0
  346. package/src/oas/oas.test.ts +254 -0
  347. package/src/oas/validator.ts +299 -0
  348. package/src/parser/base.ts +124 -0
  349. package/src/parser/expressions.test.ts +525 -0
  350. package/src/parser/expressions.ts +314 -0
  351. package/src/parser/index.ts +3 -0
  352. package/src/parser/match.test.ts +296 -0
  353. package/src/parser/parser.test.ts +739 -0
  354. package/src/parser/parser.ts +1469 -0
  355. package/src/parser/schedule.test.ts +287 -0
  356. package/src/parser/webhook.test.ts +248 -0
  357. package/src/plugin.ts +83 -0
  358. package/src/scheduler/cron-parser.test.ts +236 -0
  359. package/src/scheduler/cron-parser.ts +236 -0
  360. package/src/scheduler/index.ts +10 -0
  361. package/src/scheduler/scheduler.ts +443 -0
  362. package/src/scheduler/types.ts +71 -0
  363. package/src/stores/factory.ts +104 -0
  364. package/src/stores/file.test.ts +276 -0
  365. package/src/stores/file.ts +211 -0
  366. package/src/stores/index.ts +6 -0
  367. package/src/stores/memory.test.ts +238 -0
  368. package/src/stores/memory.ts +63 -0
  369. package/src/stores/postgrest.test.ts +488 -0
  370. package/src/stores/postgrest.ts +263 -0
  371. package/src/stores/stores.test.ts +197 -0
  372. package/src/stores/types.ts +58 -0
  373. package/src/sync/index.ts +16 -0
  374. package/src/sync/state.ts +126 -0
  375. package/src/sync/store.ts +139 -0
  376. package/src/sync/sync.test.ts +271 -0
  377. package/src/utils/async.ts +10 -0
  378. package/src/utils/file.ts +106 -0
  379. package/src/utils/index.ts +14 -0
  380. package/src/utils/logger.ts +53 -0
  381. package/src/utils/path.ts +47 -0
  382. package/src/webhook/index.ts +15 -0
  383. package/src/webhook/server.test.ts +253 -0
  384. package/src/webhook/server.ts +389 -0
  385. package/src/webhook/store.ts +239 -0
  386. package/src/webhook/types.ts +93 -0
  387. package/tsconfig.json +17 -0
  388. 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
+ }
@@ -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
+ });