@effect-app/infra 4.0.0-beta.29 → 4.0.0-beta.290

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 (473) hide show
  1. package/CHANGELOG.md +2211 -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 +35 -14
  6. package/dist/ClusterCosmos.d.ts +64 -0
  7. package/dist/ClusterCosmos.d.ts.map +1 -0
  8. package/dist/ClusterCosmos.js +547 -0
  9. package/dist/ClusterServiceBus.d.ts +67 -0
  10. package/dist/ClusterServiceBus.d.ts.map +1 -0
  11. package/dist/ClusterServiceBus.js +82 -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 +14 -3
  33. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  34. package/dist/Store/Cosmos/query.js +179 -41
  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 +385 -254
  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 +79 -39
  41. package/dist/Store/Memory.d.ts +5 -9
  42. package/dist/Store/Memory.d.ts.map +1 -1
  43. package/dist/Store/Memory.js +324 -67
  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 +232 -0
  47. package/dist/Store/SQL/query.d.ts +49 -0
  48. package/dist/Store/SQL/query.d.ts.map +1 -0
  49. package/dist/Store/SQL/query.js +527 -0
  50. package/dist/Store/SQL.d.ts +21 -0
  51. package/dist/Store/SQL.d.ts.map +1 -0
  52. package/dist/Store/SQL.js +456 -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 +6 -4
  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/utils.d.ts +5 -2
  60. package/dist/Store/utils.d.ts.map +1 -1
  61. package/dist/Store/utils.js +9 -5
  62. package/dist/WorkflowEngineCosmos.d.ts +29 -0
  63. package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
  64. package/dist/WorkflowEngineCosmos.js +542 -0
  65. package/dist/WorkflowEngineSqlite.d.ts +24 -0
  66. package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
  67. package/dist/WorkflowEngineSqlite.js +550 -0
  68. package/dist/arbs.d.ts +1 -1
  69. package/dist/arbs.d.ts.map +1 -1
  70. package/dist/arbs.js +5 -3
  71. package/dist/codec.d.ts.map +1 -0
  72. package/dist/codec.js +5 -0
  73. package/dist/{adapters/cosmos-client.d.ts → cosmos-client.d.ts} +4 -2
  74. package/dist/cosmos-client.d.ts.map +1 -0
  75. package/dist/cosmos-client.js +11 -0
  76. package/dist/errorReporter.d.ts +6 -4
  77. package/dist/errorReporter.d.ts.map +1 -1
  78. package/dist/errorReporter.js +23 -27
  79. package/dist/fileUtil.d.ts +1 -1
  80. package/dist/fileUtil.d.ts.map +1 -1
  81. package/dist/fileUtil.js +2 -2
  82. package/dist/index.d.ts +2 -1
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +3 -2
  85. package/dist/internal/RequestContextMiddleware.d.ts +5 -0
  86. package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
  87. package/dist/internal/RequestContextMiddleware.js +45 -0
  88. package/dist/internal/auth.d.ts +53 -0
  89. package/dist/internal/auth.d.ts.map +1 -0
  90. package/dist/internal/auth.js +180 -0
  91. package/dist/internal/events.d.ts +11 -0
  92. package/dist/internal/events.d.ts.map +1 -0
  93. package/dist/internal/events.js +49 -0
  94. package/dist/internal/health.d.ts.map +1 -0
  95. package/dist/internal/health.js +5 -0
  96. package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +14 -6
  97. package/dist/layerUtils.d.ts.map +1 -0
  98. package/dist/layerUtils.js +17 -0
  99. package/dist/logger/jsonLogger.d.ts +1 -1
  100. package/dist/logger/jsonLogger.d.ts.map +1 -1
  101. package/dist/logger/jsonLogger.js +5 -3
  102. package/dist/logger/logFmtLogger.d.ts +1 -1
  103. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  104. package/dist/logger/logFmtLogger.js +3 -3
  105. package/dist/logger/shared.d.ts +2 -2
  106. package/dist/logger/shared.d.ts.map +1 -1
  107. package/dist/logger/shared.js +5 -5
  108. package/dist/logger.d.ts +4 -4
  109. package/dist/logger.d.ts.map +1 -1
  110. package/dist/middlewares.d.ts.map +1 -0
  111. package/dist/{api/middlewares.js → middlewares.js} +1 -1
  112. package/dist/{adapters/mongo-client.d.ts → mongo-client.d.ts} +3 -2
  113. package/dist/mongo-client.d.ts.map +1 -0
  114. package/dist/mongo-client.js +15 -0
  115. package/dist/otel.d.ts +75 -0
  116. package/dist/otel.d.ts.map +1 -0
  117. package/dist/otel.js +65 -0
  118. package/dist/rateLimit.d.ts +11 -3
  119. package/dist/rateLimit.d.ts.map +1 -1
  120. package/dist/rateLimit.js +7 -12
  121. package/dist/{adapters/redis-client.d.ts → redis-client.d.ts} +5 -2
  122. package/dist/redis-client.d.ts.map +1 -0
  123. package/dist/redis-client.js +98 -0
  124. package/dist/{api/reportError.d.ts → reportError.d.ts} +1 -1
  125. package/dist/reportError.d.ts.map +1 -0
  126. package/dist/reportError.js +28 -0
  127. package/dist/{api/routing → routing}/middleware/RouterMiddleware.d.ts +4 -3
  128. package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
  129. package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
  130. package/dist/routing/middleware/middleware.d.ts +48 -0
  131. package/dist/routing/middleware/middleware.d.ts.map +1 -0
  132. package/dist/routing/middleware/middleware.js +128 -0
  133. package/dist/{api/routing → routing}/middleware.d.ts +0 -1
  134. package/dist/routing/middleware.d.ts.map +1 -0
  135. package/dist/{api/routing → routing}/middleware.js +1 -2
  136. package/dist/routing/schema/jwt.d.ts.map +1 -0
  137. package/dist/routing/schema/jwt.js +13 -0
  138. package/dist/routing/tsort.d.ts.map +1 -0
  139. package/dist/routing/tsort.js +51 -0
  140. package/dist/{api/routing → routing}/utils.d.ts +3 -3
  141. package/dist/routing/utils.d.ts.map +1 -0
  142. package/dist/routing/utils.js +45 -0
  143. package/dist/routing.d.ts +182 -0
  144. package/dist/routing.d.ts.map +1 -0
  145. package/dist/routing.js +256 -0
  146. package/dist/test.d.ts +2 -2
  147. package/dist/test.d.ts.map +1 -1
  148. package/dist/test.js +2 -2
  149. package/dist/util.d.ts.map +1 -0
  150. package/dist/util.js +14 -0
  151. package/docs/cluster-storage.md +26 -0
  152. package/docs/workflow-engine.md +262 -0
  153. package/examples/query.ts +47 -39
  154. package/package.json +33 -352
  155. package/src/CUPS.ts +53 -14
  156. package/src/ClusterCosmos.ts +1118 -0
  157. package/src/ClusterServiceBus.ts +242 -0
  158. package/src/{api/ContextProvider.ts → ContextProvider.ts} +20 -17
  159. package/src/Emailer/Sendgrid.ts +83 -60
  160. package/src/Emailer/fake.ts +4 -4
  161. package/src/MainFiberSet.ts +32 -13
  162. package/src/QueueMaker/errors.ts +3 -1
  163. package/src/{adapters/SQL → SQL}/Model.ts +42 -41
  164. package/src/SQL.ts +1 -0
  165. package/src/Store/Cosmos/query.ts +218 -54
  166. package/src/Store/Cosmos.ts +529 -365
  167. package/src/Store/Disk.ts +112 -70
  168. package/src/Store/Memory.ts +365 -99
  169. package/src/Store/SQL/Pg.ts +363 -0
  170. package/src/Store/SQL/query.ts +603 -0
  171. package/src/Store/SQL.ts +746 -0
  172. package/src/Store/codeFilter.ts +8 -6
  173. package/src/Store/index.ts +25 -10
  174. package/src/Store/utils.ts +32 -25
  175. package/src/WorkflowEngineCosmos.ts +749 -0
  176. package/src/WorkflowEngineSqlite.ts +813 -0
  177. package/src/arbs.ts +5 -3
  178. package/src/{adapters/cosmos-client.ts → cosmos-client.ts} +5 -3
  179. package/src/errorReporter.ts +68 -78
  180. package/src/fileUtil.ts +1 -1
  181. package/src/index.ts +2 -1
  182. package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
  183. package/src/internal/auth.ts +272 -0
  184. package/src/{api/internal → internal}/events.ts +22 -13
  185. package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
  186. package/src/logger/jsonLogger.ts +5 -3
  187. package/src/logger/logFmtLogger.ts +3 -3
  188. package/src/logger/shared.ts +5 -4
  189. package/src/middlewares.ts +10 -0
  190. package/src/{adapters/mongo-client.ts → mongo-client.ts} +4 -2
  191. package/src/otel.ts +152 -0
  192. package/src/rateLimit.ts +34 -23
  193. package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
  194. package/src/{api/reportError.ts → reportError.ts} +3 -2
  195. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
  196. package/src/{api/routing → routing}/middleware/middleware.ts +62 -17
  197. package/src/routing/middleware.ts +4 -0
  198. package/src/{api/routing → routing}/schema/jwt.ts +2 -1
  199. package/src/{api/routing → routing}/utils.ts +2 -1
  200. package/src/routing.ts +823 -0
  201. package/src/test.ts +4 -4
  202. package/src/vitest.ts +1 -1
  203. package/test/auth.test.ts +101 -0
  204. package/test/cluster-cosmos.test.ts +612 -0
  205. package/test/cluster-servicebus.test.ts +180 -0
  206. package/test/cluster-sqlite.test.ts +205 -0
  207. package/test/contextProvider.test.ts +15 -12
  208. package/test/controller.test.ts +28 -32
  209. package/test/cosmos-query.test.ts +159 -0
  210. package/test/dist/auth.test.d.ts.map +1 -0
  211. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  212. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  213. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  214. package/test/dist/contextProvider.test.d.ts.map +1 -1
  215. package/test/dist/controller.test.d.ts.map +1 -1
  216. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  217. package/test/dist/fixtures.d.ts +29 -11
  218. package/test/dist/fixtures.d.ts.map +1 -1
  219. package/test/dist/fixtures.js +17 -10
  220. package/test/dist/query.test.d.ts.map +1 -1
  221. package/test/dist/rawQuery.test.d.ts.map +1 -1
  222. package/test/dist/repository-ext.test.d.ts.map +1 -0
  223. package/test/dist/requires.test.d.ts.map +1 -1
  224. package/test/dist/router-generator.test.d.ts.map +1 -0
  225. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  226. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  227. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  228. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  229. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  230. package/test/dist/sql-store.test.d.ts.map +1 -0
  231. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  232. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  233. package/test/fixtures.ts +16 -9
  234. package/test/layerUtils.test.ts +2 -2
  235. package/test/query.test.ts +905 -40
  236. package/test/rawQuery.test.ts +340 -22
  237. package/test/repository-ext.test.ts +178 -0
  238. package/test/requires.test.ts +10 -5
  239. package/test/router-generator.test.ts +187 -0
  240. package/test/routing-interruptibility.test.ts +66 -0
  241. package/test/rpc-context-map-streaming.test.ts +262 -0
  242. package/test/rpc-e2e-invalidation.test.ts +420 -0
  243. package/test/rpc-multi-middleware.test.ts +85 -10
  244. package/test/rpc-stream-fullstack.test.ts +304 -0
  245. package/test/sql-store.test.ts +1711 -0
  246. package/test/validateSample.test.ts +26 -14
  247. package/test/workflow-engine-cosmos.test.ts +345 -0
  248. package/test/workflow-engine-sqlite.test.ts +297 -0
  249. package/tsconfig.examples.json +1 -1
  250. package/tsconfig.json +3 -1
  251. package/tsconfig.src.json +35 -35
  252. package/tsconfig.test.json +2 -2
  253. package/dist/Emailer/service.d.ts +0 -55
  254. package/dist/Emailer/service.d.ts.map +0 -1
  255. package/dist/Emailer/service.js +0 -6
  256. package/dist/Emailer.d.ts +0 -2
  257. package/dist/Emailer.d.ts.map +0 -1
  258. package/dist/Emailer.js +0 -2
  259. package/dist/Model/Repository/ext.d.ts +0 -41
  260. package/dist/Model/Repository/ext.d.ts.map +0 -1
  261. package/dist/Model/Repository/ext.js +0 -65
  262. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  263. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  264. package/dist/Model/Repository/internal/internal.js +0 -316
  265. package/dist/Model/Repository/legacy.d.ts +0 -19
  266. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  267. package/dist/Model/Repository/legacy.js +0 -2
  268. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  269. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  270. package/dist/Model/Repository/makeRepo.js +0 -24
  271. package/dist/Model/Repository/service.d.ts +0 -89
  272. package/dist/Model/Repository/service.d.ts.map +0 -1
  273. package/dist/Model/Repository/service.js +0 -2
  274. package/dist/Model/Repository/validation.d.ts +0 -42
  275. package/dist/Model/Repository/validation.d.ts.map +0 -1
  276. package/dist/Model/Repository/validation.js +0 -32
  277. package/dist/Model/Repository.d.ts +0 -6
  278. package/dist/Model/Repository.d.ts.map +0 -1
  279. package/dist/Model/Repository.js +0 -6
  280. package/dist/Model/dsl.d.ts +0 -32
  281. package/dist/Model/dsl.d.ts.map +0 -1
  282. package/dist/Model/dsl.js +0 -44
  283. package/dist/Model/filter/filterApi.d.ts +0 -30
  284. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  285. package/dist/Model/filter/filterApi.js +0 -2
  286. package/dist/Model/filter/types/errors.d.ts +0 -29
  287. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  288. package/dist/Model/filter/types/errors.js +0 -2
  289. package/dist/Model/filter/types/fields.d.ts +0 -15
  290. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  291. package/dist/Model/filter/types/fields.js +0 -2
  292. package/dist/Model/filter/types/path/common.d.ts +0 -316
  293. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  294. package/dist/Model/filter/types/path/common.js +0 -2
  295. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  296. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  297. package/dist/Model/filter/types/path/eager.js +0 -31
  298. package/dist/Model/filter/types/path/index.d.ts +0 -4
  299. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  300. package/dist/Model/filter/types/path/index.js +0 -3
  301. package/dist/Model/filter/types/utils.d.ts +0 -79
  302. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  303. package/dist/Model/filter/types/utils.js +0 -2
  304. package/dist/Model/filter/types/validator.d.ts +0 -30
  305. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  306. package/dist/Model/filter/types/validator.js +0 -2
  307. package/dist/Model/filter/types.d.ts +0 -5
  308. package/dist/Model/filter/types.d.ts.map +0 -1
  309. package/dist/Model/filter/types.js +0 -7
  310. package/dist/Model/query/dsl.d.ts +0 -248
  311. package/dist/Model/query/dsl.d.ts.map +0 -1
  312. package/dist/Model/query/dsl.js +0 -104
  313. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  314. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  315. package/dist/Model/query/new-kid-interpreter.js +0 -165
  316. package/dist/Model/query.d.ts +0 -15
  317. package/dist/Model/query.d.ts.map +0 -1
  318. package/dist/Model/query.js +0 -3
  319. package/dist/Model.d.ts +0 -4
  320. package/dist/Model.d.ts.map +0 -1
  321. package/dist/Model.js +0 -4
  322. package/dist/Operations.d.ts +0 -55
  323. package/dist/Operations.d.ts.map +0 -1
  324. package/dist/Operations.js +0 -102
  325. package/dist/OperationsRepo.d.ts +0 -41
  326. package/dist/OperationsRepo.d.ts.map +0 -1
  327. package/dist/OperationsRepo.js +0 -14
  328. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  329. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  330. package/dist/QueueMaker/SQLQueue.js +0 -130
  331. package/dist/QueueMaker/memQueue.d.ts +0 -11
  332. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  333. package/dist/QueueMaker/memQueue.js +0 -76
  334. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  335. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  336. package/dist/QueueMaker/sbqueue.js +0 -91
  337. package/dist/QueueMaker/service.d.ts +0 -11
  338. package/dist/QueueMaker/service.d.ts.map +0 -1
  339. package/dist/QueueMaker/service.js +0 -4
  340. package/dist/RequestContext.d.ts +0 -63
  341. package/dist/RequestContext.d.ts.map +0 -1
  342. package/dist/RequestContext.js +0 -49
  343. package/dist/RequestFiberSet.d.ts +0 -36
  344. package/dist/RequestFiberSet.d.ts.map +0 -1
  345. package/dist/RequestFiberSet.js +0 -78
  346. package/dist/Store/ContextMapContainer.d.ts +0 -14
  347. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  348. package/dist/Store/ContextMapContainer.js +0 -16
  349. package/dist/Store/service.d.ts +0 -108
  350. package/dist/Store/service.d.ts.map +0 -1
  351. package/dist/Store/service.js +0 -71
  352. package/dist/Store.d.ts +0 -2
  353. package/dist/Store.d.ts.map +0 -1
  354. package/dist/Store.js +0 -2
  355. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  356. package/dist/adapters/SQL/Model.js +0 -478
  357. package/dist/adapters/SQL.d.ts.map +0 -1
  358. package/dist/adapters/ServiceBus.d.ts +0 -58
  359. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  360. package/dist/adapters/ServiceBus.js +0 -99
  361. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  362. package/dist/adapters/cosmos-client.js +0 -9
  363. package/dist/adapters/index.d.ts +0 -2
  364. package/dist/adapters/index.d.ts.map +0 -1
  365. package/dist/adapters/index.js +0 -2
  366. package/dist/adapters/logger.d.ts +0 -9
  367. package/dist/adapters/logger.d.ts.map +0 -1
  368. package/dist/adapters/logger.js +0 -3
  369. package/dist/adapters/memQueue.d.ts +0 -13
  370. package/dist/adapters/memQueue.d.ts.map +0 -1
  371. package/dist/adapters/memQueue.js +0 -20
  372. package/dist/adapters/mongo-client.d.ts.map +0 -1
  373. package/dist/adapters/mongo-client.js +0 -13
  374. package/dist/adapters/redis-client.d.ts.map +0 -1
  375. package/dist/adapters/redis-client.js +0 -94
  376. package/dist/api/ContextProvider.d.ts +0 -31
  377. package/dist/api/ContextProvider.d.ts.map +0 -1
  378. package/dist/api/ContextProvider.js +0 -38
  379. package/dist/api/codec.d.ts.map +0 -1
  380. package/dist/api/codec.js +0 -5
  381. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  382. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  383. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  384. package/dist/api/internal/auth.d.ts +0 -15
  385. package/dist/api/internal/auth.d.ts.map +0 -1
  386. package/dist/api/internal/auth.js +0 -47
  387. package/dist/api/internal/events.d.ts +0 -9
  388. package/dist/api/internal/events.d.ts.map +0 -1
  389. package/dist/api/internal/events.js +0 -42
  390. package/dist/api/internal/health.d.ts.map +0 -1
  391. package/dist/api/internal/health.js +0 -5
  392. package/dist/api/layerUtils.d.ts.map +0 -1
  393. package/dist/api/layerUtils.js +0 -16
  394. package/dist/api/middlewares.d.ts.map +0 -1
  395. package/dist/api/reportError.d.ts.map +0 -1
  396. package/dist/api/reportError.js +0 -27
  397. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  398. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  399. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  400. package/dist/api/routing/middleware/middleware.js +0 -92
  401. package/dist/api/routing/middleware.d.ts.map +0 -1
  402. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  403. package/dist/api/routing/schema/jwt.js +0 -12
  404. package/dist/api/routing/tsort.d.ts.map +0 -1
  405. package/dist/api/routing/tsort.js +0 -51
  406. package/dist/api/routing/utils.d.ts.map +0 -1
  407. package/dist/api/routing/utils.js +0 -44
  408. package/dist/api/routing.d.ts +0 -138
  409. package/dist/api/routing.d.ts.map +0 -1
  410. package/dist/api/routing.js +0 -166
  411. package/dist/api/setupRequest.d.ts +0 -12
  412. package/dist/api/setupRequest.d.ts.map +0 -1
  413. package/dist/api/setupRequest.js +0 -44
  414. package/dist/api/util.d.ts.map +0 -1
  415. package/dist/api/util.js +0 -14
  416. package/eslint.config.mjs +0 -24
  417. package/src/Emailer/service.ts +0 -52
  418. package/src/Emailer.ts +0 -1
  419. package/src/Model/Repository/ext.ts +0 -283
  420. package/src/Model/Repository/internal/internal.ts +0 -577
  421. package/src/Model/Repository/legacy.ts +0 -27
  422. package/src/Model/Repository/makeRepo.ts +0 -139
  423. package/src/Model/Repository/service.ts +0 -627
  424. package/src/Model/Repository/validation.ts +0 -31
  425. package/src/Model/Repository.ts +0 -5
  426. package/src/Model/dsl.ts +0 -128
  427. package/src/Model/filter/filterApi.ts +0 -60
  428. package/src/Model/filter/types/errors.ts +0 -47
  429. package/src/Model/filter/types/fields.ts +0 -50
  430. package/src/Model/filter/types/path/common.ts +0 -404
  431. package/src/Model/filter/types/path/eager.ts +0 -298
  432. package/src/Model/filter/types/path/index.ts +0 -4
  433. package/src/Model/filter/types/utils.ts +0 -128
  434. package/src/Model/filter/types/validator.ts +0 -46
  435. package/src/Model/filter/types.ts +0 -6
  436. package/src/Model/query/dsl.ts +0 -2110
  437. package/src/Model/query/new-kid-interpreter.ts +0 -210
  438. package/src/Model/query.ts +0 -13
  439. package/src/Model.ts +0 -3
  440. package/src/Operations.ts +0 -235
  441. package/src/OperationsRepo.ts +0 -16
  442. package/src/QueueMaker/SQLQueue.ts +0 -189
  443. package/src/QueueMaker/memQueue.ts +0 -130
  444. package/src/QueueMaker/sbqueue.ts +0 -137
  445. package/src/QueueMaker/service.ts +0 -17
  446. package/src/RequestContext.ts +0 -63
  447. package/src/RequestFiberSet.ts +0 -105
  448. package/src/Store/ContextMapContainer.ts +0 -20
  449. package/src/Store/index.test.ts.bak +0 -112
  450. package/src/Store/service.ts +0 -184
  451. package/src/Store.ts +0 -1
  452. package/src/adapters/SQL.ts +0 -1
  453. package/src/adapters/ServiceBus.ts +0 -209
  454. package/src/adapters/index.ts +0 -0
  455. package/src/adapters/logger.ts +0 -3
  456. package/src/adapters/memQueue.ts +0 -21
  457. package/src/api/internal/auth.ts +0 -68
  458. package/src/api/middlewares.ts +0 -10
  459. package/src/api/routing/middleware.ts +0 -6
  460. package/src/api/routing.ts +0 -598
  461. package/src/api/setupRequest.ts +0 -84
  462. package/tsconfig.json.bak +0 -12
  463. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  464. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  465. /package/dist/{api/internal → internal}/health.d.ts +0 -0
  466. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  467. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  468. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  469. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  470. /package/src/{api/codec.ts → codec.ts} +0 -0
  471. /package/src/{api/internal → internal}/health.ts +0 -0
  472. /package/src/{api/routing → routing}/tsort.ts +0 -0
  473. /package/src/{api/util.ts → util.ts} +0 -0
@@ -0,0 +1,420 @@
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 { RpcSerialization } from "effect/unstable/rpc"
34
+ import { createServer } from "http"
35
+ import { RequestContextMiddleware } from "../src/internal/RequestContextMiddleware.js"
36
+ import { makeRouter } from "../src/routing.js"
37
+ import { DefaultGenericMiddlewaresLive } from "../src/routing/middleware.js"
38
+ import { MemoryStoreLive } from "../src/Store/Memory.js"
39
+ import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, SomeElseMiddleware, SomeElseMiddlewareLive, SomeService, Test, TestLive } from "./fixtures.js"
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Middleware (mirrors AppMiddleware shape — same composite as other e2e tests).
43
+ // ---------------------------------------------------------------------------
44
+
45
+ class AppMiddleware extends MiddlewareMaker
46
+ .Tag<AppMiddleware>()("AppMiddleware", RequestContextMap)
47
+ .middleware(RequireRoles, Test)
48
+ .middleware(AllowAnonymous)
49
+ .middleware(SomeElseMiddleware)
50
+ .middleware(...DefaultGenericMiddlewares)
51
+ {
52
+ static Default = this.layer.pipe(
53
+ Layer.provide(
54
+ [
55
+ RequireRolesLive.pipe(Layer.provide(SomeService.Default)),
56
+ AllowAnonymousLive,
57
+ TestLive,
58
+ SomeElseMiddlewareLive,
59
+ DefaultGenericMiddlewaresLive
60
+ ] as const
61
+ )
62
+ )
63
+ }
64
+
65
+ const { Router, matchAll } = makeRouter(AppMiddleware.Default)
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Resources
69
+ // ---------------------------------------------------------------------------
70
+
71
+ const DynamicKey: Invalidation.InvalidationKey = ["dynamic", "key"]
72
+ const ExtraKey: Invalidation.InvalidationKey = ["extra", "key"]
73
+ const StreamKey: Invalidation.InvalidationKey = ["stream", "key"]
74
+
75
+ const { TaggedRequestFor } = makeRpcClient(AppMiddleware)
76
+ const Req = TaggedRequestFor("Inv")
77
+
78
+ class CmdBoom extends TaggedErrorClass<CmdBoom>()("CmdBoom", { reason: S.String }) {}
79
+
80
+ class DoNothing extends Req.Command<DoNothing>()("DoNothing", {}, {
81
+ allowAnonymous: true,
82
+ success: S.Void
83
+ }) {}
84
+
85
+ class DoWithDynamicKey extends Req.Command<DoWithDynamicKey>()("DoWithDynamicKey", {}, {
86
+ allowAnonymous: true,
87
+ success: S.String
88
+ }) {}
89
+
90
+ class DoWithBothKeys extends Req.Command<DoWithBothKeys>()("DoWithBothKeys", {}, {
91
+ allowAnonymous: true,
92
+ success: S.Number
93
+ }) {}
94
+
95
+ class DoAndFail extends Req.Command<DoAndFail>()("DoAndFail", {}, {
96
+ allowAnonymous: true,
97
+ success: S.Void,
98
+ error: CmdBoom
99
+ }) {}
100
+
101
+ class StreamWithKey extends Req.Command<StreamWithKey>()("StreamWithKey", {}, {
102
+ stream: true,
103
+ allowAnonymous: true,
104
+ success: S.Number
105
+ }) {}
106
+
107
+ class StreamWithRepoWrite extends Req.Command<StreamWithRepoWrite>()("StreamWithRepoWrite", {}, {
108
+ stream: true,
109
+ allowAnonymous: true,
110
+ success: S.Number
111
+ }) {}
112
+
113
+ class RepoItem extends S.Class<RepoItem>("RepoItem")({
114
+ id: S.String,
115
+ label: S.String
116
+ }) {}
117
+
118
+ class GetRepoCount extends Req.Query<GetRepoCount>()("GetRepoCount", {}, {
119
+ allowAnonymous: true,
120
+ success: S.Number
121
+ }) {}
122
+
123
+ class SaveRepoItem extends Req.Command<SaveRepoItem>()("SaveRepoItem", {
124
+ id: S.String,
125
+ label: S.String
126
+ }, {
127
+ allowAnonymous: true,
128
+ error: S.Union([InvalidStateError, OptimisticConcurrencyException]),
129
+ success: S.Void
130
+ }) {}
131
+
132
+ class RepoItems extends Context.Service<RepoItems>()("RepoItems", {
133
+ make: makeRepo("RepoItem", RepoItem, {})
134
+ }) {
135
+ static Default = Layer.effect(this, this.make).pipe(
136
+ Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive))
137
+ )
138
+ }
139
+
140
+ // A second, unrelated repo — its writes must NOT invalidate a query that only read `RepoItem`.
141
+ class OtherItem extends S.Class<OtherItem>("OtherItem")({
142
+ id: S.String,
143
+ label: S.String
144
+ }) {}
145
+
146
+ class SaveOtherItem extends Req.Command<SaveOtherItem>()("SaveOtherItem", {
147
+ id: S.String,
148
+ label: S.String
149
+ }, {
150
+ allowAnonymous: true,
151
+ success: S.Void
152
+ }) {}
153
+
154
+ class OtherItems extends Context.Service<OtherItems>()("OtherItems", {
155
+ make: makeRepo("OtherItem", OtherItem, {})
156
+ }) {
157
+ static Default = Layer.effect(this, this.make).pipe(
158
+ Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive))
159
+ )
160
+ }
161
+
162
+ const InvRsc = {
163
+ DoNothing,
164
+ DoWithDynamicKey,
165
+ DoWithBothKeys,
166
+ DoAndFail,
167
+ StreamWithKey,
168
+ StreamWithRepoWrite,
169
+ GetRepoCount,
170
+ SaveRepoItem,
171
+ SaveOtherItem
172
+ }
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // Controllers / router
176
+ // ---------------------------------------------------------------------------
177
+
178
+ const router = Router(InvRsc)({
179
+ dependencies: [RepoItems.Default, OtherItems.Default],
180
+ *effect(match) {
181
+ const repo = yield* RepoItems
182
+ const otherRepo = yield* OtherItems
183
+ return match({
184
+ DoNothing: () => Effect.void,
185
+ DoWithDynamicKey: Effect.fnUntraced(function*() {
186
+ yield* Invalidation.InvalidationSet.use((_) => _.add(DynamicKey))
187
+ return "done"
188
+ }),
189
+ DoWithBothKeys: Effect.fnUntraced(function*() {
190
+ yield* Invalidation.InvalidationSet.use((_) => _.add(DynamicKey))
191
+ yield* Invalidation.InvalidationSet.use((_) => _.add(ExtraKey))
192
+ return 99
193
+ }),
194
+ DoAndFail: Effect.fnUntraced(function*() {
195
+ yield* Invalidation.InvalidationSet.use((_) => _.add(DynamicKey))
196
+ return yield* Effect.fail(new CmdBoom({ reason: "intentional failure" }))
197
+ }),
198
+ StreamWithKey: () =>
199
+ Stream.fromIterable([1, 2, 3]).pipe(
200
+ Stream.tap(() => Invalidation.InvalidationSet.use((_) => _.add(StreamKey)))
201
+ ),
202
+ StreamWithRepoWrite: () =>
203
+ Stream.fromIterable([1, 2, 3]).pipe(
204
+ Stream.tap((n) => repo.save(new RepoItem({ id: String(n), label: "x" })).pipe(Effect.orDie))
205
+ ),
206
+ GetRepoCount: () => repo.all.pipe(Effect.map((_) => _.length), Effect.orDie),
207
+ SaveRepoItem: ({ id, label }) => repo.save(new RepoItem({ id, label })).pipe(Effect.orDie),
208
+ SaveOtherItem: ({ id, label }) => otherRepo.save(new OtherItem({ id, label })).pipe(Effect.orDie)
209
+ })
210
+ }
211
+ })
212
+
213
+ const RpcRouterLayer = matchAll({ router })
214
+
215
+ // ---------------------------------------------------------------------------
216
+ // HTTP wiring — fresh server on loopback per `it.live`.
217
+ // ---------------------------------------------------------------------------
218
+
219
+ const NodeServerLayer = NodeHttpServer.layer(() => createServer(), { port: 0 })
220
+
221
+ const ServerLayer = HttpRouter
222
+ .serve(RpcRouterLayer.pipe(Layer.provide(HttpRouter.middleware(RequestContextMiddleware()).layer)))
223
+ .pipe(
224
+ Layer.provide(NodeServerLayer),
225
+ Layer.provide(RpcSerialization.layerNdjson)
226
+ )
227
+
228
+ const ClientLayer = Layer
229
+ .unwrap(
230
+ Effect.gen(function*() {
231
+ const server = yield* HttpServer.HttpServer
232
+ const addr = server.address
233
+ if (addr._tag !== "TcpAddress") return yield* Effect.die(new Error("expected TcpAddress"))
234
+ const host = addr.hostname === "0.0.0.0" ? "127.0.0.1" : addr.hostname
235
+ const url = `http://${host}:${addr.port}`
236
+ return ApiClientFactory
237
+ .layer({ url, headers: Option.none() })
238
+ .pipe(Layer.provide(FetchHttpClient.layer))
239
+ })
240
+ )
241
+ .pipe(Layer.provide(NodeServerLayer))
242
+
243
+ const TestLayer = Layer.mergeAll(ServerLayer, ClientLayer)
244
+
245
+ // Helper: provide a fresh `InvalidationKeysFromServer` and capture forwarded keys.
246
+ const withCapture = <A, E, R>(eff: Effect.Effect<A, E, R>) =>
247
+ Effect.gen(function*() {
248
+ const ref = yield* Ref.make<ReadonlyArray<Invalidation.InvalidationKey>>([])
249
+ const svc = makeInvalidationKeysService(ref)
250
+ const result = yield* eff.pipe(Effect.provideService(InvalidationKeysFromServer, svc), Effect.exit)
251
+ return { result, keys: yield* Ref.get(ref) }
252
+ })
253
+
254
+ const withDependencyCapture = <A, E, R>(eff: Effect.Effect<A, E, R>) =>
255
+ Effect.gen(function*() {
256
+ const readsRef = yield* Ref.make(DataDependencies.empty())
257
+ const writesRef = yield* Ref.make(DataDependencies.empty())
258
+ const svc = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
259
+ const result = yield* eff.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, svc), Effect.exit)
260
+ return { result, dependencies: yield* svc.get }
261
+ })
262
+
263
+ // ---------------------------------------------------------------------------
264
+ // Tests
265
+ // ---------------------------------------------------------------------------
266
+
267
+ it.live(
268
+ "command with no invalidation keys: caller sees raw payload, no keys forwarded",
269
+ Effect.fnUntraced(function*() {
270
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
271
+ const { result, keys } = yield* withCapture(client.DoNothing.handler())
272
+ expect(Exit.isSuccess(result)).toBe(true)
273
+ expect(keys).toStrictEqual([])
274
+ }, Effect.provide(TestLayer)),
275
+ { timeout: 10_000 }
276
+ )
277
+
278
+ it.live(
279
+ "command with dynamic InvalidationSet.use: payload + key forwarded",
280
+ Effect.fnUntraced(function*() {
281
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
282
+ const { result, keys } = yield* withCapture(client.DoWithDynamicKey.handler())
283
+ expect(Exit.isSuccess(result) && result.value).toBe("done")
284
+ expect(keys).toStrictEqual([DynamicKey])
285
+ }, Effect.provide(TestLayer)),
286
+ { timeout: 10_000 }
287
+ )
288
+
289
+ it.live(
290
+ "command accumulating multiple dynamic keys: all keys forwarded in order",
291
+ Effect.fnUntraced(function*() {
292
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
293
+ const { result, keys } = yield* withCapture(client.DoWithBothKeys.handler())
294
+ expect(Exit.isSuccess(result) && result.value).toBe(99)
295
+ expect(keys).toStrictEqual([DynamicKey, ExtraKey])
296
+ }, Effect.provide(TestLayer)),
297
+ { timeout: 10_000 }
298
+ )
299
+
300
+ it.live(
301
+ "per-request isolation: each command call starts with a fresh InvalidationSet",
302
+ Effect.fnUntraced(function*() {
303
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
304
+ const r1 = yield* withCapture(client.DoWithDynamicKey.handler())
305
+ const r2 = yield* withCapture(client.DoWithDynamicKey.handler())
306
+ // Each call must have exactly one key — no accumulation across calls
307
+ expect(r1.keys).toStrictEqual([DynamicKey])
308
+ expect(r2.keys).toStrictEqual([DynamicKey])
309
+ }, Effect.provide(TestLayer)),
310
+ { timeout: 10_000 }
311
+ )
312
+
313
+ it.live(
314
+ "command failure (V2): keys accumulated before fail still reach the client; original error re-thrown",
315
+ Effect.fnUntraced(function*() {
316
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
317
+ const { result, keys } = yield* withCapture(client.DoAndFail.handler())
318
+ expect(Exit.isFailure(result)).toBe(true)
319
+ if (Exit.isFailure(result)) {
320
+ const error = Cause.findErrorOption(result.cause)
321
+ expect(Option.isSome(error)).toBe(true)
322
+ if (Option.isSome(error)) {
323
+ expect(error.value._tag).toBe("CmdBoom")
324
+ expect(error.value.reason).toBe("intentional failure")
325
+ }
326
+ }
327
+ expect(keys).toStrictEqual([DynamicKey])
328
+ }, Effect.provide(TestLayer)),
329
+ { timeout: 10_000 }
330
+ )
331
+
332
+ it.live(
333
+ "stream: per-chunk metadata drains keys mid-stream",
334
+ Effect.fnUntraced(function*() {
335
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
336
+ const ref = yield* Ref.make<ReadonlyArray<Invalidation.InvalidationKey>>([])
337
+ const svc = makeInvalidationKeysService(ref)
338
+ const values = yield* Stream.runCollect(client.StreamWithKey.handler()).pipe(
339
+ Effect.provideService(InvalidationKeysFromServer, svc)
340
+ )
341
+ const keys = yield* Ref.get(ref)
342
+ expect(values).toStrictEqual([1, 2, 3])
343
+ // Handler taps `InvalidationSet.use` once per emitted value; routing's V3 mid-stream
344
+ // metadata drain forwards each batch as it arrives.
345
+ expect(keys).toStrictEqual([StreamKey, StreamKey, StreamKey])
346
+ }, Effect.provide(TestLayer)),
347
+ { timeout: 10_000 }
348
+ )
349
+
350
+ it.live(
351
+ "stream: per-chunk repo writes are drained and forwarded to the client recorder",
352
+ Effect.fnUntraced(function*() {
353
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
354
+ const readsRef = yield* Ref.make(DataDependencies.empty())
355
+ const writesRef = yield* Ref.make(DataDependencies.empty())
356
+ const svc = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
357
+ const values = yield* Stream.runCollect(client.StreamWithRepoWrite.handler()).pipe(
358
+ Effect.provideService(DataDependencies.DataDependencyRecorder, svc)
359
+ )
360
+ const writes = yield* Ref.get(writesRef)
361
+ expect(values).toStrictEqual([1, 2, 3])
362
+ // Each emitted value writes to RepoItem; routing drains the writes per chunk and the client
363
+ // accumulates them — the recorder dedupes, so a single RepoItem entry is recorded.
364
+ expect(writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
365
+ }, Effect.provide(TestLayer)),
366
+ { timeout: 10_000 }
367
+ )
368
+
369
+ it.live(
370
+ "repository dependencies flow through query and command metadata",
371
+ Effect.fnUntraced(function*() {
372
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
373
+
374
+ const query = yield* withDependencyCapture(client.GetRepoCount.handler())
375
+ expect(Exit.isSuccess(query.result) && query.result.value).toBe(0)
376
+ expect(query.dependencies.reads).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
377
+ expect(query.dependencies.writes).toStrictEqual(DataDependencies.empty())
378
+
379
+ const command = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
380
+ expect(Exit.isSuccess(command.result)).toBe(true)
381
+ expect(command.dependencies.reads).toStrictEqual(DataDependencies.empty())
382
+ expect(command.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
383
+ }, Effect.provide(TestLayer)),
384
+ { timeout: 10_000 }
385
+ )
386
+
387
+ it.live(
388
+ "query invalidation: a command's writes invalidate exactly the queries whose reads intersect",
389
+ Effect.fnUntraced(function*() {
390
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
391
+
392
+ // Client-side query registry: queryKey -> read dependencies forwarded by the server. Mirrors
393
+ // @effect-app/vue's `dependencyMetadata`; the derivation predicate (`intersects`) is the exact
394
+ // one the vue mutate engine uses to pick invalidation targets from a command's writes.
395
+ const queryReads = new Map<string, DataDependencies.DataDependencies>()
396
+ const invalidatedBy = (writes: DataDependencies.DataDependencies) =>
397
+ [...queryReads]
398
+ .filter(([, reads]) => DataDependencies.intersects(reads, writes))
399
+ .map(([key]) => key)
400
+
401
+ // Run the query through the real client; register its forwarded reads under its key.
402
+ const query = yield* withDependencyCapture(client.GetRepoCount.handler())
403
+ expect(Exit.isSuccess(query.result)).toBe(true)
404
+ queryReads.set("GetRepoCount", query.dependencies.reads)
405
+ // Before any command, nothing is invalidated.
406
+ expect(invalidatedBy(DataDependencies.empty())).toStrictEqual([])
407
+
408
+ // A command writing the SAME repo the query read => the query is selected for invalidation.
409
+ const save = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
410
+ expect(Exit.isSuccess(save.result)).toBe(true)
411
+ expect(invalidatedBy(save.dependencies.writes)).toStrictEqual(["GetRepoCount"])
412
+
413
+ // A command writing an UNRELATED repo => the query is NOT invalidated (negative control).
414
+ const saveOther = yield* withDependencyCapture(client.SaveOtherItem.handler({ id: "2", label: "two" }))
415
+ expect(Exit.isSuccess(saveOther.result)).toBe(true)
416
+ expect(saveOther.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("OtherItem")]))
417
+ expect(invalidatedBy(saveOther.dependencies.writes)).toStrictEqual([])
418
+ }, Effect.provide(TestLayer)),
419
+ { timeout: 10_000 }
420
+ )
@@ -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
+ )