@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
@@ -0,0 +1,394 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import * as Effect from "effect-app/Effect"
4
+ import * as Layer from "effect-app/Layer"
5
+ import { makeRepo } from "effect-app/Model/Repository"
6
+ import { RepositoryRegistryLive } from "effect-app/Model/Repository/Registry"
7
+ import * as Option from "effect-app/Option"
8
+ import * as S from "effect-app/Schema"
9
+ import { setupRequestContextFromCurrent } from "effect-app/setupRequest"
10
+ import type { JsonRecord } from "effect-app/Store"
11
+ import { StoreMaker } from "effect-app/Store"
12
+ import * as Cause from "effect/Cause"
13
+ import * as Exit from "effect/Exit"
14
+ import * as Result from "effect/Result"
15
+ import { describe, expect, it } from "vitest"
16
+ import { decodeStoredMany, decodeStoredOption, makeStoredDecode } from "../src/Store/jsonDocument.js"
17
+ import { makeMemoryStoreInt } from "../src/Store/Memory.js"
18
+ import { makeJsonLower } from "../src/Store/utils.js"
19
+
20
+ /**
21
+ * A Memory store seeded with *raw stored documents* instead of items encoded
22
+ * through the schema, so that a legacy-shaped document can reach the read path -
23
+ * exactly what Cosmos (`fromStored`) and SQL (`parseRow`) do in production.
24
+ *
25
+ * `MemoryStoreLive` cannot be used for this: it strictly `encode`s whatever it
26
+ * is seeded with, so a legacy document never makes it into the store. The inner
27
+ * store here is therefore schemaless (it may not validate what we seed), and
28
+ * the real store read boundary - `defaultValues` merged, then `jitM`, then the
29
+ * strict JSON→Encoded decode - is applied on top via {@link makeStoredDecode}.
30
+ */
31
+ const LegacyDocStoreLive = (docs: readonly Record<string, unknown>[]) =>
32
+ StoreMaker.toLayer(Effect.sync(() => ({
33
+ make: ((modelName: string, idKey: any, _seed: any, config: any) =>
34
+ Effect.map(
35
+ makeMemoryStoreInt(
36
+ modelName,
37
+ idKey,
38
+ "primary",
39
+ Effect.succeed(docs as any),
40
+ config?.defaultValues,
41
+ undefined,
42
+ makeJsonLower(config)
43
+ ),
44
+ (store) => {
45
+ const decode = makeStoredDecode<any>(config?.schema, config?.jitM)
46
+ return {
47
+ ...store,
48
+ all: Effect.flatMap(store.all, (rows) => Effect.fromResult(decodeStoredMany(rows, decode))),
49
+ find: (id: any) =>
50
+ Effect.flatMap(store.find(id), (doc) => Effect.fromResult(decodeStoredOption(doc, decode))),
51
+ filter: (f: any) =>
52
+ Effect.flatMap(store.filter(f), (rows: any[]) =>
53
+ f.select ? Effect.succeed(rows) : Effect.fromResult(decodeStoredMany(rows, decode)))
54
+ }
55
+ }
56
+ )) as any
57
+ })))
58
+
59
+ class Shop extends S.Class<Shop>("LegacyDocShop")({
60
+ id: S.String,
61
+ name: S.NonEmptyString255,
62
+ createdAt: S.Date,
63
+ updatedAt: S.Date,
64
+ vatRate: S.Number,
65
+ tags: S.ReadonlySet(S.String),
66
+ meta: S.ReadonlyMap({ key: S.String, value: S.String })
67
+ }) {}
68
+
69
+ // `vatRate` was added later; stored documents from before that do not have it.
70
+ const jitM = (json: JsonRecord): JsonRecord => "vatRate" in json ? json : { ...json, vatRate: 19 }
71
+
72
+ /** does *not* repair `vatRate`, so `legacyDoc` cannot decode at the store boundary */
73
+ const jitMThatDoesNotRepair = (json: JsonRecord): JsonRecord => ({
74
+ ...json,
75
+ updatedAt: json["updatedAt"] ?? "2024-06-03T00:00:00.000Z"
76
+ })
77
+
78
+ const legacyDoc = {
79
+ id: "shop-legacy",
80
+ name: "Legacy Shop",
81
+ createdAt: "2024-06-01T00:00:00.000Z",
82
+ updatedAt: "2024-06-03T00:00:00.000Z",
83
+ tags: ["a"],
84
+ meta: [["k", "v"]]
85
+ }
86
+
87
+ const currentDoc = {
88
+ id: "shop-current",
89
+ name: "Current Shop",
90
+ createdAt: "2024-06-02T00:00:00.000Z",
91
+ updatedAt: "2024-06-04T00:00:00.000Z",
92
+ vatRate: 7,
93
+ tags: ["b"],
94
+ meta: [["k2", "v2"]]
95
+ }
96
+
97
+ /** a legacy document that stored an explicit `null` where a Date is expected */
98
+ const nullDoc = { ...legacyDoc, id: "shop-null", vatRate: 21, updatedAt: null }
99
+
100
+ /** `vatRate` present but falsy, `updatedAt` an explicit null */
101
+ const zeroDoc = { ...legacyDoc, id: "shop-zero", vatRate: 0, updatedAt: null }
102
+
103
+ const TestLive = Layer.merge(LegacyDocStoreLive([legacyDoc, currentDoc]), RepositoryRegistryLive)
104
+ const NullDocLive = Layer.merge(LegacyDocStoreLive([nullDoc]), RepositoryRegistryLive)
105
+ const CurrentDocLive = Layer.merge(LegacyDocStoreLive([currentDoc]), RepositoryRegistryLive)
106
+ const DefaultsLive = Layer.merge(LegacyDocStoreLive([legacyDoc, zeroDoc]), RepositoryRegistryLive)
107
+
108
+ describe("repository reads of legacy documents", () => {
109
+ it("all: jitM fills the key the stored document is missing", () =>
110
+ Effect
111
+ .gen(function*() {
112
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM })
113
+
114
+ const items = yield* repo.all
115
+
116
+ expect(items).toHaveLength(2)
117
+ const legacy = items.find((_) => _.id === "shop-legacy")!
118
+ expect(legacy).toBeInstanceOf(Shop)
119
+ expect(legacy.vatRate).toBe(19)
120
+ expect(legacy.createdAt).toBeInstanceOf(Date)
121
+ expect(legacy.tags).toBeInstanceOf(Set)
122
+ expect([...legacy.tags]).toEqual(["a"])
123
+ expect(items.find((_) => _.id === "shop-current")!.vatRate).toBe(7)
124
+ })
125
+ .pipe(
126
+ Effect.provide(TestLive),
127
+ setupRequestContextFromCurrent(),
128
+ Effect.scoped,
129
+ Effect.runPromise
130
+ ))
131
+
132
+ it("find: a legacy document decodes through jitM", () =>
133
+ Effect
134
+ .gen(function*() {
135
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM })
136
+
137
+ const found = yield* repo.find("shop-legacy")
138
+
139
+ expect(Option.isSome(found)).toBe(true)
140
+ const shop = Option.getOrThrow(found)
141
+ expect(shop.vatRate).toBe(19)
142
+ expect(shop.name).toBe("Legacy Shop")
143
+ expect(shop.createdAt).toBeInstanceOf(Date)
144
+ })
145
+ .pipe(
146
+ Effect.provide(TestLive),
147
+ setupRequestContextFromCurrent(),
148
+ Effect.scoped,
149
+ Effect.runPromise
150
+ ))
151
+
152
+ it("validateSample: legacy documents validate because jitM runs at the store boundary", () =>
153
+ Effect
154
+ .gen(function*() {
155
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM })
156
+
157
+ const result = yield* repo.validateSample({ percentage: 1.0 })
158
+
159
+ expect(result.total).toBe(2)
160
+ expect(result.sampled).toBe(2)
161
+ expect(result.errors).toHaveLength(0)
162
+ expect(result.valid).toBe(2)
163
+ })
164
+ .pipe(
165
+ Effect.provide(TestLive),
166
+ setupRequestContextFromCurrent(),
167
+ Effect.scoped,
168
+ Effect.runPromise
169
+ ))
170
+
171
+ it("jitM repairs an explicit null, and the document decodes end-to-end", () =>
172
+ Effect
173
+ .gen(function*() {
174
+ // the case the store boundary exists for: `null` is not a valid
175
+ // `S.Date` encoding, so no schema decode could ever fix it
176
+ const repairNull = (json: JsonRecord): JsonRecord =>
177
+ json["updatedAt"] === null ? { ...json, updatedAt: "2024-06-05T00:00:00.000Z" } : json
178
+
179
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM: repairNull })
180
+
181
+ const shop = Option.getOrThrow(yield* repo.find("shop-null"))
182
+ expect(shop.updatedAt).toBeInstanceOf(Date)
183
+ expect(shop.updatedAt.toISOString()).toBe("2024-06-05T00:00:00.000Z")
184
+
185
+ const all = yield* repo.all
186
+ expect(all).toHaveLength(1)
187
+ expect(all[0]!.updatedAt.toISOString()).toBe("2024-06-05T00:00:00.000Z")
188
+ })
189
+ .pipe(
190
+ Effect.provide(NullDocLive),
191
+ setupRequestContextFromCurrent(),
192
+ Effect.scoped,
193
+ Effect.runPromise
194
+ ))
195
+
196
+ it("jitM receives the raw JSON document, and its JSON result is what the decode consumes", () =>
197
+ Effect
198
+ .gen(function*() {
199
+ const seen: JsonRecord[] = []
200
+ const observe = (json: JsonRecord): JsonRecord => {
201
+ seen.push(json)
202
+ // returning JSON - an ISO string, not a `Date` - is what decodes
203
+ return { ...json, updatedAt: "2024-06-09T00:00:00.000Z" }
204
+ }
205
+
206
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM: observe })
207
+
208
+ const shop = Option.getOrThrow(yield* repo.find("shop-current"))
209
+
210
+ expect(seen).toHaveLength(1)
211
+ const raw = seen[0]!
212
+ // a `Date` field arrives as an ISO string
213
+ expect(typeof raw["createdAt"]).toBe("string")
214
+ expect(raw["createdAt"]).toBe("2024-06-02T00:00:00.000Z")
215
+ // a `ReadonlySet` as an array, a `ReadonlyMap` as an array of pairs
216
+ expect(raw["tags"]).toEqual(["b"])
217
+ expect(raw["meta"]).toEqual([["k2", "v2"]])
218
+ // never native Encoded values
219
+ expect(raw["createdAt"]).not.toBeInstanceOf(Date)
220
+ expect(raw["meta"]).not.toBeInstanceOf(Map)
221
+ // `_etag` is infra metadata and is not part of the document
222
+ expect("_etag" in raw).toBe(false)
223
+
224
+ // the JSON the jitM returned was decoded to the native Encoded value
225
+ expect(shop.updatedAt).toBeInstanceOf(Date)
226
+ expect(shop.updatedAt.toISOString()).toBe("2024-06-09T00:00:00.000Z")
227
+ expect(shop.meta).toBeInstanceOf(Map)
228
+ expect([...shop.meta]).toEqual([["k2", "v2"]])
229
+ })
230
+ .pipe(
231
+ Effect.provide(CurrentDocLive),
232
+ setupRequestContextFromCurrent(),
233
+ Effect.scoped,
234
+ Effect.runPromise
235
+ ))
236
+
237
+ it("defaultValues only fill absent keys, and a stored null still reaches jitM", () =>
238
+ Effect
239
+ .gen(function*() {
240
+ const seen: JsonRecord[] = []
241
+ const repo = yield* makeRepo("LegacyDocShop", Shop, {
242
+ jitM: (json) => {
243
+ seen.push(json)
244
+ return json["updatedAt"] === null ? { ...json, updatedAt: "2024-06-08T00:00:00.000Z" } : json
245
+ },
246
+ config: {
247
+ defaultValues: {
248
+ vatRate: 19,
249
+ updatedAt: new Date("2024-01-01T00:00:00.000Z")
250
+ }
251
+ }
252
+ })
253
+
254
+ const items = yield* repo.all
255
+ expect(items).toHaveLength(2)
256
+
257
+ // absent key -> filled by defaultValues
258
+ const missing = items.find((_) => _.id === "shop-legacy")!
259
+ expect(missing.vatRate).toBe(19)
260
+ // present key -> the stored value wins, even when falsy
261
+ const present = items.find((_) => _.id === "shop-zero")!
262
+ expect(present.vatRate).toBe(0)
263
+
264
+ // defaultValues are merged *before* jitM runs
265
+ const filledSeen = seen.find((_) => _["id"] === "shop-legacy")!
266
+ expect(filledSeen["vatRate"]).toBe(19)
267
+ // ...but never overwrite a key the document has
268
+ expect(filledSeen["updatedAt"]).toBe("2024-06-03T00:00:00.000Z")
269
+
270
+ // a stored explicit `null` is NOT replaced by the default: it reaches jitM
271
+ const nullSeen = seen.find((_) => _["id"] === "shop-zero")!
272
+ expect(nullSeen["updatedAt"]).toBe(null)
273
+ expect(present.updatedAt.toISOString()).toBe("2024-06-08T00:00:00.000Z")
274
+ })
275
+ .pipe(
276
+ Effect.provide(DefaultsLive),
277
+ setupRequestContextFromCurrent(),
278
+ Effect.scoped,
279
+ Effect.runPromise
280
+ ))
281
+
282
+ /**
283
+ * The store boundary decode is deliberately **strict**: `jitM` is the one and
284
+ * only place a legacy document can be repaired, and a document it does not
285
+ * repair must fail rather than be read back half-decoded. This test pins that
286
+ * behaviour down on purpose - do not "fix" it by making the decode lenient.
287
+ *
288
+ * It fails as a *typed* `S.SchemaError` in the store's error channel (it used
289
+ * to throw out of `decodeSync` as a defect), which is what lets
290
+ * `validateSample` report the document instead of losing the whole run.
291
+ */
292
+ it("a document jitM does not repair fails as a typed SchemaError at the store boundary", () =>
293
+ Effect
294
+ .gen(function*() {
295
+ const { make } = yield* StoreMaker
296
+ // `vatRate` is still missing after this jitM ran: it only touches `updatedAt`
297
+ const store = yield* make<"id", any>("LegacyDocShop", "id", undefined, {
298
+ partitionValue: () => "primary",
299
+ schema: Shop,
300
+ jitM: jitMThatDoesNotRepair
301
+ })
302
+
303
+ // `Effect.result` only catches typed failures - a defect would reject here
304
+ const result = yield* store.all.pipe(Effect.result)
305
+
306
+ expect(Result.isFailure(result)).toBe(true)
307
+ if (!Result.isFailure(result)) return
308
+ const failure = result.failure
309
+ expect(S.isSchemaError(failure)).toBe(true)
310
+ expect((failure as S.SchemaError)._tag).toBe("SchemaError")
311
+ // the strict `toCodecJson(toEncoded(schema))` decode still reports the
312
+ // key jitM failed to add, with the path to it
313
+ expect((failure as S.SchemaError).message).toContain("Missing key")
314
+ expect((failure as S.SchemaError).message).toContain("vatRate")
315
+ })
316
+ .pipe(
317
+ Effect.provide(TestLive),
318
+ setupRequestContextFromCurrent(),
319
+ Effect.scoped,
320
+ Effect.runPromise
321
+ ))
322
+
323
+ /**
324
+ * ...and the *public* repository surface is unchanged: `Repository.find`/`all`
325
+ * declare only `DatabaseError`, so the store's `SchemaError` becomes a defect
326
+ * when the public members are produced.
327
+ */
328
+ it("the same document still dies on a public repository read", () =>
329
+ Effect
330
+ .gen(function*() {
331
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM: jitMThatDoesNotRepair })
332
+
333
+ const exit = yield* repo.all.pipe(Effect.exit)
334
+ expect(Exit.isFailure(exit)).toBe(true)
335
+ if (Exit.isFailure(exit)) {
336
+ expect(Cause.hasDies(exit.cause)).toBe(true)
337
+ expect(Cause.hasFails(exit.cause)).toBe(false)
338
+ }
339
+
340
+ // a defect is not catchable as a typed failure
341
+ const notCaught = yield* repo.find("shop-legacy").pipe(Effect.result, Effect.exit)
342
+ expect(Exit.isFailure(notCaught)).toBe(true)
343
+ })
344
+ .pipe(
345
+ Effect.provide(TestLive),
346
+ setupRequestContextFromCurrent(),
347
+ Effect.scoped,
348
+ Effect.runPromise
349
+ ))
350
+
351
+ it("validateSample reports a document that fails at the store boundary and keeps going", () =>
352
+ Effect
353
+ .gen(function*() {
354
+ const repo = yield* makeRepo("LegacyDocShop", Shop, { jitM: jitMThatDoesNotRepair })
355
+
356
+ const result = yield* repo.validateSample({ percentage: 1.0 })
357
+
358
+ expect(result.total).toBe(2)
359
+ expect(result.sampled).toBe(2)
360
+ // `shop-current` decodes, `shop-legacy` does not
361
+ expect(result.valid).toBe(1)
362
+ expect(result.errors).toHaveLength(1)
363
+ const error = result.errors[0]!
364
+ expect(error.id).toBe("shop-legacy")
365
+ expect(S.isSchemaError(error.error)).toBe(true)
366
+ })
367
+ .pipe(
368
+ Effect.provide(TestLive),
369
+ setupRequestContextFromCurrent(),
370
+ Effect.scoped,
371
+ Effect.runPromise
372
+ ))
373
+
374
+ it("_etag is not visible to jitM and survives the round trip", () => {
375
+ const seen: JsonRecord[] = []
376
+ const decode = makeStoredDecode<any>(
377
+ Shop,
378
+ (json) => {
379
+ seen.push(json)
380
+ return { ...json, vatRate: 19 }
381
+ }
382
+ )
383
+
384
+ const decoded = Result.getOrThrow(decode({ ...legacyDoc, _etag: "etag-1" } as any))
385
+
386
+ // jitM sees the document without the infra metadata
387
+ expect(seen).toHaveLength(1)
388
+ expect("_etag" in seen[0]!).toBe(false)
389
+ // ...and the etag is re-attached to the decoded Encoded document
390
+ expect(decoded._etag).toBe("etag-1")
391
+ expect(decoded.vatRate).toBe(19)
392
+ expect(decoded.createdAt).toBeInstanceOf(Date)
393
+ })
394
+ })
@@ -1,12 +1,16 @@
1
1
  import { describe, expect, expectTypeOf, it } from "@effect/vitest"
2
- import { Context, Effect, Layer, Result, S } from "effect-app"
3
2
  import { NotLoggedInError, UnauthorizedError } from "effect-app/client"
3
+ import * as Context from "effect-app/Context"
4
+ import * as Effect from "effect-app/Effect"
4
5
  import { HttpHeaders } from "effect-app/http"
6
+ import * as Layer from "effect-app/Layer"
5
7
  import * as RpcX from "effect-app/rpc"
6
8
  import { MiddlewareMaker } from "effect-app/rpc"
9
+ import * as S from "effect-app/Schema"
7
10
  import type { unhandled } from "effect-app/Types"
8
- import { Rpc } from "effect/unstable/rpc"
9
- import { type SuccessValue } from "effect/unstable/rpc/RpcMiddleware"
11
+ import * as Result from "effect/Result"
12
+ import { Rpc } from "effect/rpc"
13
+ import { type SuccessValue } from "effect/rpc/RpcMiddleware"
10
14
  import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElseMiddleware, SomeElseMiddlewareLive, SomeMiddleware, SomeMiddlewareLive, SomeService, Test, TestLive } from "./fixtures.js"
11
15
 
12
16
  export class RequiresSomeMiddleware
@@ -0,0 +1,187 @@
1
+ import { type MakeContext, type MakeErrors, makeRouter } from "@effect-app/infra/routing"
2
+ import { expectTypeOf, it } from "@effect/vitest"
3
+ import { InvalidStateError, makeRpcClient, UnauthorizedError } from "effect-app/client"
4
+ import * as Context from "effect-app/Context"
5
+ import * as Effect from "effect-app/Effect"
6
+ import * as Layer from "effect-app/Layer"
7
+ import { DefaultGenericMiddlewares } from "effect-app/middleware"
8
+ import { makeAllDSL, makeOneDSL } from "effect-app/Model"
9
+ import { type FixEnv } from "effect-app/Pure"
10
+ import * as RpcX from "effect-app/rpc"
11
+ import { MiddlewareMaker } from "effect-app/rpc"
12
+ import * as S from "effect-app/Schema"
13
+ import { type TypeTestId } from "effect-app/TypeTest"
14
+ import { type ConfigError } from "effect/Config"
15
+ import { type RpcSerialization } from "effect/rpc/RpcSerialization"
16
+ import { DefaultGenericMiddlewaresLive, DevModeMiddlewareLive } from "../src/routing/middleware.js"
17
+ import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElse, SomeService, Test, TestLive } from "./fixtures.js"
18
+
19
+ // Inline minimal context provider (provides `Some`)
20
+ class CtxProvider extends RpcX.RpcMiddleware.Tag<CtxProvider, { provides: Some }>()("CtxProvider") {
21
+ static Default = Layer.make(this, {
22
+ *make() {
23
+ return Effect.fnUntraced(function*(effect) {
24
+ return yield* Effect.provideService(effect, Some, Some.of({ a: 1 }))
25
+ })
26
+ }
27
+ })
28
+ }
29
+
30
+ // Provides `SomeElse` so AllowAnonymous's requirement is met.
31
+ class SomeElseProvider extends RpcX.RpcMiddleware.Tag<SomeElseProvider, { provides: SomeElse }>()("SomeElseProvider") {
32
+ static Default = Layer.make(this, {
33
+ *make() {
34
+ return Effect.fnUntraced(function*(effect) {
35
+ return yield* Effect.provideService(effect, SomeElse, SomeElse.of({ b: 2 }))
36
+ })
37
+ }
38
+ })
39
+ }
40
+
41
+ class mw extends MiddlewareMaker
42
+ .Tag<mw>()("mw", RequestContextMap)
43
+ .middleware(RequireRoles, Test)
44
+ .middleware(AllowAnonymous)
45
+ .middleware(CtxProvider)
46
+ .middleware(...DefaultGenericMiddlewares, SomeElseProvider)
47
+ {
48
+ static Default = this.layer.pipe(
49
+ Layer.provide([
50
+ RequireRolesLive,
51
+ TestLive,
52
+ AllowAnonymousLive,
53
+ CtxProvider.Default,
54
+ SomeElseProvider.Default,
55
+ DefaultGenericMiddlewaresLive,
56
+ DevModeMiddlewareLive,
57
+ SomeService.Default
58
+ ])
59
+ )
60
+ }
61
+
62
+ const { TaggedRequestFor } = makeRpcClient(mw)
63
+ const Req = TaggedRequestFor("GenRouter")
64
+
65
+ class GetThing extends Req.Query<GetThing>()("GetThing", { id: S.String }, {
66
+ success: S.String,
67
+ error: UnauthorizedError
68
+ }) {}
69
+ class DoThing extends Req.Command<DoThing>()("DoThing", { id: S.String }, { success: S.Void }) {}
70
+
71
+ const Resource = { GetThing, DoThing }
72
+
73
+ const { Router, matchAll } = makeRouter(mw.Default)
74
+
75
+ class ThingRepo extends Context.Service<ThingRepo>()("ThingRepo", {
76
+ make: Effect.succeed({ get: (id: string) => Effect.succeed(id + "!") })
77
+ }) {
78
+ static Default = Layer.effect(this, this.make)
79
+ }
80
+
81
+ // Case under test:
82
+ // `match({})` is given handlers as **shorthand generator methods** (`*GetThing(req) { ... }`).
83
+ // tsgo (>= 7 dev) infers `TNext = unknown` for these shorthand generators while TS6 infers `never`.
84
+ // `HandlerWithInputGen` in routing.ts must accept both — see the structural fix.
85
+ const router = Router(Resource)({
86
+ dependencies: [ThingRepo.Default],
87
+ *effect(match) {
88
+ const repo = yield* ThingRepo
89
+
90
+ if (Math.random() > 0.5) return yield* new InvalidStateError("nope")
91
+
92
+ return match({
93
+ *GetThing(req) {
94
+ const some = yield* Some
95
+ if (req.id === "boom") {
96
+ return yield* Effect.fail(new UnauthorizedError())
97
+ }
98
+ return yield* repo.get(req.id + String(some.a))
99
+ },
100
+ *DoThing(_req) {
101
+ yield* Effect.succeed(1)
102
+ }
103
+ })
104
+ }
105
+ })
106
+
107
+ // Same scenario but using the `raw:` variant — exercises the `raw` path of `HandlerWithInputGen`.
108
+ const routerRaw = Router({ GetThing })({
109
+ *effect(match) {
110
+ return match({
111
+ GetThing: {
112
+ *raw(req) {
113
+ const some = yield* Some
114
+ return yield* Effect.succeed(req.id + String(some.a))
115
+ }
116
+ }
117
+ })
118
+ }
119
+ })
120
+
121
+ it("router with generator-method handlers compiles", () => {
122
+ expectTypeOf(router).toMatchTypeOf<
123
+ Layer.Layer<never, ConfigError | InvalidStateError, SomeService | RpcSerialization>
124
+ >()
125
+ expectTypeOf(routerRaw).toMatchTypeOf<Layer.Layer<never, ConfigError, SomeService | RpcSerialization>>()
126
+ })
127
+
128
+ // Type-level assertions: verify generator yields propagate to MakeErrors / MakeContext
129
+ type Errors = MakeErrors<typeof router[TypeTestId]>
130
+ type Ctx = MakeContext<typeof router[TypeTestId]>
131
+ expectTypeOf<Errors>().toEqualTypeOf<InvalidStateError>()
132
+ expectTypeOf<Ctx>().toEqualTypeOf<ThingRepo>()
133
+
134
+ const matched = matchAll({ router })
135
+ expectTypeOf(matched).toMatchTypeOf<
136
+ Layer.Layer<never, ConfigError | InvalidStateError, SomeService | RpcSerialization>
137
+ >()
138
+
139
+ // ---------------------------------------------------------------------------
140
+ // DSL R-inference regression
141
+ // ---------------------------------------------------------------------------
142
+ // `OneDSL`/`OneDSLExt.update`/`.modify` previously annotated the callback's
143
+ // effect R as `FixEnv<R, Evt, S1, S2>`. That deadlocked inference of `R`
144
+ // (TS6 → `never`, tsgo → `unknown`), causing yielded effects to leak
145
+ // `unknown` in the R slot when consumed by generator handlers.
146
+ // The fix uses bare `R` in the callback and `FixEnv<R, …>` only on the return.
147
+ class Item extends S.Class<Item>("Item")({ id: S.String, label: S.String }) {}
148
+ class Dep extends Context.Service<Dep>()("Dep", { make: Effect.succeed({ tag: "dep" as const }) }) {}
149
+
150
+ type Evt = { _tag: "Updated"; id: string }
151
+
152
+ const Items$ = makeAllDSL<Item, Evt>()
153
+ const Item$ = makeOneDSL<Item, Evt>()
154
+
155
+ // Callback body uses generator syntax (TNext = unknown under tsgo) and yields
156
+ // a service-dependent effect — R must be inferred as `Dep` (plus the
157
+ // canonical PureEnvEnv contributed by FixEnv on the return).
158
+ const oneUpdate = Item$.update((item) =>
159
+ Effect.gen(function*() {
160
+ const dep = yield* Dep
161
+ return new Item({ id: item.id, label: item.label + dep.tag })
162
+ })
163
+ )
164
+
165
+ const allUpdate = Items$.update((items) =>
166
+ Effect.gen(function*() {
167
+ const dep = yield* Dep
168
+ return items.map((_) => new Item({ id: _.id, label: _.label + dep.tag }))
169
+ })
170
+ )
171
+
172
+ const oneModify = Item$.modify((item, _dsl) =>
173
+ Effect.gen(function*() {
174
+ const dep = yield* Dep
175
+ return { ...item, tag: dep.tag }
176
+ })
177
+ )
178
+
179
+ // `R` should be `FixEnv<Dep, Evt, …>` — never collapsed to `unknown`/`never`.
180
+ // The regression manifested as `unknown` here, breaking `Dep` assignability.
181
+ expectTypeOf(oneUpdate).toMatchTypeOf<Effect.Effect<Item, never, FixEnv<Dep, Evt, Item, Item>>>()
182
+ expectTypeOf(allUpdate).toMatchTypeOf<
183
+ Effect.Effect<readonly Item[], never, FixEnv<Dep, Evt, readonly Item[], readonly Item[]>>
184
+ >()
185
+ expectTypeOf(oneModify).toMatchTypeOf<
186
+ Effect.Effect<{ tag: "dep"; id: string; label: string }, never, FixEnv<Dep, Evt, Item, Item>>
187
+ >()
@@ -0,0 +1,66 @@
1
+ import { describe, expect, it } from "@effect/vitest"
2
+ import { ConfigureInterruptibilityMiddleware } from "effect-app/middleware"
3
+ import * as S from "effect-app/Schema"
4
+ import * as Effect from "effect/Effect"
5
+ import * as Fiber from "effect/Fiber"
6
+ import * as Layer from "effect/Layer"
7
+ import * as Ref from "effect/Ref"
8
+ import { Rpc, RpcGroup, RpcTest } from "effect/rpc"
9
+ import { applyRequestTypeInterruptibility } from "../src/routing.js"
10
+ import { ConfigureInterruptibilityMiddlewareLive, RequestType } from "../src/routing/middleware.js"
11
+
12
+ const InterruptibilityRpcs = RpcGroup.make(
13
+ Rpc
14
+ .make("doCommand", { success: S.Void })
15
+ .annotate(RequestType, "command")
16
+ .middleware(ConfigureInterruptibilityMiddleware),
17
+ Rpc
18
+ .make("doQuery", { success: S.Void })
19
+ .annotate(RequestType, "query")
20
+ .middleware(ConfigureInterruptibilityMiddleware)
21
+ )
22
+
23
+ const makeImplLayer = (commandDone: Ref.Ref<boolean>, queryDone: Ref.Ref<boolean>) =>
24
+ InterruptibilityRpcs.toLayer({
25
+ doCommand: () =>
26
+ applyRequestTypeInterruptibility(
27
+ "command",
28
+ Effect.sleep("120 millis").pipe(Effect.andThen(Ref.set(commandDone, true)))
29
+ ),
30
+ doQuery: () =>
31
+ applyRequestTypeInterruptibility(
32
+ "query",
33
+ Effect.sleep("120 millis").pipe(Effect.andThen(Ref.set(queryDone, true)))
34
+ )
35
+ })
36
+
37
+ describe("routing interruptibility", () => {
38
+ it.live(
39
+ "e2e: command continues after client interrupt, query does not",
40
+ () =>
41
+ Effect.gen(function*() {
42
+ const commandDone = yield* Ref.make(false)
43
+ const queryDone = yield* Ref.make(false)
44
+
45
+ const client = yield* RpcTest
46
+ .makeClient(InterruptibilityRpcs)
47
+ .pipe(
48
+ Effect.provide(
49
+ Layer.mergeAll(makeImplLayer(commandDone, queryDone), ConfigureInterruptibilityMiddlewareLive)
50
+ )
51
+ )
52
+
53
+ const commandFiber = yield* Effect.forkDetach(client.doCommand())
54
+ yield* Effect.sleep("20 millis")
55
+ yield* Fiber.interrupt(commandFiber)
56
+ yield* Effect.sleep("180 millis")
57
+ expect(yield* Ref.get(commandDone)).toBe(true)
58
+
59
+ const queryFiber = yield* Effect.forkDetach(client.doQuery())
60
+ yield* Effect.sleep("20 millis")
61
+ yield* Fiber.interrupt(queryFiber)
62
+ yield* Effect.sleep("180 millis")
63
+ expect(yield* Ref.get(queryDone)).toBe(false)
64
+ })
65
+ )
66
+ })