@effect-app/infra 4.0.0-beta.32 → 4.0.0-beta.320

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 (480) hide show
  1. package/CHANGELOG.md +2462 -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 +68 -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 +392 -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 +87 -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 +346 -76
  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 +257 -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 +21 -0
  51. package/dist/Store/SQL.d.ts.map +1 -0
  52. package/dist/Store/SQL.js +478 -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 +13 -0
  60. package/dist/Store/jsonDocument.d.ts.map +1 -0
  61. package/dist/Store/jsonDocument.js +31 -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 +29 -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 +2 -2
  72. package/dist/arbs.d.ts.map +1 -1
  73. package/dist/arbs.js +5 -3
  74. package/dist/codec.d.ts.map +1 -0
  75. package/dist/codec.js +5 -0
  76. package/dist/{adapters/cosmos-client.d.ts → cosmos-client.d.ts} +4 -2
  77. package/dist/cosmos-client.d.ts.map +1 -0
  78. package/dist/cosmos-client.js +11 -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 +5 -5
  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 +49 -41
  157. package/package.json +38 -352
  158. package/src/CUPS.ts +53 -14
  159. package/src/ClusterCosmos.ts +1154 -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 +537 -367
  170. package/src/Store/Disk.ts +137 -74
  171. package/src/Store/Memory.ts +402 -113
  172. package/src/Store/SQL/Pg.ts +402 -0
  173. package/src/Store/SQL/query.ts +748 -0
  174. package/src/Store/SQL.ts +786 -0
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +25 -10
  177. package/src/Store/jsonDocument.ts +43 -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 +6 -4
  182. package/src/{adapters/cosmos-client.ts → cosmos-client.ts} +5 -3
  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 +5 -4
  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/auth.test.ts +101 -0
  208. package/test/cluster-cosmos.test.ts +612 -0
  209. package/test/cluster-servicebus.test.ts +180 -0
  210. package/test/cluster-sqlite.test.ts +207 -0
  211. package/test/contextProvider.test.ts +15 -12
  212. package/test/controller.test.ts +28 -32
  213. package/test/cosmos-query.test.ts +323 -0
  214. package/test/dist/auth.test.d.ts.map +1 -0
  215. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  216. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  217. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  218. package/test/dist/contextProvider.test.d.ts.map +1 -1
  219. package/test/dist/controller.test.d.ts.map +1 -1
  220. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  221. package/test/dist/fixtures.d.ts +29 -11
  222. package/test/dist/fixtures.d.ts.map +1 -1
  223. package/test/dist/fixtures.js +17 -10
  224. package/test/dist/json-lower.test.d.ts.map +1 -0
  225. package/test/dist/query.test.d.ts.map +1 -1
  226. package/test/dist/rawQuery.test.d.ts.map +1 -1
  227. package/test/dist/repository-ext.test.d.ts.map +1 -0
  228. package/test/dist/requires.test.d.ts.map +1 -1
  229. package/test/dist/router-generator.test.d.ts.map +1 -0
  230. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  231. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  232. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  233. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  234. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  235. package/test/dist/sql-store.test.d.ts.map +1 -0
  236. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  237. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  238. package/test/fixtures.ts +16 -9
  239. package/test/json-lower.test.ts +115 -0
  240. package/test/layerUtils.test.ts +2 -2
  241. package/test/query.test.ts +1384 -46
  242. package/test/rawQuery.test.ts +340 -22
  243. package/test/repository-ext.test.ts +456 -0
  244. package/test/requires.test.ts +10 -5
  245. package/test/router-generator.test.ts +187 -0
  246. package/test/routing-interruptibility.test.ts +66 -0
  247. package/test/rpc-context-map-streaming.test.ts +262 -0
  248. package/test/rpc-e2e-invalidation.test.ts +418 -0
  249. package/test/rpc-multi-middleware.test.ts +85 -10
  250. package/test/rpc-stream-fullstack.test.ts +304 -0
  251. package/test/sql-store.test.ts +1905 -0
  252. package/test/validateSample.test.ts +26 -14
  253. package/test/workflow-engine-cosmos.test.ts +345 -0
  254. package/test/workflow-engine-sqlite.test.ts +297 -0
  255. package/tsconfig.examples.json +1 -1
  256. package/tsconfig.json +9 -2
  257. package/tsconfig.src.json +35 -35
  258. package/tsconfig.test.json +2 -2
  259. package/dist/Emailer/service.d.ts +0 -55
  260. package/dist/Emailer/service.d.ts.map +0 -1
  261. package/dist/Emailer/service.js +0 -6
  262. package/dist/Emailer.d.ts +0 -2
  263. package/dist/Emailer.d.ts.map +0 -1
  264. package/dist/Emailer.js +0 -2
  265. package/dist/Model/Repository/ext.d.ts +0 -41
  266. package/dist/Model/Repository/ext.d.ts.map +0 -1
  267. package/dist/Model/Repository/ext.js +0 -65
  268. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  269. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  270. package/dist/Model/Repository/internal/internal.js +0 -316
  271. package/dist/Model/Repository/legacy.d.ts +0 -19
  272. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  273. package/dist/Model/Repository/legacy.js +0 -2
  274. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  275. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  276. package/dist/Model/Repository/makeRepo.js +0 -24
  277. package/dist/Model/Repository/service.d.ts +0 -89
  278. package/dist/Model/Repository/service.d.ts.map +0 -1
  279. package/dist/Model/Repository/service.js +0 -2
  280. package/dist/Model/Repository/validation.d.ts +0 -42
  281. package/dist/Model/Repository/validation.d.ts.map +0 -1
  282. package/dist/Model/Repository/validation.js +0 -32
  283. package/dist/Model/Repository.d.ts +0 -6
  284. package/dist/Model/Repository.d.ts.map +0 -1
  285. package/dist/Model/Repository.js +0 -6
  286. package/dist/Model/dsl.d.ts +0 -32
  287. package/dist/Model/dsl.d.ts.map +0 -1
  288. package/dist/Model/dsl.js +0 -44
  289. package/dist/Model/filter/filterApi.d.ts +0 -30
  290. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  291. package/dist/Model/filter/filterApi.js +0 -2
  292. package/dist/Model/filter/types/errors.d.ts +0 -29
  293. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  294. package/dist/Model/filter/types/errors.js +0 -2
  295. package/dist/Model/filter/types/fields.d.ts +0 -15
  296. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  297. package/dist/Model/filter/types/fields.js +0 -2
  298. package/dist/Model/filter/types/path/common.d.ts +0 -316
  299. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  300. package/dist/Model/filter/types/path/common.js +0 -2
  301. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  302. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  303. package/dist/Model/filter/types/path/eager.js +0 -31
  304. package/dist/Model/filter/types/path/index.d.ts +0 -4
  305. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  306. package/dist/Model/filter/types/path/index.js +0 -3
  307. package/dist/Model/filter/types/utils.d.ts +0 -79
  308. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  309. package/dist/Model/filter/types/utils.js +0 -2
  310. package/dist/Model/filter/types/validator.d.ts +0 -30
  311. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  312. package/dist/Model/filter/types/validator.js +0 -2
  313. package/dist/Model/filter/types.d.ts +0 -5
  314. package/dist/Model/filter/types.d.ts.map +0 -1
  315. package/dist/Model/filter/types.js +0 -7
  316. package/dist/Model/query/dsl.d.ts +0 -248
  317. package/dist/Model/query/dsl.d.ts.map +0 -1
  318. package/dist/Model/query/dsl.js +0 -104
  319. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  320. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  321. package/dist/Model/query/new-kid-interpreter.js +0 -165
  322. package/dist/Model/query.d.ts +0 -15
  323. package/dist/Model/query.d.ts.map +0 -1
  324. package/dist/Model/query.js +0 -3
  325. package/dist/Model.d.ts +0 -4
  326. package/dist/Model.d.ts.map +0 -1
  327. package/dist/Model.js +0 -4
  328. package/dist/Operations.d.ts +0 -55
  329. package/dist/Operations.d.ts.map +0 -1
  330. package/dist/Operations.js +0 -102
  331. package/dist/OperationsRepo.d.ts +0 -41
  332. package/dist/OperationsRepo.d.ts.map +0 -1
  333. package/dist/OperationsRepo.js +0 -14
  334. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  335. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  336. package/dist/QueueMaker/SQLQueue.js +0 -130
  337. package/dist/QueueMaker/memQueue.d.ts +0 -11
  338. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  339. package/dist/QueueMaker/memQueue.js +0 -76
  340. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  341. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  342. package/dist/QueueMaker/sbqueue.js +0 -91
  343. package/dist/QueueMaker/service.d.ts +0 -11
  344. package/dist/QueueMaker/service.d.ts.map +0 -1
  345. package/dist/QueueMaker/service.js +0 -4
  346. package/dist/RequestContext.d.ts +0 -63
  347. package/dist/RequestContext.d.ts.map +0 -1
  348. package/dist/RequestContext.js +0 -49
  349. package/dist/RequestFiberSet.d.ts +0 -36
  350. package/dist/RequestFiberSet.d.ts.map +0 -1
  351. package/dist/RequestFiberSet.js +0 -78
  352. package/dist/Store/ContextMapContainer.d.ts +0 -14
  353. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  354. package/dist/Store/ContextMapContainer.js +0 -16
  355. package/dist/Store/service.d.ts +0 -108
  356. package/dist/Store/service.d.ts.map +0 -1
  357. package/dist/Store/service.js +0 -71
  358. package/dist/Store.d.ts +0 -2
  359. package/dist/Store.d.ts.map +0 -1
  360. package/dist/Store.js +0 -2
  361. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  362. package/dist/adapters/SQL/Model.js +0 -478
  363. package/dist/adapters/SQL.d.ts.map +0 -1
  364. package/dist/adapters/ServiceBus.d.ts +0 -58
  365. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  366. package/dist/adapters/ServiceBus.js +0 -99
  367. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  368. package/dist/adapters/cosmos-client.js +0 -9
  369. package/dist/adapters/index.d.ts +0 -2
  370. package/dist/adapters/index.d.ts.map +0 -1
  371. package/dist/adapters/index.js +0 -2
  372. package/dist/adapters/logger.d.ts +0 -9
  373. package/dist/adapters/logger.d.ts.map +0 -1
  374. package/dist/adapters/logger.js +0 -3
  375. package/dist/adapters/memQueue.d.ts +0 -13
  376. package/dist/adapters/memQueue.d.ts.map +0 -1
  377. package/dist/adapters/memQueue.js +0 -20
  378. package/dist/adapters/mongo-client.d.ts.map +0 -1
  379. package/dist/adapters/mongo-client.js +0 -13
  380. package/dist/adapters/redis-client.d.ts.map +0 -1
  381. package/dist/adapters/redis-client.js +0 -94
  382. package/dist/api/ContextProvider.d.ts +0 -31
  383. package/dist/api/ContextProvider.d.ts.map +0 -1
  384. package/dist/api/ContextProvider.js +0 -38
  385. package/dist/api/codec.d.ts.map +0 -1
  386. package/dist/api/codec.js +0 -5
  387. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  388. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  389. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  390. package/dist/api/internal/auth.d.ts +0 -15
  391. package/dist/api/internal/auth.d.ts.map +0 -1
  392. package/dist/api/internal/auth.js +0 -47
  393. package/dist/api/internal/events.d.ts +0 -9
  394. package/dist/api/internal/events.d.ts.map +0 -1
  395. package/dist/api/internal/events.js +0 -42
  396. package/dist/api/internal/health.d.ts.map +0 -1
  397. package/dist/api/internal/health.js +0 -5
  398. package/dist/api/layerUtils.d.ts.map +0 -1
  399. package/dist/api/layerUtils.js +0 -16
  400. package/dist/api/middlewares.d.ts.map +0 -1
  401. package/dist/api/reportError.d.ts.map +0 -1
  402. package/dist/api/reportError.js +0 -27
  403. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  404. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  405. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  406. package/dist/api/routing/middleware/middleware.js +0 -92
  407. package/dist/api/routing/middleware.d.ts.map +0 -1
  408. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  409. package/dist/api/routing/schema/jwt.js +0 -12
  410. package/dist/api/routing/tsort.d.ts.map +0 -1
  411. package/dist/api/routing/tsort.js +0 -51
  412. package/dist/api/routing/utils.d.ts.map +0 -1
  413. package/dist/api/routing/utils.js +0 -44
  414. package/dist/api/routing.d.ts +0 -138
  415. package/dist/api/routing.d.ts.map +0 -1
  416. package/dist/api/routing.js +0 -166
  417. package/dist/api/setupRequest.d.ts +0 -12
  418. package/dist/api/setupRequest.d.ts.map +0 -1
  419. package/dist/api/setupRequest.js +0 -44
  420. package/dist/api/util.d.ts.map +0 -1
  421. package/dist/api/util.js +0 -14
  422. package/eslint.config.mjs +0 -24
  423. package/src/Emailer/service.ts +0 -52
  424. package/src/Emailer.ts +0 -1
  425. package/src/Model/Repository/ext.ts +0 -283
  426. package/src/Model/Repository/internal/internal.ts +0 -577
  427. package/src/Model/Repository/legacy.ts +0 -27
  428. package/src/Model/Repository/makeRepo.ts +0 -139
  429. package/src/Model/Repository/service.ts +0 -627
  430. package/src/Model/Repository/validation.ts +0 -31
  431. package/src/Model/Repository.ts +0 -5
  432. package/src/Model/dsl.ts +0 -128
  433. package/src/Model/filter/filterApi.ts +0 -60
  434. package/src/Model/filter/types/errors.ts +0 -47
  435. package/src/Model/filter/types/fields.ts +0 -50
  436. package/src/Model/filter/types/path/common.ts +0 -404
  437. package/src/Model/filter/types/path/eager.ts +0 -298
  438. package/src/Model/filter/types/path/index.ts +0 -4
  439. package/src/Model/filter/types/utils.ts +0 -128
  440. package/src/Model/filter/types/validator.ts +0 -46
  441. package/src/Model/filter/types.ts +0 -6
  442. package/src/Model/query/dsl.ts +0 -2110
  443. package/src/Model/query/new-kid-interpreter.ts +0 -210
  444. package/src/Model/query.ts +0 -13
  445. package/src/Model.ts +0 -3
  446. package/src/Operations.ts +0 -235
  447. package/src/OperationsRepo.ts +0 -16
  448. package/src/QueueMaker/SQLQueue.ts +0 -189
  449. package/src/QueueMaker/memQueue.ts +0 -130
  450. package/src/QueueMaker/sbqueue.ts +0 -137
  451. package/src/QueueMaker/service.ts +0 -17
  452. package/src/RequestContext.ts +0 -63
  453. package/src/RequestFiberSet.ts +0 -105
  454. package/src/Store/ContextMapContainer.ts +0 -20
  455. package/src/Store/index.test.ts.bak +0 -112
  456. package/src/Store/service.ts +0 -184
  457. package/src/Store.ts +0 -1
  458. package/src/adapters/SQL.ts +0 -1
  459. package/src/adapters/ServiceBus.ts +0 -209
  460. package/src/adapters/index.ts +0 -0
  461. package/src/adapters/logger.ts +0 -3
  462. package/src/adapters/memQueue.ts +0 -21
  463. package/src/api/internal/auth.ts +0 -68
  464. package/src/api/middlewares.ts +0 -10
  465. package/src/api/routing/middleware/middleware.ts +0 -128
  466. package/src/api/routing/middleware.ts +0 -6
  467. package/src/api/routing.ts +0 -598
  468. package/src/api/setupRequest.ts +0 -84
  469. package/tsconfig.json.bak +0 -12
  470. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  471. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  472. /package/dist/{api/internal → internal}/health.d.ts +0 -0
  473. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  474. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  475. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  476. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  477. /package/src/{api/codec.ts → codec.ts} +0 -0
  478. /package/src/{api/internal → internal}/health.ts +0 -0
  479. /package/src/{api/routing → routing}/tsort.ts +0 -0
  480. /package/src/{api/util.ts → util.ts} +0 -0
@@ -0,0 +1,418 @@
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 accumulates distinct keys",
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
+ expect(keys).toStrictEqual([StreamKey])
344
+ }, Effect.provide(TestLayer)),
345
+ { timeout: 10_000 }
346
+ )
347
+
348
+ it.live(
349
+ "stream: per-chunk repo writes are drained and forwarded to the client recorder",
350
+ Effect.fnUntraced(function*() {
351
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
352
+ const readsRef = yield* Ref.make(DataDependencies.empty())
353
+ const writesRef = yield* Ref.make(DataDependencies.empty())
354
+ const svc = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
355
+ const values = yield* Stream.runCollect(client.StreamWithRepoWrite.handler()).pipe(
356
+ Effect.provideService(DataDependencies.DataDependencyRecorder, svc)
357
+ )
358
+ const writes = yield* Ref.get(writesRef)
359
+ expect(values).toStrictEqual([1, 2, 3])
360
+ // Each emitted value writes to RepoItem; routing drains the writes per chunk and the client
361
+ // accumulates their entity ids into one dependency.
362
+ expect(writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem", ["1", "2", "3"])]))
363
+ }, Effect.provide(TestLayer)),
364
+ { timeout: 10_000 }
365
+ )
366
+
367
+ it.live(
368
+ "repository dependencies flow through query and command metadata",
369
+ Effect.fnUntraced(function*() {
370
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
371
+
372
+ const query = yield* withDependencyCapture(client.GetRepoCount.handler())
373
+ expect(Exit.isSuccess(query.result) && query.result.value).toBe(0)
374
+ expect(query.dependencies.reads).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
375
+ expect(query.dependencies.writes).toStrictEqual(DataDependencies.empty())
376
+
377
+ const command = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
378
+ expect(Exit.isSuccess(command.result)).toBe(true)
379
+ expect(command.dependencies.reads).toStrictEqual(DataDependencies.empty())
380
+ expect(command.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem", ["1"])]))
381
+ }, Effect.provide(TestLayer)),
382
+ { timeout: 10_000 }
383
+ )
384
+
385
+ it.live(
386
+ "query invalidation: a command's writes invalidate exactly the queries whose reads intersect",
387
+ Effect.fnUntraced(function*() {
388
+ const client = yield* ApiClientFactory.makeFor(Layer.empty)(InvRsc)
389
+
390
+ // Client-side query registry: queryKey -> read dependencies forwarded by the server. Mirrors
391
+ // @effect-app/vue's `dependencyMetadata`; the derivation predicate (`intersects`) is the exact
392
+ // one the vue mutate engine uses to pick invalidation targets from a command's writes.
393
+ const queryReads = new Map<string, DataDependencies.DataDependencies>()
394
+ const invalidatedBy = (writes: DataDependencies.DataDependencies) =>
395
+ [...queryReads]
396
+ .filter(([, reads]) => DataDependencies.intersects(reads, writes))
397
+ .map(([key]) => key)
398
+
399
+ // Run the query through the real client; register its forwarded reads under its key.
400
+ const query = yield* withDependencyCapture(client.GetRepoCount.handler())
401
+ expect(Exit.isSuccess(query.result)).toBe(true)
402
+ queryReads.set("GetRepoCount", query.dependencies.reads)
403
+ // Before any command, nothing is invalidated.
404
+ expect(invalidatedBy(DataDependencies.empty())).toStrictEqual([])
405
+
406
+ // A command writing the SAME repo the query read => the query is selected for invalidation.
407
+ const save = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
408
+ expect(Exit.isSuccess(save.result)).toBe(true)
409
+ expect(invalidatedBy(save.dependencies.writes)).toStrictEqual(["GetRepoCount"])
410
+
411
+ // A command writing an UNRELATED repo => the query is NOT invalidated (negative control).
412
+ const saveOther = yield* withDependencyCapture(client.SaveOtherItem.handler({ id: "2", label: "two" }))
413
+ expect(Exit.isSuccess(saveOther.result)).toBe(true)
414
+ expect(saveOther.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("OtherItem", ["2"])]))
415
+ expect(invalidatedBy(saveOther.dependencies.writes)).toStrictEqual([])
416
+ }, Effect.provide(TestLayer)),
417
+ { timeout: 10_000 }
418
+ )
@@ -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
+ )