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

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 +2562 -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 +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/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 +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 +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 +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 +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
@@ -0,0 +1,421 @@
1
+ /**
2
+ * E2E tests for the invalidation key flow exercised end-to-end via the
3
+ * production wrap/unwrap path:
4
+ *
5
+ * server: routing.ts wraps command success with `CommandResponseWithMetaData`
6
+ * and handler-thrown failure with `CommandFailureWithMetaData`;
7
+ * routing wraps stream values into `{_tag:"value"|"metadata"|"done"}`
8
+ * chunks. `InvalidationSet.use(...)` inside a handler accumulates keys.
9
+ * client: apiClientFactory unwraps both envelopes and forwards keys to
10
+ * `InvalidationKeysFromServer`.
11
+ *
12
+ * Transport is real HTTP (NodeHttpServer on a loopback port) so the wire
13
+ * encoding is exercised too.
14
+ */
15
+ import { NodeHttpServer } from "@effect/platform-node"
16
+ import { expect, it } from "@effect/vitest"
17
+ import { ApiClientFactory, DataDependencies, InvalidationKeysFromServer, InvalidStateError, makeInvalidationKeysService, makeRpcClient, OptimisticConcurrencyException } from "effect-app/client"
18
+ import * as Context from "effect-app/Context"
19
+ import { HttpRouter, HttpServer } from "effect-app/http"
20
+ import { DefaultGenericMiddlewares } from "effect-app/middleware"
21
+ import { makeRepo, RepositoryRegistryLive } from "effect-app/Model"
22
+ import { Invalidation, MiddlewareMaker } from "effect-app/rpc"
23
+ import * as S from "effect-app/Schema"
24
+ import { TaggedErrorClass } from "effect-app/Schema"
25
+ import * as Cause from "effect/Cause"
26
+ import * as Effect from "effect/Effect"
27
+ import * as Exit from "effect/Exit"
28
+ import * as Layer from "effect/Layer"
29
+ import * as Option from "effect/Option"
30
+ import * as Ref from "effect/Ref"
31
+ import * as Stream from "effect/Stream"
32
+ import { FetchHttpClient } from "effect/unstable/http"
33
+ import * as NetAddress from "effect/unstable/net/NetAddress"
34
+ import { RpcSerialization } from "effect/unstable/rpc"
35
+ import { createServer } from "http"
36
+ import { RequestContextMiddleware } from "../src/internal/RequestContextMiddleware.js"
37
+ import { makeRouter } from "../src/routing.js"
38
+ import { DefaultGenericMiddlewaresLive } from "../src/routing/middleware.js"
39
+ import { MemoryStoreLive } from "../src/Store/Memory.js"
40
+ import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, SomeElseMiddleware, SomeElseMiddlewareLive, SomeService, Test, TestLive } from "./fixtures.js"
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Middleware (mirrors AppMiddleware shape — same composite as other e2e tests).
44
+ // ---------------------------------------------------------------------------
45
+
46
+ class AppMiddleware extends MiddlewareMaker
47
+ .Tag<AppMiddleware>()("AppMiddleware", RequestContextMap)
48
+ .middleware(RequireRoles, Test)
49
+ .middleware(AllowAnonymous)
50
+ .middleware(SomeElseMiddleware)
51
+ .middleware(...DefaultGenericMiddlewares)
52
+ {
53
+ static Default = this.layer.pipe(
54
+ Layer.provide(
55
+ [
56
+ RequireRolesLive.pipe(Layer.provide(SomeService.Default)),
57
+ AllowAnonymousLive,
58
+ TestLive,
59
+ SomeElseMiddlewareLive,
60
+ DefaultGenericMiddlewaresLive
61
+ ] as const
62
+ )
63
+ )
64
+ }
65
+
66
+ const { Router, matchAll } = makeRouter(AppMiddleware.Default)
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Resources
70
+ // ---------------------------------------------------------------------------
71
+
72
+ const DynamicKey: Invalidation.InvalidationKey = ["dynamic", "key"]
73
+ const ExtraKey: Invalidation.InvalidationKey = ["extra", "key"]
74
+ const StreamKey: Invalidation.InvalidationKey = ["stream", "key"]
75
+
76
+ const { TaggedRequestFor } = makeRpcClient(AppMiddleware)
77
+ const Req = TaggedRequestFor("Inv")
78
+
79
+ class CmdBoom extends TaggedErrorClass<CmdBoom>()("CmdBoom", { reason: S.String }) {}
80
+
81
+ class DoNothing extends Req.Command<DoNothing>()("DoNothing", {}, {
82
+ allowAnonymous: true,
83
+ success: S.Void
84
+ }) {}
85
+
86
+ class DoWithDynamicKey extends Req.Command<DoWithDynamicKey>()("DoWithDynamicKey", {}, {
87
+ allowAnonymous: true,
88
+ success: S.String
89
+ }) {}
90
+
91
+ class DoWithBothKeys extends Req.Command<DoWithBothKeys>()("DoWithBothKeys", {}, {
92
+ allowAnonymous: true,
93
+ success: S.Number
94
+ }) {}
95
+
96
+ class DoAndFail extends Req.Command<DoAndFail>()("DoAndFail", {}, {
97
+ allowAnonymous: true,
98
+ success: S.Void,
99
+ error: CmdBoom
100
+ }) {}
101
+
102
+ class StreamWithKey extends Req.Command<StreamWithKey>()("StreamWithKey", {}, {
103
+ stream: true,
104
+ allowAnonymous: true,
105
+ success: S.Number
106
+ }) {}
107
+
108
+ class StreamWithRepoWrite extends Req.Command<StreamWithRepoWrite>()("StreamWithRepoWrite", {}, {
109
+ stream: true,
110
+ allowAnonymous: true,
111
+ success: S.Number
112
+ }) {}
113
+
114
+ class RepoItem extends S.Class<RepoItem>("RepoItem")({
115
+ id: S.String,
116
+ label: S.String
117
+ }) {}
118
+
119
+ class GetRepoCount extends Req.Query<GetRepoCount>()("GetRepoCount", {}, {
120
+ allowAnonymous: true,
121
+ success: S.Number
122
+ }) {}
123
+
124
+ class SaveRepoItem extends Req.Command<SaveRepoItem>()("SaveRepoItem", {
125
+ id: S.String,
126
+ label: S.String
127
+ }, {
128
+ allowAnonymous: true,
129
+ error: S.Union([InvalidStateError, OptimisticConcurrencyException]),
130
+ success: S.Void
131
+ }) {}
132
+
133
+ class RepoItems extends Context.Service<RepoItems>()("RepoItems", {
134
+ make: makeRepo("RepoItem", RepoItem, {})
135
+ }) {
136
+ static Default = Layer.effect(this, this.make).pipe(
137
+ Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive))
138
+ )
139
+ }
140
+
141
+ // A second, unrelated repo — its writes must NOT invalidate a query that only read `RepoItem`.
142
+ class OtherItem extends S.Class<OtherItem>("OtherItem")({
143
+ id: S.String,
144
+ label: S.String
145
+ }) {}
146
+
147
+ class SaveOtherItem extends Req.Command<SaveOtherItem>()("SaveOtherItem", {
148
+ id: S.String,
149
+ label: S.String
150
+ }, {
151
+ allowAnonymous: true,
152
+ success: S.Void
153
+ }) {}
154
+
155
+ class OtherItems extends Context.Service<OtherItems>()("OtherItems", {
156
+ make: makeRepo("OtherItem", OtherItem, {})
157
+ }) {
158
+ static Default = Layer.effect(this, this.make).pipe(
159
+ Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive))
160
+ )
161
+ }
162
+
163
+ const InvRsc = {
164
+ DoNothing,
165
+ DoWithDynamicKey,
166
+ DoWithBothKeys,
167
+ DoAndFail,
168
+ StreamWithKey,
169
+ StreamWithRepoWrite,
170
+ GetRepoCount,
171
+ SaveRepoItem,
172
+ SaveOtherItem
173
+ }
174
+
175
+ // ---------------------------------------------------------------------------
176
+ // Controllers / router
177
+ // ---------------------------------------------------------------------------
178
+
179
+ const router = Router(InvRsc)({
180
+ dependencies: [RepoItems.Default, OtherItems.Default],
181
+ *effect(match) {
182
+ const repo = yield* RepoItems
183
+ const otherRepo = yield* OtherItems
184
+ return match({
185
+ DoNothing: () => Effect.void,
186
+ DoWithDynamicKey: Effect.fnUntraced(function*() {
187
+ yield* Invalidation.InvalidationSet.use((_) => _.add(DynamicKey))
188
+ return "done"
189
+ }),
190
+ DoWithBothKeys: Effect.fnUntraced(function*() {
191
+ yield* Invalidation.InvalidationSet.use((_) => _.add(DynamicKey))
192
+ yield* Invalidation.InvalidationSet.use((_) => _.add(ExtraKey))
193
+ return 99
194
+ }),
195
+ DoAndFail: Effect.fnUntraced(function*() {
196
+ yield* Invalidation.InvalidationSet.use((_) => _.add(DynamicKey))
197
+ return yield* Effect.fail(new CmdBoom({ reason: "intentional failure" }))
198
+ }),
199
+ StreamWithKey: () =>
200
+ Stream.fromIterable([1, 2, 3]).pipe(
201
+ Stream.tap(() => Invalidation.InvalidationSet.use((_) => _.add(StreamKey)))
202
+ ),
203
+ StreamWithRepoWrite: () =>
204
+ Stream.fromIterable([1, 2, 3]).pipe(
205
+ Stream.tap((n) => repo.save(new RepoItem({ id: String(n), label: "x" })).pipe(Effect.orDie))
206
+ ),
207
+ GetRepoCount: () => repo.all.pipe(Effect.map((_) => _.length), Effect.orDie),
208
+ SaveRepoItem: ({ id, label }) => repo.save(new RepoItem({ id, label })).pipe(Effect.orDie),
209
+ SaveOtherItem: ({ id, label }) => otherRepo.save(new OtherItem({ id, label })).pipe(Effect.orDie)
210
+ })
211
+ }
212
+ })
213
+
214
+ const RpcRouterLayer = matchAll({ router })
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // HTTP wiring — fresh server on loopback per `it.live`.
218
+ // ---------------------------------------------------------------------------
219
+
220
+ const NodeServerLayer = NodeHttpServer.layer(() => createServer(), { port: 0 })
221
+
222
+ const ServerLayer = HttpRouter
223
+ .serve(RpcRouterLayer.pipe(Layer.provide(HttpRouter.middleware(RequestContextMiddleware()).layer)))
224
+ .pipe(
225
+ Layer.provide(NodeServerLayer),
226
+ Layer.provide(RpcSerialization.layerNdjson)
227
+ )
228
+
229
+ const ClientLayer = Layer
230
+ .unwrap(
231
+ Effect.gen(function*() {
232
+ const server = yield* HttpServer.HttpServer
233
+ const addr = server.address
234
+ if (NetAddress.isUnixPathAddress(addr)) {
235
+ return yield* Effect.die(new Error("expected inet address"))
236
+ }
237
+ const host = NetAddress.isUnspecified(addr.address) ? "127.0.0.1" : NetAddress.formatUrlHost(addr.address)
238
+ const url = `http://${host}:${addr.port}`
239
+ return ApiClientFactory
240
+ .layer({ url, headers: Option.none() })
241
+ .pipe(Layer.provide(FetchHttpClient.layer))
242
+ })
243
+ )
244
+ .pipe(Layer.provide(NodeServerLayer))
245
+
246
+ const TestLayer = Layer.mergeAll(ServerLayer, ClientLayer)
247
+
248
+ // Helper: provide a fresh `InvalidationKeysFromServer` and capture forwarded keys.
249
+ const withCapture = <A, E, R>(eff: Effect.Effect<A, E, R>) =>
250
+ Effect.gen(function*() {
251
+ const ref = yield* Ref.make<ReadonlyArray<Invalidation.InvalidationKey>>([])
252
+ const svc = makeInvalidationKeysService(ref)
253
+ const result = yield* eff.pipe(Effect.provideService(InvalidationKeysFromServer, svc), Effect.exit)
254
+ return { result, keys: yield* Ref.get(ref) }
255
+ })
256
+
257
+ const withDependencyCapture = <A, E, R>(eff: Effect.Effect<A, E, R>) =>
258
+ Effect.gen(function*() {
259
+ const readsRef = yield* Ref.make(DataDependencies.empty())
260
+ const writesRef = yield* Ref.make(DataDependencies.empty())
261
+ const svc = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
262
+ const result = yield* eff.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, svc), Effect.exit)
263
+ return { result, dependencies: yield* svc.get }
264
+ })
265
+
266
+ // ---------------------------------------------------------------------------
267
+ // Tests
268
+ // ---------------------------------------------------------------------------
269
+
270
+ it.live(
271
+ "command with no invalidation keys: caller sees raw payload, no keys forwarded",
272
+ Effect.fnUntraced(function*() {
273
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
274
+ const { result, keys } = yield* withCapture(client.DoNothing.handler())
275
+ expect(Exit.isSuccess(result)).toBe(true)
276
+ expect(keys).toStrictEqual([])
277
+ }, Effect.provide(TestLayer)),
278
+ { timeout: 10_000 }
279
+ )
280
+
281
+ it.live(
282
+ "command with dynamic InvalidationSet.use: payload + key forwarded",
283
+ Effect.fnUntraced(function*() {
284
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
285
+ const { result, keys } = yield* withCapture(client.DoWithDynamicKey.handler())
286
+ expect(Exit.isSuccess(result) && result.value).toBe("done")
287
+ expect(keys).toStrictEqual([DynamicKey])
288
+ }, Effect.provide(TestLayer)),
289
+ { timeout: 10_000 }
290
+ )
291
+
292
+ it.live(
293
+ "command accumulating multiple dynamic keys: all keys forwarded in order",
294
+ Effect.fnUntraced(function*() {
295
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
296
+ const { result, keys } = yield* withCapture(client.DoWithBothKeys.handler())
297
+ expect(Exit.isSuccess(result) && result.value).toBe(99)
298
+ expect(keys).toStrictEqual([DynamicKey, ExtraKey])
299
+ }, Effect.provide(TestLayer)),
300
+ { timeout: 10_000 }
301
+ )
302
+
303
+ it.live(
304
+ "per-request isolation: each command call starts with a fresh InvalidationSet",
305
+ Effect.fnUntraced(function*() {
306
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
307
+ const r1 = yield* withCapture(client.DoWithDynamicKey.handler())
308
+ const r2 = yield* withCapture(client.DoWithDynamicKey.handler())
309
+ // Each call must have exactly one key — no accumulation across calls
310
+ expect(r1.keys).toStrictEqual([DynamicKey])
311
+ expect(r2.keys).toStrictEqual([DynamicKey])
312
+ }, Effect.provide(TestLayer)),
313
+ { timeout: 10_000 }
314
+ )
315
+
316
+ it.live(
317
+ "command failure (V2): keys accumulated before fail still reach the client; original error re-thrown",
318
+ Effect.fnUntraced(function*() {
319
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
320
+ const { result, keys } = yield* withCapture(client.DoAndFail.handler())
321
+ expect(Exit.isFailure(result)).toBe(true)
322
+ if (Exit.isFailure(result)) {
323
+ const error = Cause.findErrorOption(result.cause)
324
+ expect(Option.isSome(error)).toBe(true)
325
+ if (Option.isSome(error)) {
326
+ expect(error.value._tag).toBe("CmdBoom")
327
+ expect(error.value.reason).toBe("intentional failure")
328
+ }
329
+ }
330
+ expect(keys).toStrictEqual([DynamicKey])
331
+ }, Effect.provide(TestLayer)),
332
+ { timeout: 10_000 }
333
+ )
334
+
335
+ it.live(
336
+ "stream: per-chunk metadata accumulates distinct keys",
337
+ Effect.fnUntraced(function*() {
338
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
339
+ const ref = yield* Ref.make<ReadonlyArray<Invalidation.InvalidationKey>>([])
340
+ const svc = makeInvalidationKeysService(ref)
341
+ const values = yield* Stream.runCollect(client.StreamWithKey.handler()).pipe(
342
+ Effect.provideService(InvalidationKeysFromServer, svc)
343
+ )
344
+ const keys = yield* Ref.get(ref)
345
+ expect(values).toStrictEqual([1, 2, 3])
346
+ expect(keys).toStrictEqual([StreamKey])
347
+ }, Effect.provide(TestLayer)),
348
+ { timeout: 10_000 }
349
+ )
350
+
351
+ it.live(
352
+ "stream: per-chunk repo writes are drained and forwarded to the client recorder",
353
+ Effect.fnUntraced(function*() {
354
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
355
+ const readsRef = yield* Ref.make(DataDependencies.empty())
356
+ const writesRef = yield* Ref.make(DataDependencies.empty())
357
+ const svc = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
358
+ const values = yield* Stream.runCollect(client.StreamWithRepoWrite.handler()).pipe(
359
+ Effect.provideService(DataDependencies.DataDependencyRecorder, svc)
360
+ )
361
+ const writes = yield* Ref.get(writesRef)
362
+ expect(values).toStrictEqual([1, 2, 3])
363
+ // Each emitted value writes to RepoItem; routing drains the writes per chunk and the client
364
+ // accumulates their entity ids into one dependency.
365
+ expect(writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem", ["1", "2", "3"])]))
366
+ }, Effect.provide(TestLayer)),
367
+ { timeout: 10_000 }
368
+ )
369
+
370
+ it.live(
371
+ "repository dependencies flow through query and command metadata",
372
+ Effect.fnUntraced(function*() {
373
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
374
+
375
+ const query = yield* withDependencyCapture(client.GetRepoCount.handler())
376
+ expect(Exit.isSuccess(query.result) && query.result.value).toBe(0)
377
+ expect(query.dependencies.reads).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
378
+ expect(query.dependencies.writes).toStrictEqual(DataDependencies.empty())
379
+
380
+ const command = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
381
+ expect(Exit.isSuccess(command.result)).toBe(true)
382
+ expect(command.dependencies.reads).toStrictEqual(DataDependencies.empty())
383
+ expect(command.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem", ["1"])]))
384
+ }, Effect.provide(TestLayer)),
385
+ { timeout: 10_000 }
386
+ )
387
+
388
+ it.live(
389
+ "query invalidation: a command's writes invalidate exactly the queries whose reads intersect",
390
+ Effect.fnUntraced(function*() {
391
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
392
+
393
+ // Client-side query registry: queryKey -> read dependencies forwarded by the server. Mirrors
394
+ // @effect-app/vue's `dependencyMetadata`; the derivation predicate (`intersects`) is the exact
395
+ // one the vue mutate engine uses to pick invalidation targets from a command's writes.
396
+ const queryReads = new Map<string, DataDependencies.DataDependencies>()
397
+ const invalidatedBy = (writes: DataDependencies.DataDependencies) =>
398
+ [...queryReads]
399
+ .filter(([, reads]) => DataDependencies.intersects(reads, writes))
400
+ .map(([key]) => key)
401
+
402
+ // Run the query through the real client; register its forwarded reads under its key.
403
+ const query = yield* withDependencyCapture(client.GetRepoCount.handler())
404
+ expect(Exit.isSuccess(query.result)).toBe(true)
405
+ queryReads.set("GetRepoCount", query.dependencies.reads)
406
+ // Before any command, nothing is invalidated.
407
+ expect(invalidatedBy(DataDependencies.empty())).toStrictEqual([])
408
+
409
+ // A command writing the SAME repo the query read => the query is selected for invalidation.
410
+ const save = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
411
+ expect(Exit.isSuccess(save.result)).toBe(true)
412
+ expect(invalidatedBy(save.dependencies.writes)).toStrictEqual(["GetRepoCount"])
413
+
414
+ // A command writing an UNRELATED repo => the query is NOT invalidated (negative control).
415
+ const saveOther = yield* withDependencyCapture(client.SaveOtherItem.handler({ id: "2", label: "two" }))
416
+ expect(Exit.isSuccess(saveOther.result)).toBe(true)
417
+ expect(saveOther.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("OtherItem", ["2"])]))
418
+ expect(invalidatedBy(saveOther.dependencies.writes)).toStrictEqual([])
419
+ }, Effect.provide(TestLayer)),
420
+ { timeout: 10_000 }
421
+ )
@@ -1,19 +1,24 @@
1
1
  import { NodeHttpServer } from "@effect/platform-node"
2
2
  import { expect, expectTypeOf, it } from "@effect/vitest"
3
- import { Console, Effect, Layer, Result } from "effect"
4
- import { S } from "effect-app"
5
3
  import { NotLoggedInError } from "effect-app/client"
4
+ import * as Context from "effect-app/Context"
6
5
  import { HttpRouter } from "effect-app/http"
7
6
  import { DefaultGenericMiddlewares } from "effect-app/middleware"
8
- import { MiddlewareMaker } from "effect-app/rpc"
9
- import { middlewareGroup } from "effect-app/rpc/MiddlewareMaker"
7
+ import * as RpcX from "effect-app/rpc"
8
+ import * as S from "effect-app/Schema"
9
+ import * as Console from "effect/Console"
10
+ import * as Effect from "effect/Effect"
11
+ import * as Layer from "effect/Layer"
12
+ import * as Ref from "effect/Ref"
13
+ import * as Result from "effect/Result"
10
14
  import { FetchHttpClient } from "effect/unstable/http"
11
- import { RpcClient, RpcGroup, RpcSerialization, RpcServer, RpcTest } from "effect/unstable/rpc"
15
+ import { Rpc, RpcClient, RpcGroup, RpcSerialization, RpcServer, RpcTest } from "effect/unstable/rpc"
12
16
  import { createServer } from "http"
13
- import { DefaultGenericMiddlewaresLive } from "../src/api/routing.js"
17
+ import { DefaultGenericMiddlewaresLive } from "../src/routing.js"
14
18
  import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElseMiddleware, SomeElseMiddlewareLive, SomeMiddleware, SomeMiddlewareLive, SomeService, Test, TestLive, UserProfile } from "./fixtures.js"
15
19
 
16
- const incomplete = MiddlewareMaker
20
+ const incomplete = RpcX
21
+ .MiddlewareMaker
17
22
  .Tag<middleware>()("MiddlewareMaker", RequestContextMap)
18
23
  .middleware(RequireRoles)
19
24
  .middleware(AllowAnonymous, Test)
@@ -21,7 +26,8 @@ const incomplete = MiddlewareMaker
21
26
  // this extension is allowed otherwise the error is quite obscure
22
27
  export class incompleteMiddleware extends incomplete {}
23
28
 
24
- class middleware extends MiddlewareMaker
29
+ class middleware extends RpcX
30
+ .MiddlewareMaker
25
31
  .Tag<middleware>()("MiddlewareMaker", RequestContextMap)
26
32
  .middleware(RequireRoles)
27
33
  .middleware(AllowAnonymous, Test)
@@ -29,7 +35,7 @@ class middleware extends MiddlewareMaker
29
35
  .middleware(...DefaultGenericMiddlewares)
30
36
  {}
31
37
 
32
- const UserRpcs = middlewareGroup(middleware)(
38
+ const UserRpcs = RpcX.MiddlewareMaker.middlewareGroup(middleware)(
33
39
  RpcGroup.make(
34
40
  middleware.rpc("getUser", {
35
41
  success: S.Literal("awesome")
@@ -56,7 +62,7 @@ const impl = UserRpcs
56
62
 
57
63
  expectTypeOf<Layer.Services<typeof impl>>().toEqualTypeOf<never>()
58
64
 
59
- const UserRpcsBad = middlewareGroup(middleware)(
65
+ const UserRpcsBad = RpcX.MiddlewareMaker.middlewareGroup(middleware)(
60
66
  RpcGroup.make(
61
67
  middleware.rpc("doSomethingElse", {
62
68
  success: S.Literal("also-awesome2"),
@@ -136,3 +142,72 @@ it.live(
136
142
  Effect.provide(RpcTestLayer)
137
143
  )
138
144
  )
145
+
146
+ // Per-request service isolation test
147
+
148
+ class PerRequestCounter extends Context.Service<PerRequestCounter>()(
149
+ "PerRequestCounter",
150
+ { make: Effect.sync(() => ({ a: 0 })) }
151
+ ) {
152
+ static Default = Layer.effect(this, this.make)
153
+ }
154
+
155
+ class GlobalCounter extends Context.Service<GlobalCounter, {
156
+ readonly ref: Ref.Ref<number>
157
+ }>()("GlobalCounter") {}
158
+
159
+ const CounterRpcs = RpcGroup.make(
160
+ Rpc.make("incrementA", {
161
+ success: S.Number
162
+ }),
163
+ Rpc.make("incrementB", {
164
+ success: S.Number
165
+ })
166
+ )
167
+
168
+ const counterImpl = CounterRpcs
169
+ .toLayer({
170
+ incrementA: Effect.fn(function*() {
171
+ const counter = yield* PerRequestCounter
172
+ counter.a++
173
+ const global = yield* GlobalCounter
174
+ yield* Ref.update(global.ref, (n) => n + 1)
175
+ return counter.a
176
+ }, Effect.provide(PerRequestCounter.Default)),
177
+ incrementB: Effect.fn(function*() {
178
+ const counter = yield* PerRequestCounter
179
+ counter.a++
180
+ const global = yield* GlobalCounter
181
+ yield* Ref.update(global.ref, (n) => n + 1)
182
+ return counter.a
183
+ }, Effect.provide(PerRequestCounter.Default))
184
+ })
185
+
186
+ const GlobalCounterLive = Layer.effect(
187
+ GlobalCounter,
188
+ Ref.make(0).pipe(Effect.map((ref) => ({ ref })))
189
+ )
190
+
191
+ const CounterTestLayer = counterImpl.pipe(Layer.provideMerge(GlobalCounterLive))
192
+
193
+ it.live(
194
+ "per-request service isolation with shared global counter",
195
+ Effect.fnUntraced(
196
+ function*() {
197
+ const client = yield* RpcTest.makeClient(CounterRpcs)
198
+ const global = yield* GlobalCounter
199
+
200
+ const r1 = yield* client.incrementA()
201
+ const r2 = yield* client.incrementB()
202
+
203
+ // per-request counter is fresh each time → both return 1
204
+ expect(r1).toBe(1)
205
+ expect(r2).toBe(1)
206
+
207
+ // global counter is shared across requests → accumulates to 2
208
+ const globalCount = yield* Ref.get(global.ref)
209
+ expect(globalCount).toBe(2)
210
+ },
211
+ Effect.provide(CounterTestLayer)
212
+ )
213
+ )