@effect-app/infra 4.0.0-beta.33 → 4.0.0-beta.330

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 (490) hide show
  1. package/CHANGELOG.md +2555 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +29 -10
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +36 -15
  6. package/dist/ClusterCosmos.d.ts +64 -0
  7. package/dist/ClusterCosmos.d.ts.map +1 -0
  8. package/dist/ClusterCosmos.js +576 -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/ContextProvider.d.ts +34 -0
  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 +12 -8
  22. package/dist/MainFiberSet.d.ts.map +1 -1
  23. package/dist/MainFiberSet.js +23 -7
  24. package/dist/QueueMaker/errors.d.ts +4 -2
  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 +31 -42
  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 +395 -256
  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 +93 -42
  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 +349 -79
  44. package/dist/Store/SQL/Pg.d.ts +4 -0
  45. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  46. package/dist/Store/SQL/Pg.js +261 -0
  47. package/dist/Store/SQL/query.d.ts +53 -0
  48. package/dist/Store/SQL/query.d.ts.map +1 -0
  49. package/dist/Store/SQL/query.js +656 -0
  50. package/dist/Store/SQL.d.ts +28 -0
  51. package/dist/Store/SQL.d.ts.map +1 -0
  52. package/dist/Store/SQL.js +483 -0
  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 +18 -5
  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 +24 -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/internal/health.d.ts.map +1 -0
  98. package/dist/internal/health.js +5 -0
  99. package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +14 -6
  100. package/dist/layerUtils.d.ts.map +1 -0
  101. package/dist/layerUtils.js +17 -0
  102. package/dist/logger/jsonLogger.d.ts +1 -1
  103. package/dist/logger/jsonLogger.d.ts.map +1 -1
  104. package/dist/logger/jsonLogger.js +5 -3
  105. package/dist/logger/logFmtLogger.d.ts +1 -1
  106. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  107. package/dist/logger/logFmtLogger.js +3 -3
  108. package/dist/logger/shared.d.ts +2 -2
  109. package/dist/logger/shared.d.ts.map +1 -1
  110. package/dist/logger/shared.js +6 -6
  111. package/dist/logger.d.ts +4 -4
  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} +3 -2
  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} +5 -2
  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 +4 -3
  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/routing/middleware/middleware.d.ts +48 -0
  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 +25 -21
  157. package/package.json +38 -352
  158. package/src/CUPS.ts +54 -15
  159. package/src/ClusterCosmos.ts +1150 -0
  160. package/src/ClusterServiceBus.ts +244 -0
  161. package/src/{api/ContextProvider.ts → ContextProvider.ts} +20 -17
  162. package/src/Emailer/Sendgrid.ts +83 -60
  163. package/src/Emailer/fake.ts +4 -4
  164. package/src/MainFiberSet.ts +32 -13
  165. package/src/QueueMaker/errors.ts +3 -1
  166. package/src/{adapters/SQL → SQL}/Model.ts +42 -41
  167. package/src/SQL.ts +1 -0
  168. package/src/Store/Cosmos/query.ts +275 -55
  169. package/src/Store/Cosmos.ts +547 -366
  170. package/src/Store/Disk.ts +146 -73
  171. package/src/Store/Memory.ts +420 -115
  172. package/src/Store/SQL/Pg.ts +412 -0
  173. package/src/Store/SQL/query.ts +748 -0
  174. package/src/Store/SQL.ts +806 -0
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +25 -10
  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 +56 -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 +22 -13
  189. package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
  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} +4 -2
  195. package/src/otel.ts +177 -0
  196. package/src/rateLimit.ts +35 -24
  197. package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
  198. package/src/{api/reportError.ts → reportError.ts} +3 -2
  199. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
  200. package/src/routing/middleware/middleware.ts +196 -0
  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 +612 -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 +15 -12
  214. package/test/controller.test.ts +27 -31
  215. package/test/cosmos-container-throughput.test.ts +61 -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 +29 -11
  228. package/test/dist/fixtures.d.ts.map +1 -1
  229. package/test/dist/fixtures.js +17 -10
  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/sql-store.test.d.ts.map +1 -0
  243. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  244. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  245. package/test/fixtures.ts +16 -9
  246. package/test/json-lower.test.ts +129 -0
  247. package/test/layerUtils.test.ts +2 -2
  248. package/test/query.test.ts +1382 -44
  249. package/test/rawQuery.test.ts +433 -8
  250. package/test/repository-ext.test.ts +456 -0
  251. package/test/repository-legacy-document.test.ts +394 -0
  252. package/test/requires.test.ts +10 -5
  253. package/test/router-generator.test.ts +187 -0
  254. package/test/routing-interruptibility.test.ts +66 -0
  255. package/test/rpc-context-map-streaming.test.ts +265 -0
  256. package/test/rpc-e2e-invalidation.test.ts +421 -0
  257. package/test/rpc-multi-middleware.test.ts +85 -10
  258. package/test/rpc-stream-fullstack.test.ts +307 -0
  259. package/test/sql-store.test.ts +1931 -0
  260. package/test/validateSample.test.ts +71 -43
  261. package/test/workflow-engine-cosmos.test.ts +345 -0
  262. package/test/workflow-engine-sqlite.test.ts +297 -0
  263. package/tsconfig.examples.json +1 -1
  264. package/tsconfig.json +9 -2
  265. package/tsconfig.src.json +35 -35
  266. package/tsconfig.test.json +2 -2
  267. package/dist/Emailer/service.d.ts +0 -55
  268. package/dist/Emailer/service.d.ts.map +0 -1
  269. package/dist/Emailer/service.js +0 -6
  270. package/dist/Emailer.d.ts +0 -2
  271. package/dist/Emailer.d.ts.map +0 -1
  272. package/dist/Emailer.js +0 -2
  273. package/dist/Model/Repository/ext.d.ts +0 -41
  274. package/dist/Model/Repository/ext.d.ts.map +0 -1
  275. package/dist/Model/Repository/ext.js +0 -65
  276. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  277. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  278. package/dist/Model/Repository/internal/internal.js +0 -316
  279. package/dist/Model/Repository/legacy.d.ts +0 -19
  280. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  281. package/dist/Model/Repository/legacy.js +0 -2
  282. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  283. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  284. package/dist/Model/Repository/makeRepo.js +0 -24
  285. package/dist/Model/Repository/service.d.ts +0 -89
  286. package/dist/Model/Repository/service.d.ts.map +0 -1
  287. package/dist/Model/Repository/service.js +0 -2
  288. package/dist/Model/Repository/validation.d.ts +0 -42
  289. package/dist/Model/Repository/validation.d.ts.map +0 -1
  290. package/dist/Model/Repository/validation.js +0 -32
  291. package/dist/Model/Repository.d.ts +0 -6
  292. package/dist/Model/Repository.d.ts.map +0 -1
  293. package/dist/Model/Repository.js +0 -6
  294. package/dist/Model/dsl.d.ts +0 -32
  295. package/dist/Model/dsl.d.ts.map +0 -1
  296. package/dist/Model/dsl.js +0 -44
  297. package/dist/Model/filter/filterApi.d.ts +0 -30
  298. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  299. package/dist/Model/filter/filterApi.js +0 -2
  300. package/dist/Model/filter/types/errors.d.ts +0 -29
  301. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  302. package/dist/Model/filter/types/errors.js +0 -2
  303. package/dist/Model/filter/types/fields.d.ts +0 -15
  304. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  305. package/dist/Model/filter/types/fields.js +0 -2
  306. package/dist/Model/filter/types/path/common.d.ts +0 -316
  307. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  308. package/dist/Model/filter/types/path/common.js +0 -2
  309. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  310. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  311. package/dist/Model/filter/types/path/eager.js +0 -31
  312. package/dist/Model/filter/types/path/index.d.ts +0 -4
  313. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  314. package/dist/Model/filter/types/path/index.js +0 -3
  315. package/dist/Model/filter/types/utils.d.ts +0 -79
  316. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  317. package/dist/Model/filter/types/utils.js +0 -2
  318. package/dist/Model/filter/types/validator.d.ts +0 -30
  319. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  320. package/dist/Model/filter/types/validator.js +0 -2
  321. package/dist/Model/filter/types.d.ts +0 -5
  322. package/dist/Model/filter/types.d.ts.map +0 -1
  323. package/dist/Model/filter/types.js +0 -7
  324. package/dist/Model/query/dsl.d.ts +0 -248
  325. package/dist/Model/query/dsl.d.ts.map +0 -1
  326. package/dist/Model/query/dsl.js +0 -104
  327. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  328. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  329. package/dist/Model/query/new-kid-interpreter.js +0 -165
  330. package/dist/Model/query.d.ts +0 -15
  331. package/dist/Model/query.d.ts.map +0 -1
  332. package/dist/Model/query.js +0 -3
  333. package/dist/Model.d.ts +0 -4
  334. package/dist/Model.d.ts.map +0 -1
  335. package/dist/Model.js +0 -4
  336. package/dist/Operations.d.ts +0 -55
  337. package/dist/Operations.d.ts.map +0 -1
  338. package/dist/Operations.js +0 -102
  339. package/dist/OperationsRepo.d.ts +0 -41
  340. package/dist/OperationsRepo.d.ts.map +0 -1
  341. package/dist/OperationsRepo.js +0 -14
  342. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  343. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  344. package/dist/QueueMaker/SQLQueue.js +0 -130
  345. package/dist/QueueMaker/memQueue.d.ts +0 -11
  346. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  347. package/dist/QueueMaker/memQueue.js +0 -76
  348. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  349. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  350. package/dist/QueueMaker/sbqueue.js +0 -91
  351. package/dist/QueueMaker/service.d.ts +0 -11
  352. package/dist/QueueMaker/service.d.ts.map +0 -1
  353. package/dist/QueueMaker/service.js +0 -4
  354. package/dist/RequestContext.d.ts +0 -63
  355. package/dist/RequestContext.d.ts.map +0 -1
  356. package/dist/RequestContext.js +0 -49
  357. package/dist/RequestFiberSet.d.ts +0 -36
  358. package/dist/RequestFiberSet.d.ts.map +0 -1
  359. package/dist/RequestFiberSet.js +0 -78
  360. package/dist/Store/ContextMapContainer.d.ts +0 -14
  361. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  362. package/dist/Store/ContextMapContainer.js +0 -16
  363. package/dist/Store/service.d.ts +0 -108
  364. package/dist/Store/service.d.ts.map +0 -1
  365. package/dist/Store/service.js +0 -71
  366. package/dist/Store.d.ts +0 -2
  367. package/dist/Store.d.ts.map +0 -1
  368. package/dist/Store.js +0 -2
  369. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  370. package/dist/adapters/SQL/Model.js +0 -478
  371. package/dist/adapters/SQL.d.ts.map +0 -1
  372. package/dist/adapters/ServiceBus.d.ts +0 -58
  373. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  374. package/dist/adapters/ServiceBus.js +0 -99
  375. package/dist/adapters/cosmos-client.d.ts +0 -14
  376. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  377. package/dist/adapters/cosmos-client.js +0 -9
  378. package/dist/adapters/index.d.ts +0 -2
  379. package/dist/adapters/index.d.ts.map +0 -1
  380. package/dist/adapters/index.js +0 -2
  381. package/dist/adapters/logger.d.ts +0 -9
  382. package/dist/adapters/logger.d.ts.map +0 -1
  383. package/dist/adapters/logger.js +0 -3
  384. package/dist/adapters/memQueue.d.ts +0 -13
  385. package/dist/adapters/memQueue.d.ts.map +0 -1
  386. package/dist/adapters/memQueue.js +0 -20
  387. package/dist/adapters/mongo-client.d.ts.map +0 -1
  388. package/dist/adapters/mongo-client.js +0 -13
  389. package/dist/adapters/redis-client.d.ts.map +0 -1
  390. package/dist/adapters/redis-client.js +0 -94
  391. package/dist/api/ContextProvider.d.ts +0 -31
  392. package/dist/api/ContextProvider.d.ts.map +0 -1
  393. package/dist/api/ContextProvider.js +0 -38
  394. package/dist/api/codec.d.ts.map +0 -1
  395. package/dist/api/codec.js +0 -5
  396. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  397. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  398. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  399. package/dist/api/internal/auth.d.ts +0 -15
  400. package/dist/api/internal/auth.d.ts.map +0 -1
  401. package/dist/api/internal/auth.js +0 -47
  402. package/dist/api/internal/events.d.ts +0 -9
  403. package/dist/api/internal/events.d.ts.map +0 -1
  404. package/dist/api/internal/events.js +0 -42
  405. package/dist/api/internal/health.d.ts.map +0 -1
  406. package/dist/api/internal/health.js +0 -5
  407. package/dist/api/layerUtils.d.ts.map +0 -1
  408. package/dist/api/layerUtils.js +0 -16
  409. package/dist/api/middlewares.d.ts.map +0 -1
  410. package/dist/api/reportError.d.ts.map +0 -1
  411. package/dist/api/reportError.js +0 -27
  412. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  413. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  414. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  415. package/dist/api/routing/middleware/middleware.js +0 -92
  416. package/dist/api/routing/middleware.d.ts.map +0 -1
  417. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  418. package/dist/api/routing/schema/jwt.js +0 -12
  419. package/dist/api/routing/tsort.d.ts.map +0 -1
  420. package/dist/api/routing/tsort.js +0 -51
  421. package/dist/api/routing/utils.d.ts.map +0 -1
  422. package/dist/api/routing/utils.js +0 -44
  423. package/dist/api/routing.d.ts +0 -138
  424. package/dist/api/routing.d.ts.map +0 -1
  425. package/dist/api/routing.js +0 -166
  426. package/dist/api/setupRequest.d.ts +0 -12
  427. package/dist/api/setupRequest.d.ts.map +0 -1
  428. package/dist/api/setupRequest.js +0 -44
  429. package/dist/api/util.d.ts.map +0 -1
  430. package/dist/api/util.js +0 -14
  431. package/eslint.config.mjs +0 -24
  432. package/src/Emailer/service.ts +0 -52
  433. package/src/Emailer.ts +0 -1
  434. package/src/Model/Repository/ext.ts +0 -283
  435. package/src/Model/Repository/internal/internal.ts +0 -577
  436. package/src/Model/Repository/legacy.ts +0 -27
  437. package/src/Model/Repository/makeRepo.ts +0 -139
  438. package/src/Model/Repository/service.ts +0 -627
  439. package/src/Model/Repository/validation.ts +0 -31
  440. package/src/Model/Repository.ts +0 -5
  441. package/src/Model/dsl.ts +0 -128
  442. package/src/Model/filter/filterApi.ts +0 -60
  443. package/src/Model/filter/types/errors.ts +0 -47
  444. package/src/Model/filter/types/fields.ts +0 -50
  445. package/src/Model/filter/types/path/common.ts +0 -404
  446. package/src/Model/filter/types/path/eager.ts +0 -298
  447. package/src/Model/filter/types/path/index.ts +0 -4
  448. package/src/Model/filter/types/utils.ts +0 -128
  449. package/src/Model/filter/types/validator.ts +0 -46
  450. package/src/Model/filter/types.ts +0 -6
  451. package/src/Model/query/dsl.ts +0 -2110
  452. package/src/Model/query/new-kid-interpreter.ts +0 -210
  453. package/src/Model/query.ts +0 -13
  454. package/src/Model.ts +0 -3
  455. package/src/Operations.ts +0 -235
  456. package/src/OperationsRepo.ts +0 -16
  457. package/src/QueueMaker/SQLQueue.ts +0 -189
  458. package/src/QueueMaker/memQueue.ts +0 -130
  459. package/src/QueueMaker/sbqueue.ts +0 -137
  460. package/src/QueueMaker/service.ts +0 -17
  461. package/src/RequestContext.ts +0 -63
  462. package/src/RequestFiberSet.ts +0 -105
  463. package/src/Store/ContextMapContainer.ts +0 -20
  464. package/src/Store/index.test.ts.bak +0 -112
  465. package/src/Store/service.ts +0 -184
  466. package/src/Store.ts +0 -1
  467. package/src/adapters/SQL.ts +0 -1
  468. package/src/adapters/ServiceBus.ts +0 -209
  469. package/src/adapters/cosmos-client.ts +0 -16
  470. package/src/adapters/index.ts +0 -0
  471. package/src/adapters/logger.ts +0 -3
  472. package/src/adapters/memQueue.ts +0 -21
  473. package/src/api/internal/auth.ts +0 -68
  474. package/src/api/middlewares.ts +0 -10
  475. package/src/api/routing/middleware/middleware.ts +0 -128
  476. package/src/api/routing/middleware.ts +0 -6
  477. package/src/api/routing.ts +0 -598
  478. package/src/api/setupRequest.ts +0 -84
  479. package/tsconfig.json.bak +0 -12
  480. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  481. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  482. /package/dist/{api/internal → internal}/health.d.ts +0 -0
  483. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  484. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  485. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  486. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  487. /package/src/{api/codec.ts → codec.ts} +0 -0
  488. /package/src/{api/internal → internal}/health.ts +0 -0
  489. /package/src/{api/routing → routing}/tsort.ts +0 -0
  490. /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
 
@@ -138,14 +168,14 @@ describe("validateSample", () => {
138
168
  // schema that expects a 'status' field
139
169
  class ItemWithStatus extends S.Class<ItemWithStatus>("ItemWithStatus")({
140
170
  id: S.String,
141
- status: S.Literal("active", "inactive")
171
+ status: S.Literals(["active", "inactive"])
142
172
  }) {}
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/unstable/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
+ })