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,488 @@
1
+ ---
2
+ sidebar_position: 20
3
+ ---
4
+
5
+ # Examples
6
+
7
+ Real-world examples demonstrating Reqon's capabilities.
8
+
9
+ ## Basic API Sync
10
+
11
+ Fetch and store data from a public API:
12
+
13
+ ```vague
14
+ mission JSONPlaceholderSync {
15
+ source API {
16
+ auth: none,
17
+ base: "https://jsonplaceholder.typicode.com"
18
+ }
19
+
20
+ store posts: file("posts")
21
+ store users: file("users")
22
+
23
+ action FetchPosts {
24
+ get "/posts"
25
+
26
+ for post in response {
27
+ store post -> posts { key: .id }
28
+ }
29
+ }
30
+
31
+ action FetchUsers {
32
+ get "/users"
33
+
34
+ for user in response {
35
+ map user -> User {
36
+ id: .id,
37
+ name: .name,
38
+ email: lowercase(.email),
39
+ company: .company.name
40
+ }
41
+ store user -> users { key: .id }
42
+ }
43
+ }
44
+
45
+ run [FetchPosts, FetchUsers]
46
+ }
47
+ ```
48
+
49
+ ## Xero Integration
50
+
51
+ Sync invoices from Xero with OAuth2 authentication:
52
+
53
+ ```vague
54
+ mission XeroInvoiceSync {
55
+ source Xero {
56
+ auth: oauth2,
57
+ base: "https://api.xero.com/api.xro/2.0",
58
+ headers: {
59
+ "Xero-Tenant-Id": env("XERO_TENANT_ID")
60
+ }
61
+ }
62
+
63
+ store invoices: file("xero-invoices")
64
+ store errors: file("sync-errors")
65
+
66
+ schema XeroInvoice {
67
+ InvoiceID: string,
68
+ InvoiceNumber: string,
69
+ Contact: { ContactID: string, Name: string },
70
+ Total: number,
71
+ Status: string
72
+ }
73
+
74
+ schema ErrorResponse {
75
+ error: string,
76
+ code: number
77
+ }
78
+
79
+ action FetchInvoices {
80
+ get "/Invoices" {
81
+ params: { page: 1 },
82
+ paginate: page(page, 100),
83
+ until: length(response.Invoices) == 0,
84
+ since: lastSync
85
+ }
86
+
87
+ match response {
88
+ ErrorResponse where .code == 401 -> jump RefreshToken then retry,
89
+ ErrorResponse -> queue errors { item: { error: response.error } },
90
+ _ -> continue
91
+ }
92
+
93
+ for invoice in response.Invoices {
94
+ map invoice -> StandardInvoice {
95
+ id: .InvoiceID,
96
+ number: .InvoiceNumber,
97
+ customerId: .Contact.ContactID,
98
+ customerName: .Contact.Name,
99
+ amount: .Total,
100
+ status: lowercase(.Status),
101
+ source: "xero"
102
+ }
103
+ store invoice -> invoices { key: .id, upsert: true }
104
+ }
105
+ }
106
+
107
+ action RefreshToken {
108
+ post "https://identity.xero.com/connect/token" {
109
+ body: {
110
+ grant_type: "refresh_token",
111
+ refresh_token: env("XERO_REFRESH_TOKEN"),
112
+ client_id: env("XERO_CLIENT_ID"),
113
+ client_secret: env("XERO_CLIENT_SECRET")
114
+ }
115
+ }
116
+ }
117
+
118
+ run FetchInvoices
119
+ }
120
+ ```
121
+
122
+ ## Multi-Source Reconciliation
123
+
124
+ Sync and reconcile data from multiple sources:
125
+
126
+ ```vague
127
+ mission OrderReconciliation {
128
+ source Shopify { auth: bearer, base: "https://mystore.myshopify.com/admin/api/2024-01" }
129
+ source Stripe { auth: bearer, base: "https://api.stripe.com/v1" }
130
+ source Warehouse { auth: api_key, base: "https://warehouse.example.com/api" }
131
+
132
+ store shopifyOrders: memory("shopify")
133
+ store stripePayments: memory("stripe")
134
+ store warehouseShipments: memory("warehouse")
135
+ store reconciledOrders: file("reconciled")
136
+ store discrepancies: file("discrepancies")
137
+
138
+ action FetchShopify {
139
+ get Shopify "/orders.json" {
140
+ params: { status: "any", limit: 250 },
141
+ paginate: cursor(page_info, 250, "link.next"),
142
+ until: response.orders == null or length(response.orders) == 0
143
+ }
144
+
145
+ for order in response.orders {
146
+ store order -> shopifyOrders { key: .id }
147
+ }
148
+ }
149
+
150
+ action FetchStripe {
151
+ get Stripe "/payment_intents" {
152
+ params: { limit: 100 },
153
+ paginate: cursor(starting_after, 100, "data[length(data)-1].id"),
154
+ until: response.has_more == false
155
+ }
156
+
157
+ for payment in response.data {
158
+ store payment -> stripePayments { key: .id }
159
+ }
160
+ }
161
+
162
+ action FetchWarehouse {
163
+ get Warehouse "/shipments" {
164
+ paginate: offset(offset, 100),
165
+ until: length(response.shipments) == 0
166
+ }
167
+
168
+ for shipment in response.shipments {
169
+ store shipment -> warehouseShipments { key: .order_id }
170
+ }
171
+ }
172
+
173
+ action Reconcile {
174
+ for order in shopifyOrders {
175
+ // Find matching payment
176
+ for payment in stripePayments where .metadata.order_id == order.id {
177
+ // Find matching shipment
178
+ for shipment in warehouseShipments where .order_id == order.id {
179
+ map order -> ReconciledOrder {
180
+ orderId: order.id,
181
+ orderAmount: order.total_price,
182
+ paymentId: payment.id,
183
+ paymentAmount: payment.amount / 100,
184
+ shipmentId: shipment.id,
185
+ shipmentStatus: shipment.status,
186
+ amountMatch: order.total_price == payment.amount / 100,
187
+ isShipped: shipment.status == "delivered"
188
+ }
189
+
190
+ match order {
191
+ _ where order.amountMatch == false -> {
192
+ store order -> discrepancies { key: .orderId }
193
+ },
194
+ _ -> store order -> reconciledOrders { key: .orderId }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+
201
+ run [FetchShopify, FetchStripe, FetchWarehouse] then Reconcile
202
+ }
203
+ ```
204
+
205
+ ## OpenAPI Integration
206
+
207
+ Use OpenAPI spec for type-safe API calls:
208
+
209
+ ```vague
210
+ mission PetstoreSync {
211
+ source Petstore from "https://petstore3.swagger.io/api/v3/openapi.json" {
212
+ auth: api_key,
213
+ validateResponses: true
214
+ }
215
+
216
+ store pets: file("pets")
217
+ store newPets: file("new-pets")
218
+
219
+ action FetchAllPets {
220
+ call Petstore.findPetsByStatus {
221
+ params: { status: "available" }
222
+ }
223
+
224
+ for pet in response {
225
+ validate pet {
226
+ assume .id is number,
227
+ assume .name is string
228
+ }
229
+ store pet -> pets { key: .id }
230
+ }
231
+ }
232
+
233
+ action CreatePet {
234
+ for pet in newPets {
235
+ call Petstore.addPet {
236
+ body: {
237
+ name: pet.name,
238
+ photoUrls: pet.photos or [],
239
+ status: "available"
240
+ }
241
+ }
242
+
243
+ match response {
244
+ { id: _ } -> {
245
+ store response -> pets { key: .id }
246
+ delete newPets[pet.id]
247
+ },
248
+ _ -> continue
249
+ }
250
+ }
251
+ }
252
+
253
+ run FetchAllPets
254
+ }
255
+ ```
256
+
257
+ ## Error Handling with Dead Letter Queue
258
+
259
+ Robust error handling with retry and DLQ:
260
+
261
+ ```vague
262
+ mission RobustSync {
263
+ source API {
264
+ auth: bearer,
265
+ base: "https://api.example.com",
266
+ rateLimit: { requestsPerMinute: 60, strategy: "pause" },
267
+ circuitBreaker: { failureThreshold: 5, resetTimeout: 30000 }
268
+ }
269
+
270
+ store data: file("data")
271
+ store dlq: file("dead-letter-queue")
272
+ store processed: file("processed")
273
+
274
+ schema SuccessResponse { data: any }
275
+ schema RateLimitError { error: string, retryAfter: number }
276
+ schema AuthError { error: string, code: number }
277
+ schema ValidationError { error: string, details: array }
278
+
279
+ action FetchWithRetry {
280
+ get "/items" {
281
+ paginate: offset(offset, 100),
282
+ until: length(response.data) == 0,
283
+ retry: { maxAttempts: 3, backoff: exponential }
284
+ }
285
+
286
+ match response {
287
+ RateLimitError -> retry { delay: response.retryAfter * 1000 },
288
+ AuthError where .code == 401 -> jump RefreshAuth then retry,
289
+ AuthError -> abort response.error,
290
+ ValidationError -> {
291
+ store response -> dlq { key: uuid() }
292
+ skip
293
+ },
294
+ SuccessResponse -> continue,
295
+ _ -> abort "Unexpected response"
296
+ }
297
+
298
+ for item in response.data {
299
+ store item -> data { key: .id }
300
+ }
301
+ }
302
+
303
+ action ProcessItems {
304
+ for item in data where .processed != true {
305
+ get concat("/items/", item.id, "/process")
306
+
307
+ match response {
308
+ { error: e } -> {
309
+ queue dlq {
310
+ item: {
311
+ itemId: item.id,
312
+ error: e,
313
+ timestamp: now(),
314
+ retryCount: (item.retryCount or 0) + 1
315
+ }
316
+ }
317
+ skip
318
+ },
319
+ _ -> {
320
+ store { ...item, processed: true } -> processed { key: .id }
321
+ }
322
+ }
323
+ }
324
+ }
325
+
326
+ action RefreshAuth {
327
+ post "/auth/refresh" {
328
+ body: { refreshToken: env("REFRESH_TOKEN") }
329
+ }
330
+ }
331
+
332
+ run FetchWithRetry then ProcessItems
333
+ }
334
+ ```
335
+
336
+ ## Scheduled Incremental Sync
337
+
338
+ Regular incremental sync with scheduling:
339
+
340
+ ```vague
341
+ mission ScheduledSync {
342
+ schedule: every 15 minutes
343
+ skipIfRunning: true
344
+
345
+ source API {
346
+ auth: oauth2,
347
+ base: "https://api.example.com"
348
+ }
349
+
350
+ store customers: sql("customers")
351
+ store orders: sql("orders")
352
+ store syncLog: file("sync-log")
353
+
354
+ action SyncCustomers {
355
+ store { action: "SyncCustomers", started: now() } -> syncLog
356
+
357
+ get "/customers" {
358
+ since: lastSync,
359
+ paginate: cursor(after, 100, "cursor.next"),
360
+ until: response.cursor.next == null
361
+ }
362
+
363
+ for customer in response.data {
364
+ store customer -> customers { key: .id, upsert: true }
365
+ }
366
+
367
+ store {
368
+ action: "SyncCustomers",
369
+ completed: now(),
370
+ count: length(response.data)
371
+ } -> syncLog
372
+ }
373
+
374
+ action SyncOrders {
375
+ store { action: "SyncOrders", started: now() } -> syncLog
376
+
377
+ get "/orders" {
378
+ since: lastSync,
379
+ paginate: cursor(after, 100, "cursor.next"),
380
+ until: response.cursor.next == null
381
+ }
382
+
383
+ for order in response.data {
384
+ store order -> orders { key: .id, upsert: true }
385
+ }
386
+
387
+ store {
388
+ action: "SyncOrders",
389
+ completed: now(),
390
+ count: length(response.data)
391
+ } -> syncLog
392
+ }
393
+
394
+ run [SyncCustomers, SyncOrders]
395
+ }
396
+ ```
397
+
398
+ ## GitHub Repository Sync
399
+
400
+ Sync repository data from GitHub:
401
+
402
+ ```vague
403
+ mission GitHubSync {
404
+ source GitHub {
405
+ auth: bearer,
406
+ base: "https://api.github.com",
407
+ headers: {
408
+ "Accept": "application/vnd.github.v3+json"
409
+ }
410
+ }
411
+
412
+ store repos: file("repos")
413
+ store issues: file("issues")
414
+ store pullRequests: file("pull-requests")
415
+
416
+ action FetchRepos {
417
+ get "/user/repos" {
418
+ params: { per_page: 100, sort: "updated" },
419
+ paginate: page(page, 100),
420
+ until: length(response) < 100
421
+ }
422
+
423
+ for repo in response {
424
+ map repo -> Repository {
425
+ id: .id,
426
+ name: .name,
427
+ fullName: .full_name,
428
+ description: .description,
429
+ stars: .stargazers_count,
430
+ forks: .forks_count,
431
+ language: .language,
432
+ updatedAt: .updated_at
433
+ }
434
+ store repo -> repos { key: .id }
435
+ }
436
+ }
437
+
438
+ action FetchIssues {
439
+ for repo in repos where .open_issues_count > 0 {
440
+ get concat("/repos/", repo.fullName, "/issues") {
441
+ params: { state: "open", per_page: 100 },
442
+ paginate: page(page, 100),
443
+ until: length(response) < 100
444
+ }
445
+
446
+ for issue in response where .pull_request == null {
447
+ map issue -> Issue {
448
+ id: .id,
449
+ repoId: repo.id,
450
+ number: .number,
451
+ title: .title,
452
+ state: .state,
453
+ author: .user.login,
454
+ createdAt: .created_at
455
+ }
456
+ store issue -> issues { key: .id }
457
+ }
458
+ }
459
+ }
460
+
461
+ action FetchPRs {
462
+ for repo in repos {
463
+ get concat("/repos/", repo.fullName, "/pulls") {
464
+ params: { state: "open", per_page: 100 }
465
+ }
466
+
467
+ for pr in response {
468
+ map pr -> PullRequest {
469
+ id: .id,
470
+ repoId: repo.id,
471
+ number: .number,
472
+ title: .title,
473
+ author: .user.login,
474
+ branch: .head.ref,
475
+ createdAt: .created_at
476
+ }
477
+ store pr -> pullRequests { key: .id }
478
+ }
479
+ }
480
+ }
481
+
482
+ run FetchRepos then [FetchIssues, FetchPRs]
483
+ }
484
+ ```
485
+
486
+ ## More Examples
487
+
488
+ For more examples, see the [examples directory](https://github.com/mcclowes/reqon/tree/main/examples) in the Reqon repository.