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.
Files changed (396) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +22 -0
  3. package/dist/ast/nodes.d.ts +83 -4
  4. package/dist/ast/nodes.js +14 -0
  5. package/dist/auth/circuit-breaker.js +7 -6
  6. package/dist/auth/rate-limiter.d.ts +4 -0
  7. package/dist/auth/rate-limiter.js +9 -16
  8. package/dist/cli.d.ts +13 -0
  9. package/dist/cli.js +84 -4
  10. package/dist/config/constants.d.ts +141 -0
  11. package/dist/config/constants.js +128 -0
  12. package/dist/config/index.d.ts +4 -0
  13. package/dist/config/index.js +4 -0
  14. package/dist/control/index.d.ts +2 -0
  15. package/dist/control/index.js +1 -0
  16. package/dist/control/server.d.ts +88 -0
  17. package/dist/control/server.js +238 -0
  18. package/dist/control/types.d.ts +55 -0
  19. package/dist/control/types.js +7 -0
  20. package/dist/debug/cli-debugger.d.ts +17 -0
  21. package/dist/debug/cli-debugger.js +180 -0
  22. package/dist/debug/controller.d.ts +94 -0
  23. package/dist/debug/controller.js +45 -0
  24. package/dist/debug/index.d.ts +6 -0
  25. package/dist/debug/index.js +5 -0
  26. package/dist/errors/index.d.ts +67 -0
  27. package/dist/errors/index.js +89 -1
  28. package/dist/execution/index.d.ts +1 -1
  29. package/dist/execution/state.d.ts +24 -0
  30. package/dist/index.d.ts +21 -1
  31. package/dist/index.js +33 -2
  32. package/dist/interpreter/context.d.ts +14 -0
  33. package/dist/interpreter/context.js +15 -0
  34. package/dist/interpreter/evaluator.d.ts +63 -1
  35. package/dist/interpreter/evaluator.js +186 -39
  36. package/dist/interpreter/executor.d.ts +70 -14
  37. package/dist/interpreter/executor.js +503 -174
  38. package/dist/interpreter/fetch-handler.d.ts +9 -0
  39. package/dist/interpreter/fetch-handler.js +133 -24
  40. package/dist/interpreter/http.d.ts +5 -0
  41. package/dist/interpreter/http.js +26 -12
  42. package/dist/interpreter/index.d.ts +3 -1
  43. package/dist/interpreter/index.js +2 -0
  44. package/dist/interpreter/pagination.d.ts +11 -2
  45. package/dist/interpreter/pagination.js +95 -31
  46. package/dist/interpreter/signals.d.ts +8 -0
  47. package/dist/interpreter/signals.js +12 -0
  48. package/dist/interpreter/source-manager.d.ts +75 -0
  49. package/dist/interpreter/source-manager.js +157 -0
  50. package/dist/interpreter/step-handlers/apply-handler.d.ts +29 -0
  51. package/dist/interpreter/step-handlers/apply-handler.js +79 -0
  52. package/dist/interpreter/step-handlers/for-handler.d.ts +13 -0
  53. package/dist/interpreter/step-handlers/for-handler.js +71 -4
  54. package/dist/interpreter/step-handlers/index.d.ts +4 -2
  55. package/dist/interpreter/step-handlers/index.js +4 -2
  56. package/dist/interpreter/step-handlers/match-handler.d.ts +9 -0
  57. package/dist/interpreter/step-handlers/match-handler.js +43 -16
  58. package/dist/interpreter/step-handlers/pause-handler.d.ts +52 -0
  59. package/dist/interpreter/step-handlers/pause-handler.js +87 -0
  60. package/dist/interpreter/step-handlers/store-handler.d.ts +11 -1
  61. package/dist/interpreter/step-handlers/store-handler.js +45 -13
  62. package/dist/interpreter/step-handlers/types.d.ts +3 -0
  63. package/dist/interpreter/step-handlers/validate-handler.d.ts +2 -1
  64. package/dist/interpreter/step-handlers/validate-handler.js +4 -2
  65. package/dist/interpreter/step-handlers/webhook-handler.d.ts +3 -0
  66. package/dist/interpreter/step-handlers/webhook-handler.js +18 -2
  67. package/dist/interpreter/store-manager.d.ts +46 -0
  68. package/dist/interpreter/store-manager.js +66 -0
  69. package/dist/lexer/index.d.ts +11 -4
  70. package/dist/lexer/index.js +11 -4
  71. package/dist/lexer/tokens.d.ts +17 -1
  72. package/dist/lexer/tokens.js +36 -0
  73. package/dist/mcp/index.d.ts +11 -0
  74. package/dist/mcp/index.js +11 -0
  75. package/dist/mcp/server.d.ts +17 -0
  76. package/dist/mcp/server.js +451 -0
  77. package/dist/oas/index.d.ts +2 -0
  78. package/dist/oas/index.js +1 -0
  79. package/dist/oas/mock-generator.d.ts +12 -0
  80. package/dist/oas/mock-generator.js +187 -0
  81. package/dist/observability/events.d.ts +244 -0
  82. package/dist/observability/events.js +90 -0
  83. package/dist/observability/index.d.ts +15 -0
  84. package/dist/observability/index.js +12 -0
  85. package/dist/observability/logger.d.ts +106 -0
  86. package/dist/observability/logger.js +259 -0
  87. package/dist/observability/otel.d.ts +135 -0
  88. package/dist/observability/otel.js +386 -0
  89. package/dist/parser/action-parser.d.ts +105 -0
  90. package/dist/parser/action-parser.js +645 -0
  91. package/dist/parser/expressions.d.ts +13 -0
  92. package/dist/parser/expressions.js +72 -2
  93. package/dist/parser/fetch-parser.d.ts +27 -0
  94. package/dist/parser/fetch-parser.js +269 -0
  95. package/dist/parser/index.d.ts +17 -0
  96. package/dist/parser/index.js +17 -0
  97. package/dist/parser/parser.d.ts +44 -46
  98. package/dist/parser/parser.js +122 -1070
  99. package/dist/parser/pipeline-parser.d.ts +12 -0
  100. package/dist/parser/pipeline-parser.js +52 -0
  101. package/dist/parser/schedule-parser.d.ts +7 -0
  102. package/dist/parser/schedule-parser.js +137 -0
  103. package/dist/parser/source-parser.d.ts +9 -0
  104. package/dist/parser/source-parser.js +151 -0
  105. package/dist/pause/index.d.ts +14 -0
  106. package/dist/pause/index.js +11 -0
  107. package/dist/pause/manager.d.ts +118 -0
  108. package/dist/pause/manager.js +245 -0
  109. package/dist/pause/state.d.ts +93 -0
  110. package/dist/pause/state.js +103 -0
  111. package/dist/pause/store.d.ts +61 -0
  112. package/dist/pause/store.js +156 -0
  113. package/dist/plugin.d.ts +9 -12
  114. package/dist/plugin.js +10 -13
  115. package/dist/stores/factory.d.ts +1 -1
  116. package/dist/stores/factory.js +3 -2
  117. package/dist/stores/file.d.ts +26 -0
  118. package/dist/stores/file.js +64 -10
  119. package/dist/stores/index.d.ts +16 -1
  120. package/dist/stores/index.js +16 -1
  121. package/dist/stores/memory.d.ts +4 -0
  122. package/dist/stores/memory.js +11 -0
  123. package/dist/stores/types.d.ts +17 -0
  124. package/dist/stores/types.js +12 -0
  125. package/dist/trace/index.d.ts +16 -0
  126. package/dist/trace/index.js +12 -0
  127. package/dist/trace/recorder.d.ts +71 -0
  128. package/dist/trace/recorder.js +144 -0
  129. package/dist/trace/replay.d.ts +132 -0
  130. package/dist/trace/replay.js +264 -0
  131. package/dist/trace/state.d.ts +102 -0
  132. package/dist/trace/state.js +86 -0
  133. package/dist/trace/store.d.ts +69 -0
  134. package/dist/trace/store.js +225 -0
  135. package/dist/utils/index.d.ts +1 -0
  136. package/dist/utils/index.js +1 -0
  137. package/dist/utils/type-guards.d.ts +58 -0
  138. package/dist/utils/type-guards.js +92 -0
  139. package/dist/webhook/server.js +7 -6
  140. package/package.json +55 -6
  141. package/.claude/settings.local.json +0 -31
  142. package/.claude/skills/api-integration.md +0 -125
  143. package/.claude/skills/database-schema.md +0 -51
  144. package/.claude/skills/dsl-design.md +0 -80
  145. package/.claude/skills/property-testing.md +0 -143
  146. package/.claude/skills/reqon/SKILL.md +0 -44
  147. package/.claude/skills/reqon/references/examples.md +0 -206
  148. package/.claude/skills/reqon/references/syntax.md +0 -263
  149. package/.claude/skills/vscode-extension.md +0 -113
  150. package/.github/dependabot.yml +0 -32
  151. package/.github/pull_request_template.md +0 -21
  152. package/.github/workflows/ci.yml +0 -174
  153. package/.github/workflows/release.yml +0 -73
  154. package/CLAUDE.md +0 -72
  155. package/CONTRIBUTING.md +0 -161
  156. package/TODO.md +0 -51
  157. package/dist/auth/auth.test.d.ts +0 -1
  158. package/dist/auth/auth.test.js +0 -255
  159. package/dist/errors/errors.test.d.ts +0 -1
  160. package/dist/errors/errors.test.js +0 -165
  161. package/dist/execution/execution.test.d.ts +0 -1
  162. package/dist/execution/execution.test.js +0 -246
  163. package/dist/integration.test.d.ts +0 -1
  164. package/dist/integration.test.js +0 -168
  165. package/dist/interpreter/evaluator.test.d.ts +0 -1
  166. package/dist/interpreter/evaluator.test.js +0 -512
  167. package/dist/interpreter/http.test.d.ts +0 -1
  168. package/dist/interpreter/http.test.js +0 -299
  169. package/dist/interpreter/progress.test.d.ts +0 -1
  170. package/dist/interpreter/progress.test.js +0 -216
  171. package/dist/interpreter/schema-matcher.test.d.ts +0 -1
  172. package/dist/interpreter/schema-matcher.test.js +0 -122
  173. package/dist/lexer/lexer.d.ts +0 -24
  174. package/dist/lexer/lexer.js +0 -264
  175. package/dist/lexer/lexer.test.d.ts +0 -1
  176. package/dist/lexer/lexer.test.js +0 -259
  177. package/dist/loader/loader.test.d.ts +0 -1
  178. package/dist/loader/loader.test.js +0 -287
  179. package/dist/oas/oas.test.d.ts +0 -1
  180. package/dist/oas/oas.test.js +0 -218
  181. package/dist/parser/expressions.test.d.ts +0 -1
  182. package/dist/parser/expressions.test.js +0 -378
  183. package/dist/parser/match.test.d.ts +0 -1
  184. package/dist/parser/match.test.js +0 -254
  185. package/dist/parser/parser.test.d.ts +0 -1
  186. package/dist/parser/parser.test.js +0 -333
  187. package/dist/parser/schedule.test.d.ts +0 -1
  188. package/dist/parser/schedule.test.js +0 -241
  189. package/dist/scheduler/cron-parser.test.d.ts +0 -1
  190. package/dist/scheduler/cron-parser.test.js +0 -188
  191. package/dist/stores/file.test.d.ts +0 -1
  192. package/dist/stores/file.test.js +0 -165
  193. package/dist/stores/memory.test.d.ts +0 -1
  194. package/dist/stores/memory.test.js +0 -157
  195. package/dist/stores/stores.test.d.ts +0 -1
  196. package/dist/stores/stores.test.js +0 -158
  197. package/dist/sync/sync.test.d.ts +0 -1
  198. package/dist/sync/sync.test.js +0 -221
  199. package/docusaurus/README.md +0 -41
  200. package/docusaurus/docs/advanced/execution-state.md +0 -283
  201. package/docusaurus/docs/advanced/extending-reqon.md +0 -388
  202. package/docusaurus/docs/advanced/multi-file-missions.md +0 -250
  203. package/docusaurus/docs/advanced/parallel-execution.md +0 -353
  204. package/docusaurus/docs/api-reference.md +0 -443
  205. package/docusaurus/docs/authentication/api-key.md +0 -339
  206. package/docusaurus/docs/authentication/basic.md +0 -276
  207. package/docusaurus/docs/authentication/bearer.md +0 -282
  208. package/docusaurus/docs/authentication/oauth2.md +0 -317
  209. package/docusaurus/docs/authentication/overview.md +0 -251
  210. package/docusaurus/docs/cli.md +0 -229
  211. package/docusaurus/docs/core-concepts/actions.md +0 -286
  212. package/docusaurus/docs/core-concepts/missions.md +0 -264
  213. package/docusaurus/docs/core-concepts/schemas.md +0 -353
  214. package/docusaurus/docs/core-concepts/sources.md +0 -339
  215. package/docusaurus/docs/core-concepts/stores.md +0 -332
  216. package/docusaurus/docs/dsl-syntax/expressions.md +0 -361
  217. package/docusaurus/docs/dsl-syntax/fetch.md +0 -293
  218. package/docusaurus/docs/dsl-syntax/for-loops.md +0 -324
  219. package/docusaurus/docs/dsl-syntax/map.md +0 -345
  220. package/docusaurus/docs/dsl-syntax/match.md +0 -387
  221. package/docusaurus/docs/dsl-syntax/pipelines.md +0 -397
  222. package/docusaurus/docs/dsl-syntax/validate.md +0 -401
  223. package/docusaurus/docs/error-handling/dead-letter-queues.md +0 -399
  224. package/docusaurus/docs/error-handling/flow-control.md +0 -337
  225. package/docusaurus/docs/error-handling/retry-strategies.md +0 -368
  226. package/docusaurus/docs/examples.md +0 -488
  227. package/docusaurus/docs/getting-started.md +0 -256
  228. package/docusaurus/docs/http/circuit-breaker.md +0 -401
  229. package/docusaurus/docs/http/incremental-sync.md +0 -394
  230. package/docusaurus/docs/http/pagination.md +0 -361
  231. package/docusaurus/docs/http/rate-limiting.md +0 -383
  232. package/docusaurus/docs/http/requests.md +0 -328
  233. package/docusaurus/docs/http/retry.md +0 -402
  234. package/docusaurus/docs/intro.md +0 -90
  235. package/docusaurus/docs/openapi/loading-specs.md +0 -305
  236. package/docusaurus/docs/openapi/operation-calls.md +0 -314
  237. package/docusaurus/docs/openapi/overview.md +0 -212
  238. package/docusaurus/docs/openapi/response-validation.md +0 -344
  239. package/docusaurus/docs/scheduling/cron.md +0 -305
  240. package/docusaurus/docs/scheduling/daemon-mode.md +0 -317
  241. package/docusaurus/docs/scheduling/intervals.md +0 -289
  242. package/docusaurus/docs/scheduling/overview.md +0 -231
  243. package/docusaurus/docs/stores/custom-adapters.md +0 -376
  244. package/docusaurus/docs/stores/file.md +0 -236
  245. package/docusaurus/docs/stores/memory.md +0 -193
  246. package/docusaurus/docs/stores/overview.md +0 -274
  247. package/docusaurus/docs/stores/postgrest.md +0 -316
  248. package/docusaurus/docusaurus.config.ts +0 -148
  249. package/docusaurus/package-lock.json +0 -18029
  250. package/docusaurus/package.json +0 -47
  251. package/docusaurus/sidebars.ts +0 -155
  252. package/docusaurus/src/components/HomepageFeatures/index.tsx +0 -105
  253. package/docusaurus/src/components/HomepageFeatures/styles.module.css +0 -12
  254. package/docusaurus/src/css/custom.css +0 -169
  255. package/docusaurus/src/pages/index.module.css +0 -48
  256. package/docusaurus/src/pages/index.tsx +0 -110
  257. package/docusaurus/src/pages/markdown-page.md +0 -7
  258. package/docusaurus/static/.nojekyll +0 -0
  259. package/docusaurus/static/img/docusaurus-social-card.jpg +0 -0
  260. package/docusaurus/static/img/docusaurus.png +0 -0
  261. package/docusaurus/static/img/favicon.ico +0 -0
  262. package/docusaurus/static/img/logo.svg +0 -10
  263. package/docusaurus/static/img/undraw_docusaurus_mountain.svg +0 -171
  264. package/docusaurus/static/img/undraw_docusaurus_react.svg +0 -170
  265. package/docusaurus/static/img/undraw_docusaurus_tree.svg +0 -40
  266. package/docusaurus/tsconfig.json +0 -8
  267. package/examples/README.md +0 -112
  268. package/examples/error-handling/README.md +0 -150
  269. package/examples/error-handling/payment-processor.vague +0 -287
  270. package/examples/github-sync/README.md +0 -74
  271. package/examples/github-sync/fetch-issues.vague +0 -47
  272. package/examples/github-sync/fetch-prs.vague +0 -40
  273. package/examples/github-sync/mission.vague +0 -101
  274. package/examples/github-sync/normalize.vague +0 -70
  275. package/examples/jsonplaceholder/README.md +0 -28
  276. package/examples/jsonplaceholder/posts.vague +0 -48
  277. package/examples/petstore/README.md +0 -35
  278. package/examples/petstore/openapi.yaml +0 -97
  279. package/examples/petstore/sync.vague +0 -52
  280. package/examples/temporal-comparison/README.md +0 -297
  281. package/examples/temporal-comparison/reconciliation.vague +0 -355
  282. package/examples/temporal-comparison/temporal/activities/index.ts +0 -8
  283. package/examples/temporal-comparison/temporal/activities/shipstation.ts +0 -225
  284. package/examples/temporal-comparison/temporal/activities/shopify.ts +0 -257
  285. package/examples/temporal-comparison/temporal/activities/storage.ts +0 -198
  286. package/examples/temporal-comparison/temporal/activities/stripe.ts +0 -169
  287. package/examples/temporal-comparison/temporal/activities/validation.ts +0 -205
  288. package/examples/temporal-comparison/temporal/client/schedule.ts +0 -218
  289. package/examples/temporal-comparison/temporal/config/retry.ts +0 -63
  290. package/examples/temporal-comparison/temporal/types/index.ts +0 -129
  291. package/examples/temporal-comparison/temporal/workers/main.ts +0 -130
  292. package/examples/temporal-comparison/temporal/workflows/orderReconciliation.ts +0 -262
  293. package/examples/xero/README.md +0 -88
  294. package/examples/xero/invoices.vague +0 -189
  295. package/src/api-integration.test.ts +0 -954
  296. package/src/ast/index.ts +0 -1
  297. package/src/ast/nodes.ts +0 -310
  298. package/src/auth/auth.test.ts +0 -326
  299. package/src/auth/circuit-breaker.test.ts +0 -390
  300. package/src/auth/circuit-breaker.ts +0 -379
  301. package/src/auth/credentials.test.ts +0 -273
  302. package/src/auth/credentials.ts +0 -246
  303. package/src/auth/index.ts +0 -40
  304. package/src/auth/oauth2-provider.ts +0 -177
  305. package/src/auth/rate-limiter.ts +0 -459
  306. package/src/auth/token-store.ts +0 -177
  307. package/src/auth/types.ts +0 -159
  308. package/src/benchmark/e2e.bench.ts +0 -288
  309. package/src/benchmark/evaluator.bench.ts +0 -331
  310. package/src/benchmark/fixtures.ts +0 -295
  311. package/src/benchmark/index.ts +0 -108
  312. package/src/benchmark/lexer.bench.ts +0 -69
  313. package/src/benchmark/parser.bench.ts +0 -103
  314. package/src/benchmark/resilience.bench.ts +0 -193
  315. package/src/benchmark/store.bench.ts +0 -147
  316. package/src/benchmark/utils.ts +0 -230
  317. package/src/cli.ts +0 -313
  318. package/src/errors/errors.test.ts +0 -234
  319. package/src/errors/index.ts +0 -223
  320. package/src/execution/execution.test.ts +0 -307
  321. package/src/execution/index.ts +0 -21
  322. package/src/execution/state.ts +0 -207
  323. package/src/execution/store.ts +0 -188
  324. package/src/index.ts +0 -169
  325. package/src/integration.test.ts +0 -192
  326. package/src/interpreter/context.ts +0 -57
  327. package/src/interpreter/evaluator.test.ts +0 -796
  328. package/src/interpreter/evaluator.ts +0 -245
  329. package/src/interpreter/executor.ts +0 -946
  330. package/src/interpreter/fetch-handler.ts +0 -302
  331. package/src/interpreter/http.test.ts +0 -423
  332. package/src/interpreter/http.ts +0 -308
  333. package/src/interpreter/index.ts +0 -32
  334. package/src/interpreter/pagination.ts +0 -207
  335. package/src/interpreter/progress.test.ts +0 -276
  336. package/src/interpreter/schema-matcher.test.ts +0 -160
  337. package/src/interpreter/schema-matcher.ts +0 -168
  338. package/src/interpreter/signals.ts +0 -73
  339. package/src/interpreter/step-handlers/for-handler.ts +0 -65
  340. package/src/interpreter/step-handlers/index.ts +0 -17
  341. package/src/interpreter/step-handlers/map-handler.ts +0 -24
  342. package/src/interpreter/step-handlers/match-handler.ts +0 -101
  343. package/src/interpreter/step-handlers/store-handler.ts +0 -78
  344. package/src/interpreter/step-handlers/types.ts +0 -17
  345. package/src/interpreter/step-handlers/validate-handler.ts +0 -30
  346. package/src/interpreter/step-handlers/webhook-handler.ts +0 -142
  347. package/src/lexer/index.ts +0 -18
  348. package/src/lexer/lexer.test.ts +0 -316
  349. package/src/lexer/tokens.ts +0 -179
  350. package/src/loader/index.ts +0 -288
  351. package/src/loader/loader.test.ts +0 -360
  352. package/src/oas/index.ts +0 -4
  353. package/src/oas/loader.ts +0 -126
  354. package/src/oas/oas.test.ts +0 -254
  355. package/src/oas/validator.ts +0 -299
  356. package/src/parser/base.ts +0 -124
  357. package/src/parser/expressions.test.ts +0 -525
  358. package/src/parser/expressions.ts +0 -314
  359. package/src/parser/index.ts +0 -3
  360. package/src/parser/match.test.ts +0 -296
  361. package/src/parser/parser.test.ts +0 -739
  362. package/src/parser/parser.ts +0 -1469
  363. package/src/parser/schedule.test.ts +0 -287
  364. package/src/parser/webhook.test.ts +0 -248
  365. package/src/plugin.ts +0 -83
  366. package/src/scheduler/cron-parser.test.ts +0 -236
  367. package/src/scheduler/cron-parser.ts +0 -236
  368. package/src/scheduler/index.ts +0 -10
  369. package/src/scheduler/scheduler.ts +0 -443
  370. package/src/scheduler/types.ts +0 -71
  371. package/src/stores/factory.ts +0 -104
  372. package/src/stores/file.test.ts +0 -276
  373. package/src/stores/file.ts +0 -211
  374. package/src/stores/index.ts +0 -6
  375. package/src/stores/memory.test.ts +0 -238
  376. package/src/stores/memory.ts +0 -63
  377. package/src/stores/postgrest.test.ts +0 -488
  378. package/src/stores/postgrest.ts +0 -263
  379. package/src/stores/stores.test.ts +0 -197
  380. package/src/stores/types.ts +0 -58
  381. package/src/sync/index.ts +0 -16
  382. package/src/sync/state.ts +0 -126
  383. package/src/sync/store.ts +0 -139
  384. package/src/sync/sync.test.ts +0 -271
  385. package/src/utils/async.ts +0 -10
  386. package/src/utils/file.ts +0 -106
  387. package/src/utils/index.ts +0 -14
  388. package/src/utils/logger.ts +0 -53
  389. package/src/utils/path.ts +0 -47
  390. package/src/webhook/index.ts +0 -15
  391. package/src/webhook/server.test.ts +0 -253
  392. package/src/webhook/server.ts +0 -389
  393. package/src/webhook/store.ts +0 -239
  394. package/src/webhook/types.ts +0 -93
  395. package/tsconfig.json +0 -17
  396. package/vitest.config.ts +0 -39
package/src/ast/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from './nodes.js';
package/src/ast/nodes.ts DELETED
@@ -1,310 +0,0 @@
1
- import type {
2
- Expression,
3
- FieldDefinition,
4
- SchemaDefinition,
5
- Statement as VagueStatement,
6
- } from 'vague-lang';
7
-
8
- // Reqon extends Vague's statements
9
- export type Statement = VagueStatement | MissionDefinition | SourceDefinition | StoreDefinition | ActionDefinition;
10
-
11
- export interface ReqonProgram {
12
- type: 'ReqonProgram';
13
- statements: Statement[];
14
- }
15
-
16
- // source Xero { auth: oauth2, base: "https://api.xero.com/..." }
17
- // source Xero from "./xero-openapi.yaml" { auth: oauth2 }
18
- export interface SourceDefinition {
19
- type: 'SourceDefinition';
20
- name: string;
21
- specPath?: string; // OAS spec path (URL or file path)
22
- config: SourceConfig;
23
- }
24
-
25
- export interface SourceConfig {
26
- auth: AuthConfig;
27
- base?: string; // Optional if using OAS (derived from spec)
28
- headers?: Record<string, Expression>;
29
- validateResponses?: boolean; // Validate responses against OAS schema
30
- rateLimit?: RateLimitSourceConfig; // Rate limiting configuration
31
- circuitBreaker?: CircuitBreakerSourceConfig; // Circuit breaker configuration
32
- }
33
-
34
- export interface CircuitBreakerSourceConfig {
35
- /** Number of failures before opening circuit (default: 5) */
36
- failureThreshold?: number;
37
- /** Time in seconds before attempting recovery (default: 30) */
38
- resetTimeout?: number;
39
- /** Number of successful requests in half-open to close circuit (default: 2) */
40
- successThreshold?: number;
41
- /** Time window in seconds for counting failures (default: 60) */
42
- failureWindow?: number;
43
- }
44
-
45
- export interface RateLimitSourceConfig {
46
- strategy?: 'pause' | 'throttle' | 'fail'; // Default: 'pause'
47
- maxWait?: number; // Max seconds to wait (default: 300)
48
- fallbackRpm?: number; // Fallback requests per minute if no headers
49
- }
50
-
51
- export interface AuthConfig {
52
- type: 'oauth2' | 'bearer' | 'basic' | 'api_key' | 'none';
53
- // Details resolved at runtime from environment/config
54
- }
55
-
56
- // store invoices_cache: nosql("invoices")
57
- // store invoices_sql: sql("accounting.invoices")
58
- export interface StoreDefinition {
59
- type: 'StoreDefinition';
60
- name: string;
61
- storeType: 'nosql' | 'sql' | 'memory';
62
- target: string; // collection/table name
63
- }
64
-
65
- // Schedule configuration for missions
66
- // schedule: every 6 hours
67
- // schedule: cron "0 */6 * * *"
68
- // schedule: at "2025-01-20 09:00 UTC"
69
- export interface ScheduleDefinition {
70
- type: 'ScheduleDefinition';
71
- scheduleType: 'interval' | 'cron' | 'once';
72
- // For interval-based scheduling
73
- interval?: IntervalSchedule;
74
- // For cron-based scheduling
75
- cronExpression?: string;
76
- // For one-time scheduling
77
- runAt?: string; // ISO 8601 datetime or parseable date string
78
- // Optional timezone (defaults to UTC)
79
- timezone?: string;
80
- // Maximum concurrent executions (default: 1)
81
- maxConcurrency?: number;
82
- // Skip execution if previous run is still running (default: true)
83
- skipIfRunning?: boolean;
84
- // Retry configuration for failed scheduled runs
85
- retryOnFailure?: ScheduleRetryConfig;
86
- }
87
-
88
- export interface IntervalSchedule {
89
- value: number;
90
- unit: 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks';
91
- }
92
-
93
- export interface ScheduleRetryConfig {
94
- maxRetries: number;
95
- delaySeconds: number;
96
- }
97
-
98
- // mission SyncXeroInvoices { ... }
99
- export interface MissionDefinition {
100
- type: 'MissionDefinition';
101
- name: string;
102
- schedule?: ScheduleDefinition;
103
- sources: SourceDefinition[];
104
- stores: StoreDefinition[];
105
- schemas: SchemaDefinition[];
106
- actions: ActionDefinition[];
107
- pipeline: PipelineDefinition;
108
- }
109
-
110
- // action FetchInvoiceList { ... }
111
- export interface ActionDefinition {
112
- type: 'ActionDefinition';
113
- name: string;
114
- steps: ActionStep[];
115
- }
116
-
117
- export type ActionStep = FetchStep | ForStep | MapStep | ValidateStep | StoreStep | MatchStep | LetStep | WebhookStep;
118
-
119
- // let myVar = expression
120
- export interface LetStep {
121
- type: 'LetStep';
122
- name: string;
123
- value: Expression;
124
- }
125
-
126
- // wait { timeout: 60000, path: "/webhooks/callback", ... }
127
- // Waits for an external webhook callback before continuing execution
128
- export interface WebhookStep {
129
- type: 'WebhookStep';
130
- /** Timeout in milliseconds to wait for webhook (default: 300000 = 5 minutes) */
131
- timeout?: number;
132
- /** Path for the webhook endpoint (e.g., "/webhooks/callback") */
133
- path?: string;
134
- /** Number of webhook events to collect before continuing (default: 1) */
135
- expectedEvents?: number;
136
- /** Filter expression for matching webhook events */
137
- eventFilter?: Expression;
138
- /** Retry configuration if timeout occurs */
139
- retryOnTimeout?: RetryConfig;
140
- /** Store configuration for saving webhook payloads */
141
- storage?: WebhookStorageConfig;
142
- }
143
-
144
- export interface WebhookStorageConfig {
145
- /** Store name to save webhook payloads */
146
- target: string;
147
- /** Expression for extracting key from webhook payload */
148
- key?: Expression;
149
- }
150
-
151
- // Flow control directives for match arms
152
- export type FlowDirective =
153
- | { type: 'continue' } // proceed to next pipeline stage
154
- | { type: 'skip' } // skip remaining steps, move to next stage
155
- | { type: 'abort'; message?: string } // halt mission with error
156
- | { type: 'retry'; backoff?: RetryConfig } // retry current action
157
- | { type: 'queue'; target?: string } // queue for later processing
158
- | { type: 'jump'; action: string; then?: 'retry' | 'continue' }; // jump to action
159
-
160
- // match response { Schema1 -> steps..., Schema2 -> flow directive }
161
- export interface MatchStep {
162
- type: 'MatchStep';
163
- target: Expression; // what to match (usually 'response')
164
- arms: MatchArm[];
165
- }
166
-
167
- export interface MatchArm {
168
- /** Schema name to match against, or '_' for wildcard */
169
- schema: string;
170
- /** Steps to execute if matched */
171
- steps?: ActionStep[];
172
- /** Flow control directive (if no steps) */
173
- flow?: FlowDirective;
174
- }
175
-
176
- // get "/Invoices" { paginate: ..., until: ... }
177
- // call Xero.getInvoices { paginate: ... } -- OAS operationId reference
178
- // get "/Invoices" { since: lastSync } -- Incremental sync
179
- export interface FetchStep {
180
- type: 'FetchStep';
181
- // Traditional: explicit method + path
182
- method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
183
- path?: Expression; // Can contain interpolations like "/Invoices/{id}"
184
- // OAS-based: source.operationId reference
185
- operationRef?: OperationRef;
186
- source?: string; // Which source to use (defaults to first defined)
187
- body?: Expression;
188
- headers?: Record<string, Expression>;
189
- paginate?: PaginationConfig;
190
- until?: Expression; // Condition to stop pagination
191
- retry?: RetryConfig;
192
- // Incremental sync
193
- since?: SinceConfig;
194
- }
195
-
196
- // Configuration for incremental sync
197
- export interface SinceConfig {
198
- /** How to resolve the "since" timestamp */
199
- type: 'lastSync' | 'expression';
200
- /** Custom checkpoint key (defaults to source:endpoint) */
201
- key?: string;
202
- /** Query parameter name for the since value (default: varies by API) */
203
- param?: string;
204
- /** Date format for the since value */
205
- format?: 'iso' | 'unix' | 'unix-ms' | 'date-only';
206
- /** Expression to evaluate for 'expression' type */
207
- expression?: Expression;
208
- /** Field in response to use as the new "since" value for next sync */
209
- updateFrom?: string;
210
- }
211
-
212
- export interface OperationRef {
213
- source: string; // Source name (e.g., "Xero")
214
- operationId: string; // OAS operationId (e.g., "getInvoices")
215
- }
216
-
217
- export interface PaginationConfig {
218
- type: 'offset' | 'cursor' | 'page';
219
- param: string; // Query param name: "page", "offset", "cursor"
220
- pageSize: number;
221
- cursorPath?: string; // For cursor pagination: where to find next cursor in response
222
- }
223
-
224
- export interface RetryConfig {
225
- maxAttempts: number;
226
- backoff: 'exponential' | 'linear' | 'constant';
227
- initialDelay: number; // ms
228
- maxDelay?: number; // ms
229
- }
230
-
231
- // for invoice in invoices_cache where .partial == true { ... }
232
- export interface ForStep {
233
- type: 'ForStep';
234
- variable: string;
235
- collection: Expression;
236
- condition?: Expression; // where clause
237
- steps: ActionStep[];
238
- }
239
-
240
- // map invoice -> StandardInvoice { id: .InvoiceID, ... }
241
- export interface MapStep {
242
- type: 'MapStep';
243
- source: Expression;
244
- targetSchema: string;
245
- mappings: FieldMapping[];
246
- }
247
-
248
- export interface FieldMapping {
249
- field: string;
250
- expression: Expression;
251
- }
252
-
253
- // validate response { assume .Total is decimal, ... }
254
- export interface ValidateStep {
255
- type: 'ValidateStep';
256
- target: Expression;
257
- constraints: ValidationConstraint[];
258
- }
259
-
260
- export interface ValidationConstraint {
261
- type: 'ValidationConstraint';
262
- condition: Expression;
263
- message?: string;
264
- severity: 'error' | 'warning';
265
- }
266
-
267
- // store response -> invoices_cache { key: .InvoiceID, partial: false }
268
- export interface StoreStep {
269
- type: 'StoreStep';
270
- source: Expression;
271
- target: string; // store name
272
- options: StoreOptions;
273
- }
274
-
275
- export interface StoreOptions {
276
- key?: Expression; // Primary key field
277
- partial?: boolean; // Mark as partial entity
278
- upsert?: boolean; // Update if exists
279
- }
280
-
281
- // run FetchInvoiceList then HydrateInvoices then NormalizeInvoices
282
- // run [FetchOrders, FetchPayments] then ReconcileData -- parallel stages
283
- export interface PipelineDefinition {
284
- type: 'PipelineDefinition';
285
- stages: PipelineStage[];
286
- }
287
-
288
- export interface PipelineStage {
289
- /** Single action name (for sequential stages) */
290
- action?: string;
291
- /** Multiple action names (for parallel stages with bracket syntax) */
292
- actions?: string[];
293
- /** Optional: only run if condition true */
294
- condition?: Expression;
295
- }
296
-
297
- /** Helper to check if a stage is parallel */
298
- export function isParallelStage(stage: PipelineStage): stage is PipelineStage & { actions: string[] } {
299
- return Array.isArray(stage.actions) && stage.actions.length > 0;
300
- }
301
-
302
- /** Helper to get action names from a stage (works for both single and parallel) */
303
- export function getStageActions(stage: PipelineStage): string[] {
304
- if (stage.actions) return stage.actions;
305
- if (stage.action) return [stage.action];
306
- return [];
307
- }
308
-
309
- // Re-export Vague types for convenience
310
- export type { Expression, FieldDefinition, SchemaDefinition } from 'vague-lang';
@@ -1,326 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import {
3
- AdaptiveRateLimiter,
4
- parseRateLimitHeaders,
5
- RateLimitError,
6
- RateLimitTimeoutError,
7
- } from './rate-limiter.js';
8
- import { InMemoryTokenStore } from './token-store.js';
9
- import type { OAuth2Tokens, RateLimitEvent } from './types.js';
10
-
11
- describe('parseRateLimitHeaders', () => {
12
- it('parses X-RateLimit headers', () => {
13
- const headers = {
14
- 'X-RateLimit-Limit': '100',
15
- 'X-RateLimit-Remaining': '42',
16
- 'X-RateLimit-Reset': '1700000000',
17
- };
18
-
19
- const info = parseRateLimitHeaders(headers);
20
-
21
- expect(info.limit).toBe(100);
22
- expect(info.remaining).toBe(42);
23
- expect(info.resetAt).toBeInstanceOf(Date);
24
- expect(info.resetAt?.getTime()).toBe(1700000000 * 1000);
25
- });
26
-
27
- it('parses lowercase ratelimit headers', () => {
28
- const headers = {
29
- 'ratelimit-limit': '60',
30
- 'ratelimit-remaining': '5',
31
- };
32
-
33
- const info = parseRateLimitHeaders(headers);
34
-
35
- expect(info.limit).toBe(60);
36
- expect(info.remaining).toBe(5);
37
- });
38
-
39
- it('parses Retry-After header (seconds)', () => {
40
- const headers = {
41
- 'Retry-After': '30',
42
- };
43
-
44
- const info = parseRateLimitHeaders(headers);
45
-
46
- expect(info.retryAfter).toBe(30);
47
- });
48
-
49
- it('handles missing headers gracefully', () => {
50
- const info = parseRateLimitHeaders({});
51
-
52
- expect(info.limit).toBeUndefined();
53
- expect(info.remaining).toBeUndefined();
54
- expect(info.resetAt).toBeUndefined();
55
- expect(info.retryAfter).toBeUndefined();
56
- });
57
- });
58
-
59
- describe('AdaptiveRateLimiter', () => {
60
- let limiter: AdaptiveRateLimiter;
61
-
62
- beforeEach(() => {
63
- limiter = new AdaptiveRateLimiter();
64
- });
65
-
66
- it('allows requests when no limits recorded', async () => {
67
- const canProceed = await limiter.canProceed('TestAPI');
68
- expect(canProceed).toBe(true);
69
- });
70
-
71
- it('blocks requests when remaining is 0', async () => {
72
- const futureReset = new Date(Date.now() + 60000);
73
- limiter.recordResponse('TestAPI', {
74
- remaining: 0,
75
- limit: 100,
76
- resetAt: futureReset,
77
- });
78
-
79
- const canProceed = await limiter.canProceed('TestAPI');
80
- expect(canProceed).toBe(false);
81
- });
82
-
83
- it('allows requests after reset time passes', async () => {
84
- const pastReset = new Date(Date.now() - 1000);
85
- limiter.recordResponse('TestAPI', {
86
- remaining: 0,
87
- limit: 100,
88
- resetAt: pastReset,
89
- });
90
-
91
- const canProceed = await limiter.canProceed('TestAPI');
92
- expect(canProceed).toBe(true);
93
- });
94
-
95
- it('blocks during retry-after period', async () => {
96
- limiter.recordResponse('TestAPI', {
97
- retryAfter: 60, // 60 seconds
98
- });
99
-
100
- const canProceed = await limiter.canProceed('TestAPI');
101
- expect(canProceed).toBe(false);
102
- });
103
-
104
- it('tracks limits per source', async () => {
105
- limiter.recordResponse('API1', { remaining: 0, resetAt: new Date(Date.now() + 60000) });
106
- limiter.recordResponse('API2', { remaining: 50, limit: 100 });
107
-
108
- expect(await limiter.canProceed('API1')).toBe(false);
109
- expect(await limiter.canProceed('API2')).toBe(true);
110
- });
111
-
112
- it('tracks limits per endpoint within source', async () => {
113
- limiter.recordResponse('API', { remaining: 0, resetAt: new Date(Date.now() + 60000) }, '/invoices');
114
- limiter.recordResponse('API', { remaining: 50, limit: 100 }, '/contacts');
115
-
116
- expect(await limiter.canProceed('API', '/invoices')).toBe(false);
117
- expect(await limiter.canProceed('API', '/contacts')).toBe(true);
118
- });
119
-
120
- it('provides accurate status', () => {
121
- limiter.recordResponse('TestAPI', {
122
- remaining: 42,
123
- limit: 100,
124
- resetAt: new Date(Date.now() + 60000),
125
- });
126
-
127
- const status = limiter.getStatus('TestAPI');
128
-
129
- expect(status.remaining).toBe(42);
130
- expect(status.limit).toBe(100);
131
- expect(status.isLimited).toBe(false);
132
- });
133
-
134
- describe('fail strategy', () => {
135
- it('throws RateLimitError immediately when rate limited', async () => {
136
- limiter.configure('FailAPI', { strategy: 'fail' });
137
- limiter.recordResponse('FailAPI', {
138
- remaining: 0,
139
- resetAt: new Date(Date.now() + 60000),
140
- });
141
-
142
- await expect(limiter.waitForCapacity('FailAPI')).rejects.toThrow(RateLimitError);
143
- });
144
-
145
- it('includes reset time in error', async () => {
146
- limiter.configure('FailAPI', { strategy: 'fail' });
147
- const resetAt = new Date(Date.now() + 60000);
148
- limiter.recordResponse('FailAPI', { remaining: 0, resetAt });
149
-
150
- try {
151
- await limiter.waitForCapacity('FailAPI');
152
- expect.fail('Should have thrown');
153
- } catch (error) {
154
- expect(error).toBeInstanceOf(RateLimitError);
155
- expect((error as RateLimitError).resetAt).toEqual(resetAt);
156
- }
157
- });
158
- });
159
-
160
- describe('pause strategy', () => {
161
- it('throws RateLimitTimeoutError when maxWait exceeded', async () => {
162
- limiter.configure('PauseAPI', { strategy: 'pause', maxWait: 1 });
163
- limiter.recordResponse('PauseAPI', {
164
- remaining: 0,
165
- resetAt: new Date(Date.now() + 60000), // 60s in future
166
- });
167
-
168
- await expect(limiter.waitForCapacity('PauseAPI')).rejects.toThrow(RateLimitTimeoutError);
169
- });
170
-
171
- it('proceeds after reset time passes', async () => {
172
- limiter.configure('PauseAPI', { strategy: 'pause', maxWait: 5 });
173
- // Reset in 50ms
174
- limiter.recordResponse('PauseAPI', {
175
- remaining: 0,
176
- resetAt: new Date(Date.now() + 50),
177
- });
178
-
179
- // Should complete without throwing
180
- await limiter.waitForCapacity('PauseAPI');
181
- });
182
- });
183
-
184
- describe('throttle strategy', () => {
185
- it('calculates delay based on remaining requests and reset time', () => {
186
- limiter.configure('ThrottleAPI', { strategy: 'throttle' });
187
- limiter.recordResponse('ThrottleAPI', {
188
- remaining: 10,
189
- limit: 100,
190
- resetAt: new Date(Date.now() + 10000), // 10s left
191
- });
192
-
193
- const delay = limiter.getThrottleDelay('ThrottleAPI');
194
- // 10s / 10 remaining = 1s per request = 1000ms
195
- expect(delay).toBeGreaterThanOrEqual(900);
196
- expect(delay).toBeLessThanOrEqual(1100);
197
- });
198
-
199
- it('returns 0 delay when not in throttle mode', () => {
200
- limiter.configure('PauseAPI', { strategy: 'pause' });
201
- limiter.recordResponse('PauseAPI', { remaining: 10, limit: 100 });
202
-
203
- const delay = limiter.getThrottleDelay('PauseAPI');
204
- expect(delay).toBe(0);
205
- });
206
-
207
- it('uses fallback RPM when no rate limit headers', () => {
208
- limiter.configure('FallbackAPI', { strategy: 'throttle', fallbackRpm: 60 });
209
- limiter.recordResponse('FallbackAPI', {}); // No rate limit info
210
-
211
- const delay = limiter.getThrottleDelay('FallbackAPI');
212
- // 60 RPM = 1 per second = 1000ms intervals
213
- expect(delay).toBeLessThanOrEqual(1000);
214
- });
215
- });
216
-
217
- describe('callbacks', () => {
218
- it('calls onRateLimited when rate limited', async () => {
219
- const onRateLimited = vi.fn();
220
- limiter.setCallbacks({ onRateLimited });
221
- // Use maxWait of 10s so it doesn't timeout immediately (wait is only 50ms)
222
- limiter.configure('CallbackAPI', { strategy: 'pause', maxWait: 10 });
223
- limiter.recordResponse('CallbackAPI', {
224
- remaining: 0,
225
- resetAt: new Date(Date.now() + 50), // Resets in 50ms
226
- });
227
-
228
- await limiter.waitForCapacity('CallbackAPI');
229
-
230
- expect(onRateLimited).toHaveBeenCalledTimes(1);
231
- expect(onRateLimited).toHaveBeenCalledWith(
232
- expect.objectContaining({
233
- source: 'CallbackAPI',
234
- strategy: 'pause',
235
- })
236
- );
237
- });
238
-
239
- it('calls onResumed after waiting completes', async () => {
240
- const onResumed = vi.fn();
241
- limiter.setCallbacks({ onResumed });
242
- limiter.configure('ResumeAPI', { strategy: 'pause', maxWait: 5 });
243
- // Reset in 50ms
244
- limiter.recordResponse('ResumeAPI', {
245
- remaining: 0,
246
- resetAt: new Date(Date.now() + 50),
247
- });
248
-
249
- await limiter.waitForCapacity('ResumeAPI');
250
-
251
- expect(onResumed).toHaveBeenCalledTimes(1);
252
- expect(onResumed).toHaveBeenCalledWith(
253
- expect.objectContaining({
254
- source: 'ResumeAPI',
255
- })
256
- );
257
- });
258
- });
259
- });
260
-
261
- describe('InMemoryTokenStore', () => {
262
- let store: InMemoryTokenStore;
263
-
264
- beforeEach(() => {
265
- store = new InMemoryTokenStore();
266
- });
267
-
268
- it('stores and retrieves tokens', async () => {
269
- const tokens: OAuth2Tokens = {
270
- accessToken: 'access123',
271
- refreshToken: 'refresh456',
272
- expiresAt: new Date(Date.now() + 3600000),
273
- };
274
-
275
- await store.set('connection-1', tokens);
276
- const retrieved = await store.get('connection-1');
277
-
278
- expect(retrieved?.accessToken).toBe('access123');
279
- expect(retrieved?.refreshToken).toBe('refresh456');
280
- });
281
-
282
- it('returns null for unknown connections', async () => {
283
- const result = await store.get('unknown');
284
- expect(result).toBeNull();
285
- });
286
-
287
- it('deletes tokens', async () => {
288
- await store.set('connection-1', { accessToken: 'test' });
289
- await store.delete('connection-1');
290
-
291
- const result = await store.get('connection-1');
292
- expect(result).toBeNull();
293
- });
294
-
295
- it('lists all connections', async () => {
296
- await store.set('conn-1', { accessToken: 'a' });
297
- await store.set('conn-2', { accessToken: 'b' });
298
- await store.set('conn-3', { accessToken: 'c' });
299
-
300
- const connections = await store.list();
301
-
302
- expect(connections).toHaveLength(3);
303
- expect(connections).toContain('conn-1');
304
- expect(connections).toContain('conn-2');
305
- expect(connections).toContain('conn-3');
306
- });
307
-
308
- it('identifies tokens needing refresh', async () => {
309
- // Token expiring in 10 seconds (within 5 min buffer)
310
- await store.set('expiring-soon', {
311
- accessToken: 'test',
312
- expiresAt: new Date(Date.now() + 10000),
313
- });
314
-
315
- // Token not expiring soon
316
- await store.set('valid', {
317
- accessToken: 'test',
318
- expiresAt: new Date(Date.now() + 3600000),
319
- });
320
-
321
- const needsRefresh = await store.getTokensNeedingRefresh(300);
322
-
323
- expect(needsRefresh).toContain('expiring-soon');
324
- expect(needsRefresh).not.toContain('valid');
325
- });
326
- });