@effect-app/infra 4.0.0-beta.99 → 4.0.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 (486) hide show
  1. package/CHANGELOG.md +2884 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +28 -9
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +35 -14
  6. package/dist/ClusterCosmos.d.ts +67 -0
  7. package/dist/ClusterCosmos.d.ts.map +1 -0
  8. package/dist/ClusterCosmos.js +588 -0
  9. package/dist/ClusterServiceBus.d.ts +67 -0
  10. package/dist/ClusterServiceBus.d.ts.map +1 -0
  11. package/dist/ClusterServiceBus.js +84 -0
  12. package/dist/{api/ContextProvider.d.ts → ContextProvider.d.ts} +7 -4
  13. package/dist/ContextProvider.d.ts.map +1 -0
  14. package/dist/ContextProvider.js +40 -0
  15. package/dist/Emailer/Sendgrid.d.ts +110 -146
  16. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  17. package/dist/Emailer/Sendgrid.js +24 -19
  18. package/dist/Emailer/fake.d.ts +1 -1
  19. package/dist/Emailer/fake.d.ts.map +1 -1
  20. package/dist/Emailer/fake.js +4 -4
  21. package/dist/MainFiberSet.d.ts +11 -7
  22. package/dist/MainFiberSet.d.ts.map +1 -1
  23. package/dist/MainFiberSet.js +22 -6
  24. package/dist/QueueMaker/errors.d.ts +3 -1
  25. package/dist/QueueMaker/errors.d.ts.map +1 -1
  26. package/dist/QueueMaker/errors.js +4 -2
  27. package/dist/{adapters/SQL → SQL}/Model.d.ts +34 -45
  28. package/dist/SQL/Model.d.ts.map +1 -0
  29. package/dist/SQL/Model.js +469 -0
  30. package/dist/SQL.d.ts.map +1 -0
  31. package/dist/{adapters/SQL.js → SQL.js} +1 -1
  32. package/dist/Store/Cosmos/query.d.ts +16 -4
  33. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  34. package/dist/Store/Cosmos/query.js +238 -42
  35. package/dist/Store/Cosmos.d.ts +2 -2
  36. package/dist/Store/Cosmos.d.ts.map +1 -1
  37. package/dist/Store/Cosmos.js +394 -319
  38. package/dist/Store/Disk.d.ts +4 -4
  39. package/dist/Store/Disk.d.ts.map +1 -1
  40. package/dist/Store/Disk.js +91 -39
  41. package/dist/Store/Memory.d.ts +7 -10
  42. package/dist/Store/Memory.d.ts.map +1 -1
  43. package/dist/Store/Memory.js +348 -78
  44. package/dist/Store/SQL/Pg.d.ts +2 -2
  45. package/dist/Store/SQL/Pg.d.ts.map +1 -1
  46. package/dist/Store/SQL/Pg.js +229 -154
  47. package/dist/Store/SQL/query.d.ts +19 -3
  48. package/dist/Store/SQL/query.d.ts.map +1 -1
  49. package/dist/Store/SQL/query.js +306 -12
  50. package/dist/Store/SQL.d.ts +22 -5
  51. package/dist/Store/SQL.d.ts.map +1 -1
  52. package/dist/Store/SQL.js +369 -98
  53. package/dist/Store/codeFilter.d.ts +4 -4
  54. package/dist/Store/codeFilter.d.ts.map +1 -1
  55. package/dist/Store/codeFilter.js +71 -22
  56. package/dist/Store/index.d.ts +6 -4
  57. package/dist/Store/index.d.ts.map +1 -1
  58. package/dist/Store/index.js +9 -6
  59. package/dist/Store/jsonDocument.d.ts +67 -0
  60. package/dist/Store/jsonDocument.d.ts.map +1 -0
  61. package/dist/Store/jsonDocument.js +107 -0
  62. package/dist/Store/utils.d.ts +21 -2
  63. package/dist/Store/utils.d.ts.map +1 -1
  64. package/dist/Store/utils.js +253 -10
  65. package/dist/WorkflowEngineCosmos.d.ts +30 -0
  66. package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
  67. package/dist/WorkflowEngineCosmos.js +542 -0
  68. package/dist/WorkflowEngineSqlite.d.ts +24 -0
  69. package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
  70. package/dist/WorkflowEngineSqlite.js +550 -0
  71. package/dist/arbs.d.ts +6 -3
  72. package/dist/arbs.d.ts.map +1 -1
  73. package/dist/arbs.js +20 -4
  74. package/dist/codec.d.ts.map +1 -0
  75. package/dist/codec.js +5 -0
  76. package/dist/cosmos-client.d.ts +40 -0
  77. package/dist/cosmos-client.d.ts.map +1 -0
  78. package/dist/cosmos-client.js +41 -0
  79. package/dist/errorReporter.d.ts +6 -4
  80. package/dist/errorReporter.d.ts.map +1 -1
  81. package/dist/errorReporter.js +23 -27
  82. package/dist/fileUtil.d.ts +1 -1
  83. package/dist/fileUtil.d.ts.map +1 -1
  84. package/dist/fileUtil.js +2 -2
  85. package/dist/index.d.ts +2 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +3 -2
  88. package/dist/internal/RequestContextMiddleware.d.ts +5 -0
  89. package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
  90. package/dist/internal/RequestContextMiddleware.js +45 -0
  91. package/dist/internal/auth.d.ts +53 -0
  92. package/dist/internal/auth.d.ts.map +1 -0
  93. package/dist/internal/auth.js +180 -0
  94. package/dist/internal/events.d.ts +11 -0
  95. package/dist/internal/events.d.ts.map +1 -0
  96. package/dist/internal/events.js +49 -0
  97. package/dist/{api/internal → internal}/health.d.ts +1 -1
  98. package/dist/internal/health.d.ts.map +1 -0
  99. package/dist/internal/health.js +5 -0
  100. package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +10 -2
  101. package/dist/layerUtils.d.ts.map +1 -0
  102. package/dist/layerUtils.js +17 -0
  103. package/dist/logger/jsonLogger.d.ts +1 -1
  104. package/dist/logger/jsonLogger.d.ts.map +1 -1
  105. package/dist/logger/jsonLogger.js +5 -3
  106. package/dist/logger/logFmtLogger.d.ts +1 -1
  107. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  108. package/dist/logger/logFmtLogger.js +3 -3
  109. package/dist/logger/shared.d.ts +2 -2
  110. package/dist/logger/shared.d.ts.map +1 -1
  111. package/dist/logger/shared.js +6 -6
  112. package/dist/logger.d.ts.map +1 -1
  113. package/dist/middlewares.d.ts.map +1 -0
  114. package/dist/{api/middlewares.js → middlewares.js} +1 -1
  115. package/dist/{adapters/mongo-client.d.ts → mongo-client.d.ts} +2 -1
  116. package/dist/mongo-client.d.ts.map +1 -0
  117. package/dist/mongo-client.js +15 -0
  118. package/dist/otel.d.ts +75 -0
  119. package/dist/otel.d.ts.map +1 -0
  120. package/dist/otel.js +84 -0
  121. package/dist/rateLimit.d.ts +11 -3
  122. package/dist/rateLimit.d.ts.map +1 -1
  123. package/dist/rateLimit.js +7 -12
  124. package/dist/{adapters/redis-client.d.ts → redis-client.d.ts} +4 -1
  125. package/dist/redis-client.d.ts.map +1 -0
  126. package/dist/redis-client.js +98 -0
  127. package/dist/{api/reportError.d.ts → reportError.d.ts} +1 -1
  128. package/dist/reportError.d.ts.map +1 -0
  129. package/dist/reportError.js +28 -0
  130. package/dist/{api/routing → routing}/middleware/RouterMiddleware.d.ts +2 -1
  131. package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
  132. package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
  133. package/dist/{api/routing → routing}/middleware/middleware.d.ts +11 -6
  134. package/dist/routing/middleware/middleware.d.ts.map +1 -0
  135. package/dist/routing/middleware/middleware.js +152 -0
  136. package/dist/{api/routing → routing}/middleware.d.ts +0 -1
  137. package/dist/routing/middleware.d.ts.map +1 -0
  138. package/dist/{api/routing → routing}/middleware.js +1 -2
  139. package/dist/routing/schema/jwt.d.ts.map +1 -0
  140. package/dist/routing/schema/jwt.js +12 -0
  141. package/dist/routing/tsort.d.ts.map +1 -0
  142. package/dist/routing/tsort.js +51 -0
  143. package/dist/{api/routing → routing}/utils.d.ts +3 -3
  144. package/dist/routing/utils.d.ts.map +1 -0
  145. package/dist/routing/utils.js +45 -0
  146. package/dist/routing.d.ts +182 -0
  147. package/dist/routing.d.ts.map +1 -0
  148. package/dist/routing.js +256 -0
  149. package/dist/test.d.ts +2 -2
  150. package/dist/test.d.ts.map +1 -1
  151. package/dist/test.js +5 -5
  152. package/dist/util.d.ts.map +1 -0
  153. package/dist/util.js +14 -0
  154. package/docs/cluster-storage.md +26 -0
  155. package/docs/workflow-engine.md +262 -0
  156. package/examples/query.ts +23 -19
  157. package/package.json +36 -364
  158. package/src/CUPS.ts +53 -14
  159. package/src/ClusterCosmos.ts +1170 -0
  160. package/src/ClusterServiceBus.ts +244 -0
  161. package/src/{api/ContextProvider.ts → ContextProvider.ts} +10 -7
  162. package/src/Emailer/Sendgrid.ts +83 -60
  163. package/src/Emailer/fake.ts +4 -4
  164. package/src/MainFiberSet.ts +31 -12
  165. package/src/QueueMaker/errors.ts +3 -1
  166. package/src/{adapters/SQL → SQL}/Model.ts +48 -47
  167. package/src/SQL.ts +1 -0
  168. package/src/Store/Cosmos/query.ts +275 -55
  169. package/src/Store/Cosmos.ts +597 -511
  170. package/src/Store/Disk.ts +145 -71
  171. package/src/Store/Memory.ts +420 -115
  172. package/src/Store/SQL/Pg.ts +352 -268
  173. package/src/Store/SQL/query.ts +366 -20
  174. package/src/Store/SQL.ts +742 -293
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +18 -13
  177. package/src/Store/jsonDocument.ts +143 -0
  178. package/src/Store/utils.ts +307 -30
  179. package/src/WorkflowEngineCosmos.ts +749 -0
  180. package/src/WorkflowEngineSqlite.ts +813 -0
  181. package/src/arbs.ts +25 -5
  182. package/src/cosmos-client.ts +72 -0
  183. package/src/errorReporter.ts +68 -78
  184. package/src/fileUtil.ts +1 -1
  185. package/src/index.ts +2 -1
  186. package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
  187. package/src/internal/auth.ts +272 -0
  188. package/src/{api/internal → internal}/events.ts +18 -9
  189. package/src/{api/layerUtils.ts → layerUtils.ts} +7 -3
  190. package/src/logger/jsonLogger.ts +5 -3
  191. package/src/logger/logFmtLogger.ts +3 -3
  192. package/src/logger/shared.ts +6 -5
  193. package/src/middlewares.ts +10 -0
  194. package/src/{adapters/mongo-client.ts → mongo-client.ts} +3 -1
  195. package/src/otel.ts +177 -0
  196. package/src/rateLimit.ts +35 -24
  197. package/src/{adapters/redis-client.ts → redis-client.ts} +6 -2
  198. package/src/{api/reportError.ts → reportError.ts} +3 -2
  199. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +2 -1
  200. package/src/{api/routing → routing}/middleware/middleware.ts +75 -50
  201. package/src/routing/middleware.ts +4 -0
  202. package/src/{api/routing → routing}/schema/jwt.ts +2 -2
  203. package/src/{api/routing → routing}/utils.ts +2 -1
  204. package/src/routing.ts +823 -0
  205. package/src/test.ts +6 -6
  206. package/src/vitest.ts +1 -1
  207. package/test/arbs-magnitude.test.ts +33 -0
  208. package/test/arbs.test.ts +41 -0
  209. package/test/auth.test.ts +101 -0
  210. package/test/cluster-cosmos.test.ts +634 -0
  211. package/test/cluster-servicebus.test.ts +180 -0
  212. package/test/cluster-sqlite.test.ts +207 -0
  213. package/test/contextProvider.test.ts +11 -8
  214. package/test/controller.test.ts +23 -28
  215. package/test/cosmos-container-throughput.test.ts +80 -0
  216. package/test/cosmos-query.test.ts +368 -0
  217. package/test/dist/arbs-magnitude.test.d.ts.map +1 -0
  218. package/test/dist/arbs.test.d.ts.map +1 -0
  219. package/test/dist/auth.test.d.ts.map +1 -0
  220. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  221. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  222. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  223. package/test/dist/contextProvider.test.d.ts.map +1 -1
  224. package/test/dist/controller.test.d.ts.map +1 -1
  225. package/test/dist/cosmos-container-throughput.test.d.ts.map +1 -0
  226. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  227. package/test/dist/fixtures.d.ts +17 -9
  228. package/test/dist/fixtures.d.ts.map +1 -1
  229. package/test/dist/fixtures.js +8 -3
  230. package/test/dist/json-lower.test.d.ts.map +1 -0
  231. package/test/dist/query.test.d.ts.map +1 -1
  232. package/test/dist/rawQuery.test.d.ts.map +1 -1
  233. package/test/dist/repository-ext.test.d.ts.map +1 -0
  234. package/test/dist/repository-legacy-document.test.d.ts.map +1 -0
  235. package/test/dist/requires.test.d.ts.map +1 -1
  236. package/test/dist/router-generator.test.d.ts.map +1 -0
  237. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  238. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  239. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  240. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  241. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  242. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  243. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  244. package/test/fixtures.ts +7 -2
  245. package/test/json-lower.test.ts +129 -0
  246. package/test/layerUtils.test.ts +2 -2
  247. package/test/query.test.ts +1232 -42
  248. package/test/rawQuery.test.ts +432 -7
  249. package/test/repository-ext.test.ts +456 -0
  250. package/test/repository-legacy-document.test.ts +394 -0
  251. package/test/requires.test.ts +7 -3
  252. package/test/router-generator.test.ts +187 -0
  253. package/test/routing-interruptibility.test.ts +66 -0
  254. package/test/rpc-context-map-streaming.test.ts +265 -0
  255. package/test/rpc-e2e-invalidation.test.ts +421 -0
  256. package/test/rpc-multi-middleware.test.ts +17 -11
  257. package/test/rpc-stream-fullstack.test.ts +307 -0
  258. package/test/sql-store.test.ts +1202 -47
  259. package/test/validateSample.test.ts +70 -42
  260. package/test/workflow-engine-cosmos.test.ts +345 -0
  261. package/test/workflow-engine-sqlite.test.ts +297 -0
  262. package/tsconfig.examples.json +1 -1
  263. package/tsconfig.json +9 -1
  264. package/tsconfig.src.json +35 -35
  265. package/tsconfig.test.json +2 -2
  266. package/dist/Emailer/service.d.ts +0 -55
  267. package/dist/Emailer/service.d.ts.map +0 -1
  268. package/dist/Emailer/service.js +0 -6
  269. package/dist/Emailer.d.ts +0 -2
  270. package/dist/Emailer.d.ts.map +0 -1
  271. package/dist/Emailer.js +0 -2
  272. package/dist/Model/Repository/ext.d.ts +0 -41
  273. package/dist/Model/Repository/ext.d.ts.map +0 -1
  274. package/dist/Model/Repository/ext.js +0 -65
  275. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  276. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  277. package/dist/Model/Repository/internal/internal.js +0 -320
  278. package/dist/Model/Repository/legacy.d.ts +0 -19
  279. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  280. package/dist/Model/Repository/legacy.js +0 -2
  281. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  282. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  283. package/dist/Model/Repository/makeRepo.js +0 -24
  284. package/dist/Model/Repository/service.d.ts +0 -89
  285. package/dist/Model/Repository/service.d.ts.map +0 -1
  286. package/dist/Model/Repository/service.js +0 -2
  287. package/dist/Model/Repository/validation.d.ts +0 -43
  288. package/dist/Model/Repository/validation.d.ts.map +0 -1
  289. package/dist/Model/Repository/validation.js +0 -32
  290. package/dist/Model/Repository.d.ts +0 -6
  291. package/dist/Model/Repository.d.ts.map +0 -1
  292. package/dist/Model/Repository.js +0 -6
  293. package/dist/Model/dsl.d.ts +0 -32
  294. package/dist/Model/dsl.d.ts.map +0 -1
  295. package/dist/Model/dsl.js +0 -44
  296. package/dist/Model/filter/filterApi.d.ts +0 -30
  297. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  298. package/dist/Model/filter/filterApi.js +0 -2
  299. package/dist/Model/filter/types/errors.d.ts +0 -29
  300. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  301. package/dist/Model/filter/types/errors.js +0 -2
  302. package/dist/Model/filter/types/fields.d.ts +0 -15
  303. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  304. package/dist/Model/filter/types/fields.js +0 -2
  305. package/dist/Model/filter/types/path/common.d.ts +0 -316
  306. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  307. package/dist/Model/filter/types/path/common.js +0 -2
  308. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  309. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  310. package/dist/Model/filter/types/path/eager.js +0 -31
  311. package/dist/Model/filter/types/path/index.d.ts +0 -4
  312. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  313. package/dist/Model/filter/types/path/index.js +0 -3
  314. package/dist/Model/filter/types/utils.d.ts +0 -79
  315. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  316. package/dist/Model/filter/types/utils.js +0 -2
  317. package/dist/Model/filter/types/validator.d.ts +0 -30
  318. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  319. package/dist/Model/filter/types/validator.js +0 -2
  320. package/dist/Model/filter/types.d.ts +0 -5
  321. package/dist/Model/filter/types.d.ts.map +0 -1
  322. package/dist/Model/filter/types.js +0 -7
  323. package/dist/Model/query/dsl.d.ts +0 -248
  324. package/dist/Model/query/dsl.d.ts.map +0 -1
  325. package/dist/Model/query/dsl.js +0 -104
  326. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  327. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  328. package/dist/Model/query/new-kid-interpreter.js +0 -165
  329. package/dist/Model/query.d.ts +0 -15
  330. package/dist/Model/query.d.ts.map +0 -1
  331. package/dist/Model/query.js +0 -3
  332. package/dist/Model.d.ts +0 -4
  333. package/dist/Model.d.ts.map +0 -1
  334. package/dist/Model.js +0 -4
  335. package/dist/Operations.d.ts +0 -55
  336. package/dist/Operations.d.ts.map +0 -1
  337. package/dist/Operations.js +0 -102
  338. package/dist/OperationsRepo.d.ts +0 -41
  339. package/dist/OperationsRepo.d.ts.map +0 -1
  340. package/dist/OperationsRepo.js +0 -14
  341. package/dist/QueueMaker/SQLQueue.d.ts +0 -14
  342. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  343. package/dist/QueueMaker/SQLQueue.js +0 -132
  344. package/dist/QueueMaker/memQueue.d.ts +0 -11
  345. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  346. package/dist/QueueMaker/memQueue.js +0 -76
  347. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  348. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  349. package/dist/QueueMaker/sbqueue.js +0 -91
  350. package/dist/QueueMaker/service.d.ts +0 -11
  351. package/dist/QueueMaker/service.d.ts.map +0 -1
  352. package/dist/QueueMaker/service.js +0 -4
  353. package/dist/RequestContext.d.ts +0 -68
  354. package/dist/RequestContext.d.ts.map +0 -1
  355. package/dist/RequestContext.js +0 -49
  356. package/dist/RequestFiberSet.d.ts +0 -36
  357. package/dist/RequestFiberSet.d.ts.map +0 -1
  358. package/dist/RequestFiberSet.js +0 -78
  359. package/dist/Store/ContextMapContainer.d.ts +0 -25
  360. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  361. package/dist/Store/ContextMapContainer.js +0 -77
  362. package/dist/Store/service.d.ts +0 -111
  363. package/dist/Store/service.d.ts.map +0 -1
  364. package/dist/Store/service.js +0 -79
  365. package/dist/Store.d.ts +0 -2
  366. package/dist/Store.d.ts.map +0 -1
  367. package/dist/Store.js +0 -2
  368. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  369. package/dist/adapters/SQL/Model.js +0 -478
  370. package/dist/adapters/SQL.d.ts.map +0 -1
  371. package/dist/adapters/ServiceBus.d.ts +0 -58
  372. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  373. package/dist/adapters/ServiceBus.js +0 -99
  374. package/dist/adapters/cosmos-client.d.ts +0 -14
  375. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  376. package/dist/adapters/cosmos-client.js +0 -9
  377. package/dist/adapters/index.d.ts +0 -2
  378. package/dist/adapters/index.d.ts.map +0 -1
  379. package/dist/adapters/index.js +0 -2
  380. package/dist/adapters/logger.d.ts +0 -9
  381. package/dist/adapters/logger.d.ts.map +0 -1
  382. package/dist/adapters/logger.js +0 -3
  383. package/dist/adapters/memQueue.d.ts +0 -13
  384. package/dist/adapters/memQueue.d.ts.map +0 -1
  385. package/dist/adapters/memQueue.js +0 -20
  386. package/dist/adapters/mongo-client.d.ts.map +0 -1
  387. package/dist/adapters/mongo-client.js +0 -13
  388. package/dist/adapters/redis-client.d.ts.map +0 -1
  389. package/dist/adapters/redis-client.js +0 -94
  390. package/dist/api/ContextProvider.d.ts.map +0 -1
  391. package/dist/api/ContextProvider.js +0 -38
  392. package/dist/api/codec.d.ts.map +0 -1
  393. package/dist/api/codec.js +0 -5
  394. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  395. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  396. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  397. package/dist/api/internal/auth.d.ts +0 -15
  398. package/dist/api/internal/auth.d.ts.map +0 -1
  399. package/dist/api/internal/auth.js +0 -47
  400. package/dist/api/internal/events.d.ts +0 -9
  401. package/dist/api/internal/events.d.ts.map +0 -1
  402. package/dist/api/internal/events.js +0 -42
  403. package/dist/api/internal/health.d.ts.map +0 -1
  404. package/dist/api/internal/health.js +0 -5
  405. package/dist/api/layerUtils.d.ts.map +0 -1
  406. package/dist/api/layerUtils.js +0 -16
  407. package/dist/api/middlewares.d.ts.map +0 -1
  408. package/dist/api/reportError.d.ts.map +0 -1
  409. package/dist/api/reportError.js +0 -27
  410. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  411. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  412. package/dist/api/routing/middleware/middleware.js +0 -130
  413. package/dist/api/routing/middleware.d.ts.map +0 -1
  414. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  415. package/dist/api/routing/schema/jwt.js +0 -12
  416. package/dist/api/routing/tsort.d.ts.map +0 -1
  417. package/dist/api/routing/tsort.js +0 -51
  418. package/dist/api/routing/utils.d.ts.map +0 -1
  419. package/dist/api/routing/utils.js +0 -44
  420. package/dist/api/routing.d.ts +0 -134
  421. package/dist/api/routing.d.ts.map +0 -1
  422. package/dist/api/routing.js +0 -167
  423. package/dist/api/setupRequest.d.ts +0 -15
  424. package/dist/api/setupRequest.d.ts.map +0 -1
  425. package/dist/api/setupRequest.js +0 -49
  426. package/dist/api/util.d.ts.map +0 -1
  427. package/dist/api/util.js +0 -14
  428. package/eslint.config.mjs +0 -24
  429. package/src/Emailer/service.ts +0 -52
  430. package/src/Emailer.ts +0 -1
  431. package/src/Model/Repository/ext.ts +0 -283
  432. package/src/Model/Repository/internal/internal.ts +0 -580
  433. package/src/Model/Repository/legacy.ts +0 -27
  434. package/src/Model/Repository/makeRepo.ts +0 -139
  435. package/src/Model/Repository/service.ts +0 -627
  436. package/src/Model/Repository/validation.ts +0 -31
  437. package/src/Model/Repository.ts +0 -5
  438. package/src/Model/dsl.ts +0 -128
  439. package/src/Model/filter/filterApi.ts +0 -60
  440. package/src/Model/filter/types/errors.ts +0 -47
  441. package/src/Model/filter/types/fields.ts +0 -50
  442. package/src/Model/filter/types/path/common.ts +0 -404
  443. package/src/Model/filter/types/path/eager.ts +0 -298
  444. package/src/Model/filter/types/path/index.ts +0 -4
  445. package/src/Model/filter/types/utils.ts +0 -128
  446. package/src/Model/filter/types/validator.ts +0 -46
  447. package/src/Model/filter/types.ts +0 -6
  448. package/src/Model/query/dsl.ts +0 -2110
  449. package/src/Model/query/new-kid-interpreter.ts +0 -210
  450. package/src/Model/query.ts +0 -13
  451. package/src/Model.ts +0 -3
  452. package/src/Operations.ts +0 -235
  453. package/src/OperationsRepo.ts +0 -16
  454. package/src/QueueMaker/SQLQueue.ts +0 -190
  455. package/src/QueueMaker/memQueue.ts +0 -130
  456. package/src/QueueMaker/sbqueue.ts +0 -137
  457. package/src/QueueMaker/service.ts +0 -17
  458. package/src/RequestContext.ts +0 -63
  459. package/src/RequestFiberSet.ts +0 -105
  460. package/src/Store/ContextMapContainer.ts +0 -116
  461. package/src/Store/index.test.ts.bak +0 -112
  462. package/src/Store/service.ts +0 -193
  463. package/src/Store.ts +0 -1
  464. package/src/adapters/SQL.ts +0 -1
  465. package/src/adapters/ServiceBus.ts +0 -209
  466. package/src/adapters/cosmos-client.ts +0 -16
  467. package/src/adapters/index.ts +0 -0
  468. package/src/adapters/logger.ts +0 -3
  469. package/src/adapters/memQueue.ts +0 -21
  470. package/src/api/internal/auth.ts +0 -68
  471. package/src/api/middlewares.ts +0 -10
  472. package/src/api/routing/middleware.ts +0 -6
  473. package/src/api/routing.ts +0 -598
  474. package/src/api/setupRequest.ts +0 -104
  475. package/test/dist/date-query.test.d.ts.map +0 -1
  476. package/tsconfig.json.bak +0 -12
  477. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  478. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  479. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  480. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  481. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  482. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  483. /package/src/{api/codec.ts → codec.ts} +0 -0
  484. /package/src/{api/internal → internal}/health.ts +0 -0
  485. /package/src/{api/routing → routing}/tsort.ts +0 -0
  486. /package/src/{api/util.ts → util.ts} +0 -0
@@ -1,9 +1,15 @@
1
- import { Effect, S } from "effect-app"
1
+ import * as Effect from "effect-app/Effect"
2
+ import * as Layer from "effect-app/Layer"
3
+ import { makeRepo, ValidationError, ValidationResult } from "effect-app/Model/Repository"
4
+ import { RepositoryRegistryLive } from "effect-app/Model/Repository/Registry"
5
+ import * as S from "effect-app/Schema"
6
+ import { setupRequestContextFromCurrent } from "effect-app/setupRequest"
7
+ import type { JsonRecord } from "effect-app/Store"
2
8
  import { describe, expect, it } from "vitest"
3
- import { setupRequestContextFromCurrent } from "../src/api/setupRequest.js"
4
- import { makeRepo, ValidationError, ValidationResult } from "../src/Model/Repository.js"
5
9
  import { MemoryStoreLive } from "../src/Store/Memory.js"
6
10
 
11
+ const TestStoreLive = Layer.merge(MemoryStoreLive, RepositoryRegistryLive)
12
+
7
13
  // simple schema for valid items
8
14
  class SimpleItem extends S.Class<SimpleItem>("SimpleItem")({
9
15
  id: S.String,
@@ -11,6 +17,26 @@ class SimpleItem extends S.Class<SimpleItem>("SimpleItem")({
11
17
  count: S.NonNegativeInt
12
18
  }) {}
13
19
 
20
+ /**
21
+ * `count` is stored as a *string*, so its Encoded shape accepts anything the
22
+ * JSON document happens to hold while the domain decode still demands a finite
23
+ * number.
24
+ *
25
+ * That split is what `validateSample` exists for, and it is the only way to
26
+ * observe a repository-level validation error now that `jitM` runs at the store
27
+ * boundary: the store's `toCodecJson(toEncoded(schema))` decode is strict, so a
28
+ * `jitM` that produced a value the *Encoded* shape rejects would fail loudly in
29
+ * the store instead of ever reaching the repository.
30
+ */
31
+ class LooseCountItem extends S.Class<LooseCountItem>("LooseCountItem")({
32
+ id: S.String,
33
+ name: S.NonEmptyString255,
34
+ count: S.FiniteFromString
35
+ }) {}
36
+
37
+ /** build a `LooseCountItem` from its encoded (stored) form */
38
+ const looseItem = (id: string, name: string, count: string) => S.decodeSync(LooseCountItem)({ id, name, count })
39
+
14
40
  describe("validateSample", () => {
15
41
  it("returns success when all items pass validation", () =>
16
42
  Effect
@@ -25,41 +51,42 @@ describe("validateSample", () => {
25
51
 
26
52
  const result = yield* repo.validateSample({ percentage: 1.0 }) // 100%
27
53
 
28
- expect(result).toBeInstanceOf(ValidationResult)
54
+ expect(S.is(ValidationResult)(result)).toBe(true)
29
55
  expect(result.total).toBe(3)
30
56
  expect(result.sampled).toBe(3)
31
57
  expect(result.valid).toBe(3)
32
58
  expect(result.errors).toHaveLength(0)
33
59
  })
34
60
  .pipe(
35
- Effect.provide(MemoryStoreLive),
61
+ Effect.provide(TestStoreLive),
36
62
  setupRequestContextFromCurrent(),
63
+ Effect.scoped,
37
64
  Effect.runPromise
38
65
  ))
39
66
 
40
- it("returns errors when jitM produces invalid data", () =>
67
+ it("returns errors when jitM produces data the domain schema rejects", () =>
41
68
  Effect
42
69
  .gen(function*() {
43
- // jitM that corrupts one specific item's count to be negative
44
- const corruptingJitM = (pm: typeof SimpleItem.Encoded) => {
45
- if (pm.id === "2" || pm.id === "3") {
46
- return { ...pm, count: -999 } // make count negative (invalid for NonNegativeInt)
70
+ // jitM that corrupts two specific items' count into a non-numeric string
71
+ const corruptingJitM = (json: JsonRecord): JsonRecord => {
72
+ if (json["id"] === "2" || json["id"] === "3") {
73
+ return { ...json, count: "not-a-number" } // still a string, so the store decode is happy
47
74
  }
48
- return pm
75
+ return json
49
76
  }
50
77
 
51
- const repo = yield* makeRepo("CorruptItem", SimpleItem, {
78
+ const repo = yield* makeRepo("CorruptItem", LooseCountItem, {
52
79
  jitM: corruptingJitM,
53
80
  makeInitial: Effect.succeed([
54
- new SimpleItem({ id: "1", name: S.NonEmptyString255("Valid"), count: S.NonNegativeInt(10) }),
55
- new SimpleItem({ id: "2", name: S.NonEmptyString255("WillBeInvalid1"), count: S.NonNegativeInt(20) }),
56
- new SimpleItem({ id: "3", name: S.NonEmptyString255("WillBeInvalid2"), count: S.NonNegativeInt(30) })
81
+ looseItem("1", "Valid", "10"),
82
+ looseItem("2", "WillBeInvalid1", "20"),
83
+ looseItem("3", "WillBeInvalid2", "30")
57
84
  ])
58
85
  })
59
86
 
60
87
  const result = yield* repo.validateSample({ percentage: 1.0 }) // 100%
61
88
 
62
- expect(result).toBeInstanceOf(ValidationResult)
89
+ expect(S.is(ValidationResult)(result)).toBe(true)
63
90
  expect(result.total).toBe(3)
64
91
  expect(result.sampled).toBe(3)
65
92
  expect(result.valid).toBe(1)
@@ -67,7 +94,7 @@ describe("validateSample", () => {
67
94
 
68
95
  // verify error structure
69
96
  for (const error of result.errors) {
70
- expect(error).toBeInstanceOf(ValidationError)
97
+ expect(S.is(ValidationError)(error)).toBe(true)
71
98
  expect(error.id).toBeDefined()
72
99
  expect(error.rawData).toBeDefined()
73
100
  expect(error.jitMResult).toBeDefined()
@@ -80,8 +107,9 @@ describe("validateSample", () => {
80
107
  expect(failingIds).toContain("3")
81
108
  })
82
109
  .pipe(
83
- Effect.provide(MemoryStoreLive),
110
+ Effect.provide(TestStoreLive),
84
111
  setupRequestContextFromCurrent(),
112
+ Effect.scoped,
85
113
  Effect.runPromise
86
114
  ))
87
115
 
@@ -98,8 +126,9 @@ describe("validateSample", () => {
98
126
  expect(result.errors).toHaveLength(0)
99
127
  })
100
128
  .pipe(
101
- Effect.provide(MemoryStoreLive),
129
+ Effect.provide(TestStoreLive),
102
130
  setupRequestContextFromCurrent(),
131
+ Effect.scoped,
103
132
  Effect.runPromise
104
133
  ))
105
134
 
@@ -127,8 +156,9 @@ describe("validateSample", () => {
127
156
  expect(result.errors).toHaveLength(0)
128
157
  })
129
158
  .pipe(
130
- Effect.provide(MemoryStoreLive),
159
+ Effect.provide(TestStoreLive),
131
160
  setupRequestContextFromCurrent(),
161
+ Effect.scoped,
132
162
  Effect.runPromise
133
163
  ))
134
164
 
@@ -143,9 +173,9 @@ describe("validateSample", () => {
143
173
 
144
174
  // jitM that adds default status for items
145
175
  const repo = yield* makeRepo("ItemWithStatus", ItemWithStatus, {
146
- jitM: (pm) => ({
147
- ...pm,
148
- status: pm.status ?? "active" // default to active if missing
176
+ jitM: (json) => ({
177
+ ...json,
178
+ status: json["status"] ?? "active" // default to active if missing
149
179
  }),
150
180
  makeInitial: Effect.succeed([
151
181
  new ItemWithStatus({ id: "1", status: "active" }),
@@ -161,8 +191,9 @@ describe("validateSample", () => {
161
191
  expect(result.errors).toHaveLength(0)
162
192
  })
163
193
  .pipe(
164
- Effect.provide(MemoryStoreLive),
194
+ Effect.provide(TestStoreLive),
165
195
  setupRequestContextFromCurrent(),
196
+ Effect.scoped,
166
197
  Effect.runPromise
167
198
  ))
168
199
 
@@ -170,16 +201,14 @@ describe("validateSample", () => {
170
201
  Effect
171
202
  .gen(function*() {
172
203
  // jitM that corrupts the data
173
- const corruptingJitM = (pm: typeof SimpleItem.Encoded) => ({
174
- ...pm,
175
- count: -999 // always corrupt count
204
+ const corruptingJitM = (json: JsonRecord): JsonRecord => ({
205
+ ...json,
206
+ count: "not-a-number" // always corrupt count
176
207
  })
177
208
 
178
- const repo = yield* makeRepo("ContextErrorTest", SimpleItem, {
209
+ const repo = yield* makeRepo("ContextErrorTest", LooseCountItem, {
179
210
  jitM: corruptingJitM,
180
- makeInitial: Effect.succeed([
181
- new SimpleItem({ id: "bad-item", name: S.NonEmptyString255("Test"), count: S.NonNegativeInt(100) })
182
- ])
211
+ makeInitial: Effect.succeed([looseItem("bad-item", "Test", "100")])
183
212
  })
184
213
 
185
214
  const result = yield* repo.validateSample({ percentage: 1.0 })
@@ -189,27 +218,25 @@ describe("validateSample", () => {
189
218
  const error = result.errors[0]!
190
219
  expect(error.id).toBe("bad-item")
191
220
 
192
- // rawData should contain the original db data (with valid count)
221
+ // rawData is what the store returned: jitM already ran at the store
222
+ // boundary, so the corrupted count is what the repository decoded
193
223
  expect(error.rawData).toMatchObject({
194
224
  id: "bad-item",
195
225
  name: "Test",
196
- count: 100
226
+ count: "not-a-number"
197
227
  })
198
228
 
199
- // jitMResult should contain the corrupted data
200
- expect(error.jitMResult).toMatchObject({
201
- id: "bad-item",
202
- name: "Test",
203
- count: -999
204
- })
229
+ // jitMResult is kept for compatibility and is identical to rawData
230
+ expect(error.jitMResult).toEqual(error.rawData)
205
231
 
206
232
  // error should be a SchemaError
207
233
  expect(error.error).toBeDefined()
208
- expect((error.error as any)._tag).toBe("SchemaError")
234
+ expect((error.error as { _tag?: string })._tag).toBe("SchemaError")
209
235
  })
210
236
  .pipe(
211
- Effect.provide(MemoryStoreLive),
237
+ Effect.provide(TestStoreLive),
212
238
  setupRequestContextFromCurrent(),
239
+ Effect.scoped,
213
240
  Effect.runPromise
214
241
  ))
215
242
 
@@ -230,8 +257,9 @@ describe("validateSample", () => {
230
257
  expect(result.errors).toHaveLength(0)
231
258
  })
232
259
  .pipe(
233
- Effect.provide(MemoryStoreLive),
260
+ Effect.provide(TestStoreLive),
234
261
  setupRequestContextFromCurrent(),
262
+ Effect.scoped,
235
263
  Effect.runPromise
236
264
  ))
237
265
  })
@@ -0,0 +1,345 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * Workflow engine conformance tests.
4
+ *
5
+ * The `runSuite` body is engine-agnostic: it runs against
6
+ * `WorkflowEngine.layerMemory` (fast, always) and — when `COSMOS_TEST_URL`
7
+ * is set — against the Cosmos adapter (`layerCosmos`) pointed at a Cosmos
8
+ * emulator. Both must satisfy the same observable contract: idempotent
9
+ * execution, activity replay (no double side effects), suspend → durable-
10
+ * deferred completion → resume with a correctly decoded result, interrupt
11
+ * propagation, and first-writer-wins deferred completion.
12
+ *
13
+ * A second describe block (Cosmos emulator only) exercises adapter
14
+ * internals — the recovery poller (driving execs whose lease has lapsed)
15
+ * and the clock poller (firing past-due clocks) — by seeding rows
16
+ * directly against the Cosmos container.
17
+ */
18
+ import { assert, describe, it } from "@effect/vitest"
19
+ import { Context, Duration, Effect, Exit, Layer, Option, Redacted, Schema } from "effect"
20
+ import { Activity, DurableDeferred, Workflow, WorkflowEngine } from "effect/workflow"
21
+ import { CosmosClient, CosmosClientLayer } from "../src/cosmos-client.js"
22
+ import { layerCosmos } from "../src/WorkflowEngineCosmos.js"
23
+
24
+ // --- Shared mutable counter for activity-side-effect assertions --------
25
+
26
+ class CounterRef extends Context.Service<CounterRef, { count: number }>()("CounterRef") {
27
+ static readonly layer = Layer.effect(CounterRef, Effect.sync(() => ({ count: 0 })))
28
+ }
29
+
30
+ // --- Workflow definitions ----------------------------------------------
31
+
32
+ const IncrementWorkflow = Workflow.make("WorkflowEngineCosmos/IncrementWorkflow", {
33
+ payload: { value: Schema.Number },
34
+ success: Schema.Number,
35
+ idempotencyKey: ({ value }) => String(value)
36
+ })
37
+
38
+ const IncrementHandler = IncrementWorkflow.toLayer(({ value }) => Effect.succeed(value + 1))
39
+
40
+ // Counts activity body invocations across re-executes so the test can
41
+ // prove side-effects don't repeat when a persisted result is available.
42
+ const CounterWorkflow = Workflow.make("WorkflowEngineCosmos/CounterWorkflow", {
43
+ payload: { id: Schema.String },
44
+ success: Schema.Number,
45
+ idempotencyKey: ({ id }) => id
46
+ })
47
+
48
+ const CounterHandler = CounterWorkflow.toLayer(Effect.fn(function*() {
49
+ const counter = yield* CounterRef
50
+ return yield* Activity.make({
51
+ name: "Bump",
52
+ success: Schema.Number,
53
+ execute: Effect.sync(() => {
54
+ counter.count++
55
+ return counter.count
56
+ })
57
+ })
58
+ }))
59
+
60
+ // Suspends on a deferred, then composes the persisted activity result
61
+ // with the resumed deferred value. Exercises Result/Exit round-trip.
62
+ const Trigger = DurableDeferred.make("WorkflowEngineCosmos/Trigger", { success: Schema.String })
63
+
64
+ const SuspendWorkflow = Workflow.make("WorkflowEngineCosmos/SuspendWorkflow", {
65
+ payload: { id: Schema.String },
66
+ success: Schema.String,
67
+ idempotencyKey: ({ id }) => id
68
+ })
69
+
70
+ const SuspendHandler = SuspendWorkflow.toLayer(Effect.fn(function*({ id }) {
71
+ const n = yield* Activity.make({
72
+ name: "step",
73
+ success: Schema.Number,
74
+ execute: Effect.succeed(1)
75
+ })
76
+ const v = yield* DurableDeferred.await(Trigger)
77
+ return `${id}:${n}:${v}`
78
+ }))
79
+
80
+ // Plain durable-deferred await — used to assert first-writer-wins on done().
81
+ const AwaitOnly = Workflow.make("WorkflowEngineCosmos/AwaitOnly", {
82
+ payload: { id: Schema.String },
83
+ success: Schema.String,
84
+ idempotencyKey: ({ id }) => id
85
+ })
86
+
87
+ const AwaitOnlyHandler = AwaitOnly.toLayer(Effect.fn(function*() {
88
+ return yield* DurableDeferred.await(Trigger)
89
+ }))
90
+
91
+ const Handlers = Layer.mergeAll(IncrementHandler, SuspendHandler, CounterHandler, AwaitOnlyHandler)
92
+
93
+ // Helper that polls until the workflow completes (or `maxIterations` elapse).
94
+ const waitForComplete = (
95
+ workflow: { readonly poll: (id: string) => Effect.Effect<Option.Option<Workflow.Result<any, any>>, never, any> },
96
+ executionId: string,
97
+ step = Duration.millis(10),
98
+ maxIterations = 200
99
+ ) =>
100
+ Effect.gen(function*() {
101
+ for (let i = 0; i < maxIterations; i++) {
102
+ const polled = yield* workflow.poll(executionId)
103
+ if (Option.isSome(polled) && polled.value._tag === "Complete") {
104
+ return polled.value
105
+ }
106
+ yield* Effect.sleep(step)
107
+ }
108
+ return undefined
109
+ })
110
+
111
+ const runSuite = (engineLayer: Layer.Layer<WorkflowEngine.WorkflowEngine>) => {
112
+ const TestLayer = Handlers.pipe(
113
+ Layer.provideMerge(CounterRef.layer),
114
+ Layer.provideMerge(engineLayer)
115
+ )
116
+
117
+ it.live("executes a workflow and polls the result", () =>
118
+ Effect
119
+ .gen(function*() {
120
+ const executionId = yield* IncrementWorkflow.execute({ value: 41 }, { discard: true })
121
+ const result = yield* IncrementWorkflow.execute({ value: 41 })
122
+ const polled = yield* IncrementWorkflow.poll(executionId)
123
+
124
+ assert.strictEqual(result, 42)
125
+ assert(
126
+ Option.isSome(polled)
127
+ && polled.value._tag === "Complete"
128
+ && Exit.isSuccess(polled.value.exit)
129
+ )
130
+ assert.strictEqual(polled.value.exit.value, 42)
131
+ })
132
+ .pipe(Effect.provide(TestLayer)))
133
+
134
+ it.live("re-executing the same id is idempotent", () =>
135
+ Effect
136
+ .gen(function*() {
137
+ const a = yield* IncrementWorkflow.execute({ value: 7 })
138
+ const b = yield* IncrementWorkflow.execute({ value: 7 })
139
+ assert.strictEqual(a, b)
140
+ })
141
+ .pipe(Effect.provide(TestLayer)))
142
+
143
+ it.live("activity side effects run once across re-executions", () =>
144
+ Effect
145
+ .gen(function*() {
146
+ const counter = yield* CounterRef
147
+ yield* CounterWorkflow.execute({ id: "once" })
148
+ yield* CounterWorkflow.execute({ id: "once" })
149
+ yield* CounterWorkflow.execute({ id: "once" })
150
+ assert.strictEqual(counter.count, 1)
151
+ })
152
+ .pipe(Effect.provide(TestLayer)))
153
+
154
+ it.live("suspends on a durable deferred, then resumes with the decoded result", () =>
155
+ Effect
156
+ .gen(function*() {
157
+ // The execution suspends on `Trigger`; completing the deferred resumes
158
+ // it (the workflow body replays, the `step` activity is served from its
159
+ // persisted result), and the final value round-trips through the engine.
160
+ const executionId = yield* SuspendWorkflow.execute({ id: "abc" }, { discard: true })
161
+
162
+ const token = yield* DurableDeferred.tokenFromPayload(Trigger, {
163
+ workflow: SuspendWorkflow,
164
+ payload: { id: "abc" }
165
+ })
166
+ yield* DurableDeferred.done(Trigger, { token, exit: Exit.succeed("ok") })
167
+
168
+ const done = yield* waitForComplete(SuspendWorkflow, executionId)
169
+ assert(done && Exit.isSuccess(done.exit))
170
+ assert.strictEqual(done.exit.value, "abc:1:ok")
171
+ })
172
+ .pipe(Effect.provide(TestLayer)))
173
+
174
+ it.live("deferredDone is idempotent (first-writer-wins)", () =>
175
+ Effect
176
+ .gen(function*() {
177
+ const executionId = yield* AwaitOnly.execute({ id: "dup" }, { discard: true })
178
+ const token = yield* DurableDeferred.tokenFromPayload(Trigger, {
179
+ workflow: AwaitOnly,
180
+ payload: { id: "dup" }
181
+ })
182
+ yield* DurableDeferred.done(Trigger, { token, exit: Exit.succeed("first") })
183
+ // Second completion must lose; the workflow body sees "first".
184
+ yield* DurableDeferred.done(Trigger, { token, exit: Exit.succeed("second") })
185
+
186
+ const done = yield* waitForComplete(AwaitOnly, executionId)
187
+ assert(done && Exit.isSuccess(done.exit))
188
+ assert.strictEqual(done.exit.value, "first")
189
+ })
190
+ .pipe(Effect.provide(TestLayer)))
191
+
192
+ it.live("interrupt eventually completes a suspended execution", () =>
193
+ Effect
194
+ .gen(function*() {
195
+ const executionId = yield* AwaitOnly.execute({ id: "int" }, { discard: true })
196
+ // Give the workflow time to suspend on the deferred.
197
+ yield* Effect.sleep(Duration.millis(50))
198
+ yield* AwaitOnly.interrupt(executionId)
199
+
200
+ // Interrupt collapses the suspended execution into a completion. A
201
+ // durable engine re-drives across several storage round-trips, so poll
202
+ // until it reports Complete rather than asserting a fixed delay.
203
+ const done = yield* waitForComplete(AwaitOnly, executionId)
204
+ assert(done !== undefined && done._tag === "Complete")
205
+ })
206
+ .pipe(Effect.provide(TestLayer)))
207
+ }
208
+
209
+ describe("WorkflowEngine (in-memory)", () => {
210
+ runSuite(WorkflowEngine.layerMemory)
211
+ })
212
+
213
+ // --- Cosmos-emulator-only adapter tests --------------------------------
214
+ //
215
+ // Opt-in. Run with e.g.
216
+ // COSMOS_TEST_URL="https://localhost:8081" COSMOS_TEST_DB="workflow-test" \
217
+ // NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm vitest run workflow-engine-cosmos
218
+ const cosmosUrl = process.env["COSMOS_TEST_URL"]
219
+ const cosmosDb = process.env["COSMOS_TEST_DB"] ?? "workflow-test"
220
+
221
+ describe.skipIf(!cosmosUrl)("WorkflowEngine (Cosmos) — conformance", () => {
222
+ runSuite(
223
+ layerCosmos({
224
+ url: Redacted.make(cosmosUrl ?? ""),
225
+ dbName: cosmosDb,
226
+ prefix: `test-${Date.now()}-`,
227
+ // Tight cadences so the suite doesn't wait on the background pollers.
228
+ recoveryInterval: Duration.seconds(2),
229
+ clockPollInterval: Duration.seconds(1)
230
+ })
231
+ )
232
+ })
233
+
234
+ describe.skipIf(!cosmosUrl)("WorkflowEngine (Cosmos) — adapter internals", () => {
235
+ // Each test gets its own container prefix so seeded docs don't leak.
236
+ const prefixFor = (label: string) => `test-${Date.now()}-${label}-`
237
+
238
+ const adapterLayer = (prefix: string) =>
239
+ Layer
240
+ .mergeAll(
241
+ IncrementHandler,
242
+ AwaitOnlyHandler,
243
+ CounterRef.layer,
244
+ CosmosClientLayer(cosmosUrl ?? "", cosmosDb)
245
+ )
246
+ .pipe(
247
+ Layer.provideMerge(
248
+ layerCosmos({
249
+ url: Redacted.make(cosmosUrl ?? ""),
250
+ dbName: cosmosDb,
251
+ prefix,
252
+ recoveryInterval: Duration.millis(500),
253
+ clockPollInterval: Duration.millis(500)
254
+ })
255
+ )
256
+ )
257
+
258
+ it.live("recovery poller drives execs with stale leases", () => {
259
+ const prefix = prefixFor("recovery")
260
+ const containerId = `${prefix}workflow-engine`
261
+ return Effect
262
+ .gen(function*() {
263
+ const { db } = yield* CosmosClient
264
+ const container = db.container(containerId)
265
+ // Pre-seed a running exec whose lease has already expired and whose
266
+ // payload is the schema-encoded form of `{ value: 99 }`.
267
+ yield* Effect.promise(() =>
268
+ container.items.upsert({
269
+ id: "exec",
270
+ _partitionKey: "recover-1",
271
+ type: "exec",
272
+ workflowName: IncrementWorkflow._tag,
273
+ payload: JSON.stringify({ value: 99 }),
274
+ status: "running",
275
+ suspended: false,
276
+ interrupted: false,
277
+ worker: "ghost",
278
+ leaseExpiresAt: new Date(Date.now() - 60_000).toISOString(),
279
+ etag: "seed"
280
+ })
281
+ )
282
+
283
+ // Wait for the recovery poller (500ms cadence) to drive it.
284
+ yield* Effect.sleep(Duration.seconds(2))
285
+
286
+ const polled = yield* IncrementWorkflow.poll("recover-1")
287
+ assert(
288
+ Option.isSome(polled)
289
+ && polled.value._tag === "Complete"
290
+ && Exit.isSuccess(polled.value.exit)
291
+ )
292
+ assert.strictEqual(polled.value.exit.value, 100)
293
+ })
294
+ .pipe(Effect.provide(adapterLayer(prefix)))
295
+ })
296
+
297
+ it.live("clock poller fires past-due clocks", () => {
298
+ const prefix = prefixFor("clocks")
299
+ const containerId = `${prefix}workflow-engine`
300
+ return Effect
301
+ .gen(function*() {
302
+ const { db } = yield* CosmosClient
303
+ const container = db.container(containerId)
304
+ // Seed an exec + a clock that fired in the past. No in-process timer
305
+ // exists (we never called scheduleClock), so only the poller can
306
+ // resolve the deferred.
307
+ yield* Effect.promise(() =>
308
+ container.items.upsert({
309
+ id: "exec",
310
+ _partitionKey: "exec-clock",
311
+ type: "exec",
312
+ workflowName: AwaitOnly._tag,
313
+ payload: JSON.stringify({ id: "wake" }),
314
+ status: "running",
315
+ suspended: false,
316
+ interrupted: false,
317
+ etag: "seed"
318
+ })
319
+ )
320
+ yield* Effect.promise(() =>
321
+ container.items.upsert({
322
+ id: "clock::wake",
323
+ _partitionKey: "exec-clock",
324
+ type: "clock",
325
+ workflowName: AwaitOnly._tag,
326
+ deferredName: Trigger.name,
327
+ fireAt: new Date(Date.now() - 60_000).toISOString()
328
+ })
329
+ )
330
+
331
+ yield* Effect.sleep(Duration.seconds(2))
332
+
333
+ // The clock fire is a deferred-complete; assert the deferred row
334
+ // now exists for this execution.
335
+ const deferred = yield* Effect.promise(() =>
336
+ container.item(encodeURIComponent(`deferred::${Trigger.name}`), "exec-clock").read<{ exit: string }>()
337
+ )
338
+ assert(deferred.resource !== undefined)
339
+ // And the clock doc has been deleted.
340
+ const clockGone = yield* Effect.promise(() => container.item("clock::wake", "exec-clock").read())
341
+ assert.strictEqual(clockGone.statusCode, 404)
342
+ })
343
+ .pipe(Effect.provide(adapterLayer(prefix)))
344
+ })
345
+ })