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,297 @@
1
+ # Reqon vs Temporal: E-Commerce Order Reconciliation
2
+
3
+ This example demonstrates a complex multi-vendor order reconciliation pipeline that syncs data from Shopify, Stripe, and ShipStation, validates for discrepancies, and stores results in a database.
4
+
5
+ ## The Scenario
6
+
7
+ An e-commerce company needs to:
8
+ 1. Sync orders from Shopify (source of truth for orders)
9
+ 2. Sync payments from Stripe (source of truth for payments)
10
+ 3. Sync shipments from ShipStation (source of truth for fulfillment)
11
+ 4. Cross-reference and validate all three data sources
12
+ 5. Flag discrepancies (unpaid orders, missing shipments, refund mismatches)
13
+ 6. Store reconciled data with audit trail
14
+ 7. Handle rate limits, retries, and pagination across all APIs
15
+ 8. Run daily with incremental sync
16
+
17
+ ## The Numbers
18
+
19
+ | Metric | Reqon | Temporal |
20
+ |--------|-------|----------|
21
+ | **Total Lines of Code** | ~280 | ~1,500+ |
22
+ | **Files** | 1 | 12 |
23
+ | **Dependencies** | 1 (reqon) | 8+ (@temporalio/*, axios, pg, stripe) |
24
+ | **Infrastructure** | None | Temporal Server + PostgreSQL + Workers |
25
+ | **Setup Time** | 0 minutes | 30+ minutes |
26
+ | **Learning Curve** | Hours | Days/Weeks |
27
+
28
+ ## Side-by-Side Comparison
29
+
30
+ ### 1. API Pagination
31
+
32
+ **Reqon** (2 lines):
33
+ ```vague
34
+ paginate: cursor(page_info, 250, "link.next"),
35
+ until: response.orders.length == 0,
36
+ ```
37
+
38
+ **Temporal** (40+ lines):
39
+ ```typescript
40
+ let cursor: string | null = null;
41
+ do {
42
+ Context.current().heartbeat({ page: pageCount, ordersFound: allOrders.length });
43
+ const { orders, nextCursor } = await client.fetchOrdersPage(cursor, since);
44
+ for (const order of orders) {
45
+ allOrders.push(transformOrder(order));
46
+ }
47
+ cursor = nextCursor;
48
+ pageCount++;
49
+ } while (cursor);
50
+ ```
51
+
52
+ ### 2. Rate Limiting
53
+
54
+ **Reqon** (4 lines):
55
+ ```vague
56
+ rateLimit: {
57
+ strategy: "pause",
58
+ maxWait: 120,
59
+ fallbackRpm: 40
60
+ }
61
+ ```
62
+
63
+ **Temporal** (50+ lines):
64
+ ```typescript
65
+ class ShopifyClient {
66
+ private rateLimitState: RateLimitState | null = null;
67
+
68
+ private updateRateLimitState(headers: Record<string, string>): void {
69
+ // Parse headers, calculate remaining, track reset time...
70
+ }
71
+
72
+ private async waitForRateLimit(): Promise<void> {
73
+ if (!this.rateLimitState) return;
74
+ if (this.rateLimitState.remaining < 5) {
75
+ const waitTime = Math.max(0, this.rateLimitState.resetAt.getTime() - Date.now());
76
+ if (waitTime > 0) {
77
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
78
+ }
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ ### 3. Schema Transformation
85
+
86
+ **Reqon** (15 lines):
87
+ ```vague
88
+ map order -> UnifiedOrder {
89
+ order_id: "shopify_" + .id,
90
+ customer_email: .customer.email,
91
+ total_amount: .total_price,
92
+ payment_status: match .financial_status {
93
+ "paid" => "captured",
94
+ "pending" => "pending",
95
+ "refunded" => "refunded",
96
+ _ => "unknown"
97
+ }
98
+ }
99
+ ```
100
+
101
+ **Temporal** (30+ lines):
102
+ ```typescript
103
+ function transformOrder(order: ShopifyOrder): UnifiedOrder {
104
+ const paymentStatusMap: Record<string, string> = {
105
+ paid: 'captured',
106
+ partially_paid: 'partial',
107
+ pending: 'pending',
108
+ refunded: 'refunded',
109
+ partially_refunded: 'partial_refund',
110
+ };
111
+
112
+ return {
113
+ order_id: `shopify_${order.id}`,
114
+ customer_email: order.customer?.email || '',
115
+ total_amount: parseFloat(order.total_price),
116
+ payment_status: paymentStatusMap[order.financial_status] || 'unknown',
117
+ // ... 10 more fields
118
+ };
119
+ }
120
+ ```
121
+
122
+ ### 4. Validation Rules
123
+
124
+ **Reqon** (5 lines):
125
+ ```vague
126
+ validate order {
127
+ assume payment_exists == true
128
+ } or {
129
+ store { type: "missing_payment", ... } -> discrepancies { ... }
130
+ }
131
+ ```
132
+
133
+ **Temporal** (50+ lines):
134
+ ```typescript
135
+ export async function validateOrdersHavePayments(
136
+ orders: UnifiedOrder[],
137
+ payments: UnifiedPayment[]
138
+ ): Promise<Discrepancy[]> {
139
+ const discrepancies: Discrepancy[] = [];
140
+ const paymentsByOrderId = new Map<string, UnifiedPayment[]>();
141
+
142
+ for (const payment of payments) {
143
+ const existing = paymentsByOrderId.get(payment.order_id) || [];
144
+ existing.push(payment);
145
+ paymentsByOrderId.set(payment.order_id, existing);
146
+ }
147
+
148
+ const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
149
+
150
+ for (const order of orders) {
151
+ if (order.payment_status === 'pending' && order.created_at < threeDaysAgo) {
152
+ const orderPayments = paymentsByOrderId.get(order.order_id);
153
+ if (!orderPayments || orderPayments.length === 0) {
154
+ discrepancies.push({
155
+ id: `disc_${order.order_id}_no_payment`,
156
+ // ... more fields
157
+ });
158
+ }
159
+ }
160
+ }
161
+ return discrepancies;
162
+ }
163
+ ```
164
+
165
+ ### 5. Pipeline Orchestration with Parallel Execution
166
+
167
+ **Reqon** (3 lines):
168
+ ```vague
169
+ // Fetch from all three APIs in parallel, then validate
170
+ run [SyncShopifyOrders, SyncStripePayments, SyncShipStationShipments]
171
+ then ValidateReconciliation
172
+ ```
173
+ Brackets indicate parallel execution - all three sync actions run concurrently for maximum performance.
174
+
175
+ **Temporal** (100+ lines):
176
+ ```typescript
177
+ export async function orderReconciliationWorkflow(): Promise<ReconciliationResult> {
178
+ // Initialize state, queries, signals...
179
+ setHandler(getStatusQuery, () => state);
180
+ setHandler(cancelSignal, () => { cancelled = true; });
181
+ setHandler(pauseSignal, () => { paused = true; });
182
+ setHandler(resumeSignal, () => { paused = false; });
183
+
184
+ try {
185
+ state.status = 'syncing_shopify';
186
+ await checkPauseAndCancel();
187
+ const shopifyLastSync = await storage.getCheckpoint('shopify_orders_last_sync');
188
+ const orders = await shopify.fetchAllShopifyOrders(shopifyLastSync);
189
+ state.ordersProcessed = await storage.upsertOrders(orders);
190
+ await storage.setCheckpoint('shopify_orders_last_sync', new Date().toISOString());
191
+
192
+ // Repeat for Stripe...
193
+ // Repeat for ShipStation...
194
+ // Validation step...
195
+ } catch (error) {
196
+ state.status = 'failed';
197
+ throw error;
198
+ }
199
+ }
200
+ ```
201
+
202
+ ### 6. Running the Pipeline
203
+
204
+ **Reqon**:
205
+ ```bash
206
+ # Run once
207
+ reqon reconciliation.vague --auth ./credentials.json
208
+
209
+ # Dry run
210
+ reqon reconciliation.vague --dry-run
211
+
212
+ # Resume from checkpoint
213
+ reqon reconciliation.vague --resume exec-abc123
214
+
215
+ # Schedule with cron
216
+ 0 2 * * * reqon reconciliation.vague
217
+ ```
218
+
219
+ **Temporal**:
220
+ ```bash
221
+ # 1. Start PostgreSQL
222
+ docker-compose up -d postgresql
223
+
224
+ # 2. Start Temporal Server
225
+ docker-compose up -d temporal temporal-ui
226
+
227
+ # 3. Wait for server to be ready
228
+ sleep 30
229
+
230
+ # 4. Start worker (in separate terminal)
231
+ npx ts-node src/workers/main.ts
232
+
233
+ # 5. Trigger workflow
234
+ npx ts-node src/client/schedule.ts run
235
+
236
+ # 6. (Optional) Create schedule
237
+ npx ts-node src/client/schedule.ts schedule
238
+ ```
239
+
240
+ ## When to Use Which
241
+
242
+ ### Use Reqon When:
243
+ - ✅ Your workflow is data synchronization / ETL
244
+ - ✅ You need to fetch, transform, validate, and store data
245
+ - ✅ You want minimal infrastructure
246
+ - ✅ Business users need to understand the pipeline
247
+ - ✅ You need quick iteration and prototyping
248
+ - ✅ The "happy path" is the main path
249
+ - ✅ Retry/backoff/rate-limiting are your main concerns
250
+
251
+ ### Use Temporal When:
252
+ - ⚡ You need human-in-the-loop workflows
253
+ - ⚡ You have complex branching/conditional logic
254
+ - ⚡ You need workflow versioning/migration
255
+ - ⚡ You need sub-second latency on signals
256
+ - ⚡ You're building microservice orchestration
257
+ - ⚡ You need the full power of a programming language
258
+ - ⚡ You already have Temporal infrastructure
259
+
260
+ ## Files
261
+
262
+ ### Reqon Solution
263
+ - `reconciliation.vague` - **The complete solution in ~280 lines**
264
+
265
+ ### Temporal Solution (11 files, ~1,500 lines)
266
+ ```
267
+ temporal/
268
+ ├── types/
269
+ │ └── index.ts # Type definitions (130 lines)
270
+ ├── config/
271
+ │ └── retry.ts # Retry configuration (50 lines)
272
+ ├── activities/
273
+ │ ├── index.ts # Activity exports
274
+ │ ├── shopify.ts # Shopify API (220 lines)
275
+ │ ├── stripe.ts # Stripe API (150 lines)
276
+ │ ├── shipstation.ts # ShipStation API (180 lines)
277
+ │ ├── validation.ts # Validation logic (180 lines)
278
+ │ └── storage.ts # Database operations (160 lines)
279
+ ├── workflows/
280
+ │ └── orderReconciliation.ts # Main workflow (200 lines)
281
+ ├── workers/
282
+ │ └── main.ts # Worker setup (100 lines)
283
+ └── client/
284
+ └── schedule.ts # Scheduler client (180 lines)
285
+ ```
286
+
287
+ ## The Bottom Line
288
+
289
+ For data synchronization pipelines, Reqon offers:
290
+
291
+ 1. **10x less code** - Focus on *what* you want, not *how* to do it
292
+ 2. **Zero infrastructure** - Run anywhere Node.js runs
293
+ 3. **Domain-specific** - Built specifically for fetch/transform/validate/store
294
+ 4. **Readable** - Business logic is visible, not buried in code
295
+ 5. **Batteries included** - Pagination, rate limiting, retries, checkpointing built-in
296
+
297
+ Temporal is a powerful general-purpose workflow engine, but for the specific domain of data pipelines, it's like using a chainsaw to cut butter. Reqon is purpose-built for this domain and shows in every aspect of the developer experience.
@@ -0,0 +1,355 @@
1
+ // E-Commerce Order Reconciliation Pipeline
2
+ // Syncs and validates orders across Shopify, Stripe, and ShipStation
3
+ // ~150 lines of declarative code vs ~1,500+ lines in Temporal
4
+
5
+ mission OrderReconciliation {
6
+
7
+ // ============================================================
8
+ // SOURCES - API definitions with auth and rate limiting
9
+ // ============================================================
10
+
11
+ source Shopify {
12
+ auth: oauth2,
13
+ base: "https://mystore.myshopify.com/admin/api/2024-01",
14
+ headers: { "X-Shopify-Access-Token": "${SHOPIFY_TOKEN}" },
15
+ rateLimit: {
16
+ strategy: "pause",
17
+ maxWait: 120,
18
+ fallbackRpm: 40
19
+ }
20
+ }
21
+
22
+ source Stripe {
23
+ auth: bearer,
24
+ base: "https://api.stripe.com/v1",
25
+ rateLimit: {
26
+ strategy: "throttle",
27
+ maxWait: 60,
28
+ fallbackRpm: 100
29
+ }
30
+ }
31
+
32
+ source ShipStation {
33
+ auth: basic,
34
+ base: "https://ssapi.shipstation.com",
35
+ rateLimit: {
36
+ strategy: "pause",
37
+ maxWait: 30,
38
+ fallbackRpm: 40
39
+ }
40
+ }
41
+
42
+ // ============================================================
43
+ // STORES - Where we persist reconciled data
44
+ // ============================================================
45
+
46
+ store orders: sql("reconciled_orders")
47
+ store payments: sql("reconciled_payments")
48
+ store shipments: sql("reconciled_shipments")
49
+ store discrepancies: sql("audit_discrepancies")
50
+ store sync_state: sql("sync_checkpoints")
51
+
52
+ // ============================================================
53
+ // SCHEMAS - Unified data models
54
+ // ============================================================
55
+
56
+ schema UnifiedOrder {
57
+ order_id: string,
58
+ external_id: string,
59
+ source: string,
60
+ customer_email: string,
61
+ total_amount: decimal,
62
+ currency: string,
63
+ status: string,
64
+ created_at: date,
65
+ line_items_count: int,
66
+ payment_status: string,
67
+ fulfillment_status: string,
68
+ synced_at: date
69
+ }
70
+
71
+ schema UnifiedPayment {
72
+ payment_id: string,
73
+ order_id: string,
74
+ amount: decimal,
75
+ currency: string,
76
+ status: string,
77
+ method: string,
78
+ captured_at: date,
79
+ refunded_amount: decimal
80
+ }
81
+
82
+ schema UnifiedShipment {
83
+ shipment_id: string,
84
+ order_id: string,
85
+ carrier: string,
86
+ tracking_number: string,
87
+ status: string,
88
+ shipped_at: date,
89
+ delivered_at: date
90
+ }
91
+
92
+ schema Discrepancy {
93
+ id: string,
94
+ order_id: string,
95
+ type: string,
96
+ severity: string,
97
+ description: string,
98
+ shopify_value: string,
99
+ stripe_value: string,
100
+ shipstation_value: string,
101
+ detected_at: date
102
+ }
103
+
104
+ // ============================================================
105
+ // ACTION: Sync Shopify Orders (with incremental sync)
106
+ // ============================================================
107
+
108
+ action SyncShopifyOrders {
109
+ // Get last sync timestamp for incremental sync
110
+ get "/orders.json" {
111
+ source: "Shopify",
112
+ body: {
113
+ "status": "any",
114
+ "updated_at_min": sync_state.get("shopify_orders_last_sync"),
115
+ "limit": 250
116
+ },
117
+ paginate: cursor(page_info, 250, "link.next"),
118
+ until: response.orders.length == 0,
119
+ retry: {
120
+ maxAttempts: 5,
121
+ backoff: "exponential",
122
+ initialDelay: 2000,
123
+ maxDelay: 60000
124
+ }
125
+ },
126
+
127
+ // Transform each order to unified schema
128
+ for order in response.orders {
129
+ map order -> UnifiedOrder {
130
+ order_id: "shopify_" + .id,
131
+ external_id: .id,
132
+ source: "shopify",
133
+ customer_email: .customer.email,
134
+ total_amount: .total_price,
135
+ currency: .currency,
136
+ status: .status,
137
+ created_at: .created_at,
138
+ line_items_count: length(.line_items),
139
+ payment_status: match .financial_status {
140
+ "paid" => "captured",
141
+ "partially_paid" => "partial",
142
+ "pending" => "pending",
143
+ "refunded" => "refunded",
144
+ "partially_refunded" => "partial_refund",
145
+ _ => "unknown"
146
+ },
147
+ fulfillment_status: match .fulfillment_status {
148
+ "fulfilled" => "shipped",
149
+ "partial" => "partial",
150
+ null => "unfulfilled",
151
+ _ => .fulfillment_status
152
+ },
153
+ synced_at: now()
154
+ },
155
+
156
+ store response -> orders { key: .order_id, upsert: true }
157
+ },
158
+
159
+ // Update checkpoint
160
+ store { "shopify_orders_last_sync": now() } -> sync_state { key: "shopify_orders_last_sync" }
161
+ }
162
+
163
+ // ============================================================
164
+ // ACTION: Sync Stripe Payments
165
+ // ============================================================
166
+
167
+ action SyncStripePayments {
168
+ get "/payment_intents" {
169
+ source: "Stripe",
170
+ body: {
171
+ "limit": 100,
172
+ "created[gte]": sync_state.get("stripe_payments_last_sync"),
173
+ "expand[]": "data.charges"
174
+ },
175
+ paginate: cursor(starting_after, 100, "data[-1].id"),
176
+ until: response.has_more == false,
177
+ retry: {
178
+ maxAttempts: 3,
179
+ backoff: "exponential",
180
+ initialDelay: 1000
181
+ }
182
+ },
183
+
184
+ for payment in response.data where .metadata.shopify_order_id != null {
185
+ map payment -> UnifiedPayment {
186
+ payment_id: "stripe_" + .id,
187
+ order_id: "shopify_" + .metadata.shopify_order_id,
188
+ amount: .amount / 100, // Stripe uses cents
189
+ currency: .currency,
190
+ status: match .status {
191
+ "succeeded" => "captured",
192
+ "requires_capture" => "authorized",
193
+ "canceled" => "voided",
194
+ _ => .status
195
+ },
196
+ method: .payment_method_types[0],
197
+ captured_at: .charges.data[0].created,
198
+ refunded_amount: .charges.data[0].amount_refunded / 100
199
+ },
200
+
201
+ store response -> payments { key: .payment_id, upsert: true }
202
+ },
203
+
204
+ store { "stripe_payments_last_sync": now() } -> sync_state { key: "stripe_payments_last_sync" }
205
+ }
206
+
207
+ // ============================================================
208
+ // ACTION: Sync ShipStation Shipments
209
+ // ============================================================
210
+
211
+ action SyncShipStationShipments {
212
+ get "/shipments" {
213
+ source: "ShipStation",
214
+ body: {
215
+ "pageSize": 500,
216
+ "createDateStart": sync_state.get("shipstation_last_sync"),
217
+ "sortBy": "CreateDate"
218
+ },
219
+ paginate: page(page, 500),
220
+ until: response.shipments.length == 0,
221
+ retry: {
222
+ maxAttempts: 4,
223
+ backoff: "exponential",
224
+ initialDelay: 3000
225
+ }
226
+ },
227
+
228
+ for shipment in response.shipments {
229
+ map shipment -> UnifiedShipment {
230
+ shipment_id: "ss_" + .shipmentId,
231
+ order_id: "shopify_" + .orderNumber,
232
+ carrier: .carrierCode,
233
+ tracking_number: .trackingNumber,
234
+ status: match .voided {
235
+ true => "voided",
236
+ _ => match .trackingNumber {
237
+ null => "label_created",
238
+ _ => "shipped"
239
+ }
240
+ },
241
+ shipped_at: .shipDate,
242
+ delivered_at: .deliveryDate
243
+ },
244
+
245
+ store response -> shipments { key: .shipment_id, upsert: true }
246
+ },
247
+
248
+ store { "shipstation_last_sync": now() } -> sync_state { key: "shipstation_last_sync" }
249
+ }
250
+
251
+ // ============================================================
252
+ // ACTION: Cross-Reference and Validate
253
+ // ============================================================
254
+
255
+ action ValidateReconciliation {
256
+ // Check for orders without payments
257
+ for order in orders where .payment_status == "pending" and .created_at < now() - days(3) {
258
+ let payment_exists = any of payments where .order_id == order.order_id,
259
+
260
+ validate order {
261
+ assume payment_exists == true
262
+ } or {
263
+ store {
264
+ id: "disc_" + order.order_id + "_no_payment",
265
+ order_id: order.order_id,
266
+ type: "missing_payment",
267
+ severity: "high",
268
+ description: "Order older than 3 days has no matching Stripe payment",
269
+ shopify_value: order.total_amount,
270
+ stripe_value: null,
271
+ shipstation_value: null,
272
+ detected_at: now()
273
+ } -> discrepancies { key: .id, upsert: true }
274
+ }
275
+ },
276
+
277
+ // Check for payment/order amount mismatches
278
+ for order in orders {
279
+ let matching_payments = payments where .order_id == order.order_id,
280
+ let total_paid = sum(matching_payments.amount),
281
+
282
+ validate order {
283
+ assume total_paid >= order.total_amount - 0.01,
284
+ assume total_paid <= order.total_amount + 0.01
285
+ } or {
286
+ store {
287
+ id: "disc_" + order.order_id + "_amount_mismatch",
288
+ order_id: order.order_id,
289
+ type: "amount_mismatch",
290
+ severity: match abs(order.total_amount - total_paid) {
291
+ x where x > 100 => "critical",
292
+ x where x > 10 => "high",
293
+ _ => "medium"
294
+ },
295
+ description: "Order total does not match payment total",
296
+ shopify_value: order.total_amount,
297
+ stripe_value: total_paid,
298
+ shipstation_value: null,
299
+ detected_at: now()
300
+ } -> discrepancies { key: .id, upsert: true }
301
+ }
302
+ },
303
+
304
+ // Check for shipped orders without shipment records
305
+ for order in orders where .fulfillment_status == "shipped" {
306
+ let shipment_exists = any of shipments where .order_id == order.order_id,
307
+
308
+ validate order {
309
+ assume shipment_exists == true
310
+ } or {
311
+ store {
312
+ id: "disc_" + order.order_id + "_no_shipment",
313
+ order_id: order.order_id,
314
+ type: "missing_shipment_record",
315
+ severity: "medium",
316
+ description: "Shopify shows fulfilled but no ShipStation shipment found",
317
+ shopify_value: order.fulfillment_status,
318
+ stripe_value: null,
319
+ shipstation_value: null,
320
+ detected_at: now()
321
+ } -> discrepancies { key: .id, upsert: true }
322
+ }
323
+ },
324
+
325
+ // Check for refund discrepancies
326
+ for payment in payments where .refunded_amount > 0 {
327
+ let order = first(orders where .order_id == payment.order_id),
328
+
329
+ validate payment {
330
+ assume order.payment_status == "refunded" or order.payment_status == "partial_refund"
331
+ } or {
332
+ store {
333
+ id: "disc_" + payment.order_id + "_refund_mismatch",
334
+ order_id: payment.order_id,
335
+ type: "refund_status_mismatch",
336
+ severity: "high",
337
+ description: "Stripe shows refund but Shopify payment status not updated",
338
+ shopify_value: order.payment_status,
339
+ stripe_value: payment.refunded_amount,
340
+ shipstation_value: null,
341
+ detected_at: now()
342
+ } -> discrepancies { key: .id, upsert: true }
343
+ }
344
+ }
345
+ }
346
+
347
+ // ============================================================
348
+ // PIPELINE: Parallel fetch, then sequential validation
349
+ // ============================================================
350
+
351
+ // Fetch from all three APIs in parallel for maximum performance
352
+ // ValidateReconciliation runs after all three complete
353
+ run [SyncShopifyOrders, SyncStripePayments, SyncShipStationShipments]
354
+ then ValidateReconciliation
355
+ }
@@ -0,0 +1,8 @@
1
+ // Activity exports
2
+ // Aggregate all activities for worker registration
3
+
4
+ export * from './shopify';
5
+ export * from './stripe';
6
+ export * from './shipstation';
7
+ export * from './validation';
8
+ export * from './storage';