@effect-app/infra 4.0.0-beta.31 → 4.0.0-beta.310

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 +2361 -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 +253 -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 +472 -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.map +1 -1
  109. package/dist/middlewares.d.ts.map +1 -0
  110. package/dist/{api/middlewares.js → middlewares.js} +1 -1
  111. package/dist/{adapters/mongo-client.d.ts → mongo-client.d.ts} +3 -2
  112. package/dist/mongo-client.d.ts.map +1 -0
  113. package/dist/mongo-client.js +15 -0
  114. package/dist/otel.d.ts +75 -0
  115. package/dist/otel.d.ts.map +1 -0
  116. package/dist/otel.js +84 -0
  117. package/dist/rateLimit.d.ts +11 -3
  118. package/dist/rateLimit.d.ts.map +1 -1
  119. package/dist/rateLimit.js +7 -12
  120. package/dist/{adapters/redis-client.d.ts → redis-client.d.ts} +5 -2
  121. package/dist/redis-client.d.ts.map +1 -0
  122. package/dist/redis-client.js +98 -0
  123. package/dist/{api/reportError.d.ts → reportError.d.ts} +1 -1
  124. package/dist/reportError.d.ts.map +1 -0
  125. package/dist/reportError.js +28 -0
  126. package/dist/{api/routing → routing}/middleware/RouterMiddleware.d.ts +4 -3
  127. package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
  128. package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
  129. package/dist/routing/middleware/middleware.d.ts +48 -0
  130. package/dist/routing/middleware/middleware.d.ts.map +1 -0
  131. package/dist/routing/middleware/middleware.js +152 -0
  132. package/dist/{api/routing → routing}/middleware.d.ts +0 -1
  133. package/dist/routing/middleware.d.ts.map +1 -0
  134. package/dist/{api/routing → routing}/middleware.js +1 -2
  135. package/dist/routing/schema/jwt.d.ts.map +1 -0
  136. package/dist/routing/schema/jwt.js +13 -0
  137. package/dist/routing/tsort.d.ts.map +1 -0
  138. package/dist/routing/tsort.js +51 -0
  139. package/dist/{api/routing → routing}/utils.d.ts +3 -3
  140. package/dist/routing/utils.d.ts.map +1 -0
  141. package/dist/routing/utils.js +45 -0
  142. package/dist/routing.d.ts +182 -0
  143. package/dist/routing.d.ts.map +1 -0
  144. package/dist/routing.js +256 -0
  145. package/dist/test.d.ts +2 -2
  146. package/dist/test.d.ts.map +1 -1
  147. package/dist/test.js +2 -2
  148. package/dist/util.d.ts.map +1 -0
  149. package/dist/util.js +14 -0
  150. package/docs/cluster-storage.md +26 -0
  151. package/docs/workflow-engine.md +262 -0
  152. package/examples/query.ts +47 -39
  153. package/package.json +38 -352
  154. package/src/CUPS.ts +53 -14
  155. package/src/ClusterCosmos.ts +1118 -0
  156. package/src/ClusterServiceBus.ts +242 -0
  157. package/src/{api/ContextProvider.ts → ContextProvider.ts} +20 -17
  158. package/src/Emailer/Sendgrid.ts +83 -60
  159. package/src/Emailer/fake.ts +4 -4
  160. package/src/MainFiberSet.ts +32 -13
  161. package/src/QueueMaker/errors.ts +3 -1
  162. package/src/{adapters/SQL → SQL}/Model.ts +42 -41
  163. package/src/SQL.ts +1 -0
  164. package/src/Store/Cosmos/query.ts +218 -54
  165. package/src/Store/Cosmos.ts +529 -365
  166. package/src/Store/Disk.ts +112 -70
  167. package/src/Store/Memory.ts +365 -99
  168. package/src/Store/SQL/Pg.ts +389 -0
  169. package/src/Store/SQL/query.ts +603 -0
  170. package/src/Store/SQL.ts +766 -0
  171. package/src/Store/codeFilter.ts +8 -6
  172. package/src/Store/index.ts +25 -10
  173. package/src/Store/utils.ts +32 -25
  174. package/src/WorkflowEngineCosmos.ts +749 -0
  175. package/src/WorkflowEngineSqlite.ts +813 -0
  176. package/src/arbs.ts +5 -3
  177. package/src/{adapters/cosmos-client.ts → cosmos-client.ts} +5 -3
  178. package/src/errorReporter.ts +68 -78
  179. package/src/fileUtil.ts +1 -1
  180. package/src/index.ts +2 -1
  181. package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
  182. package/src/internal/auth.ts +272 -0
  183. package/src/{api/internal → internal}/events.ts +22 -13
  184. package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
  185. package/src/logger/jsonLogger.ts +5 -3
  186. package/src/logger/logFmtLogger.ts +3 -3
  187. package/src/logger/shared.ts +5 -4
  188. package/src/middlewares.ts +10 -0
  189. package/src/{adapters/mongo-client.ts → mongo-client.ts} +4 -2
  190. package/src/otel.ts +177 -0
  191. package/src/rateLimit.ts +34 -23
  192. package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
  193. package/src/{api/reportError.ts → reportError.ts} +3 -2
  194. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
  195. package/src/routing/middleware/middleware.ts +196 -0
  196. package/src/routing/middleware.ts +4 -0
  197. package/src/{api/routing → routing}/schema/jwt.ts +2 -1
  198. package/src/{api/routing → routing}/utils.ts +2 -1
  199. package/src/routing.ts +823 -0
  200. package/src/test.ts +4 -4
  201. package/src/vitest.ts +1 -1
  202. package/test/auth.test.ts +101 -0
  203. package/test/cluster-cosmos.test.ts +612 -0
  204. package/test/cluster-servicebus.test.ts +180 -0
  205. package/test/cluster-sqlite.test.ts +205 -0
  206. package/test/contextProvider.test.ts +15 -12
  207. package/test/controller.test.ts +28 -32
  208. package/test/cosmos-query.test.ts +228 -0
  209. package/test/dist/auth.test.d.ts.map +1 -0
  210. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  211. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  212. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  213. package/test/dist/contextProvider.test.d.ts.map +1 -1
  214. package/test/dist/controller.test.d.ts.map +1 -1
  215. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  216. package/test/dist/fixtures.d.ts +29 -11
  217. package/test/dist/fixtures.d.ts.map +1 -1
  218. package/test/dist/fixtures.js +17 -10
  219. package/test/dist/query.test.d.ts.map +1 -1
  220. package/test/dist/rawQuery.test.d.ts.map +1 -1
  221. package/test/dist/repository-ext.test.d.ts.map +1 -0
  222. package/test/dist/requires.test.d.ts.map +1 -1
  223. package/test/dist/router-generator.test.d.ts.map +1 -0
  224. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  225. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  226. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  227. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  228. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  229. package/test/dist/sql-store.test.d.ts.map +1 -0
  230. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  231. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  232. package/test/fixtures.ts +16 -9
  233. package/test/layerUtils.test.ts +2 -2
  234. package/test/query.test.ts +1130 -41
  235. package/test/rawQuery.test.ts +340 -22
  236. package/test/repository-ext.test.ts +426 -0
  237. package/test/requires.test.ts +10 -5
  238. package/test/router-generator.test.ts +187 -0
  239. package/test/routing-interruptibility.test.ts +66 -0
  240. package/test/rpc-context-map-streaming.test.ts +262 -0
  241. package/test/rpc-e2e-invalidation.test.ts +418 -0
  242. package/test/rpc-multi-middleware.test.ts +85 -10
  243. package/test/rpc-stream-fullstack.test.ts +304 -0
  244. package/test/sql-store.test.ts +1711 -0
  245. package/test/validateSample.test.ts +26 -14
  246. package/test/workflow-engine-cosmos.test.ts +345 -0
  247. package/test/workflow-engine-sqlite.test.ts +297 -0
  248. package/tsconfig.examples.json +1 -1
  249. package/tsconfig.json +9 -2
  250. package/tsconfig.src.json +35 -35
  251. package/tsconfig.test.json +2 -2
  252. package/dist/Emailer/service.d.ts +0 -55
  253. package/dist/Emailer/service.d.ts.map +0 -1
  254. package/dist/Emailer/service.js +0 -6
  255. package/dist/Emailer.d.ts +0 -2
  256. package/dist/Emailer.d.ts.map +0 -1
  257. package/dist/Emailer.js +0 -2
  258. package/dist/Model/Repository/ext.d.ts +0 -41
  259. package/dist/Model/Repository/ext.d.ts.map +0 -1
  260. package/dist/Model/Repository/ext.js +0 -65
  261. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  262. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  263. package/dist/Model/Repository/internal/internal.js +0 -316
  264. package/dist/Model/Repository/legacy.d.ts +0 -19
  265. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  266. package/dist/Model/Repository/legacy.js +0 -2
  267. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  268. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  269. package/dist/Model/Repository/makeRepo.js +0 -24
  270. package/dist/Model/Repository/service.d.ts +0 -89
  271. package/dist/Model/Repository/service.d.ts.map +0 -1
  272. package/dist/Model/Repository/service.js +0 -2
  273. package/dist/Model/Repository/validation.d.ts +0 -42
  274. package/dist/Model/Repository/validation.d.ts.map +0 -1
  275. package/dist/Model/Repository/validation.js +0 -32
  276. package/dist/Model/Repository.d.ts +0 -6
  277. package/dist/Model/Repository.d.ts.map +0 -1
  278. package/dist/Model/Repository.js +0 -6
  279. package/dist/Model/dsl.d.ts +0 -32
  280. package/dist/Model/dsl.d.ts.map +0 -1
  281. package/dist/Model/dsl.js +0 -44
  282. package/dist/Model/filter/filterApi.d.ts +0 -30
  283. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  284. package/dist/Model/filter/filterApi.js +0 -2
  285. package/dist/Model/filter/types/errors.d.ts +0 -29
  286. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  287. package/dist/Model/filter/types/errors.js +0 -2
  288. package/dist/Model/filter/types/fields.d.ts +0 -15
  289. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  290. package/dist/Model/filter/types/fields.js +0 -2
  291. package/dist/Model/filter/types/path/common.d.ts +0 -316
  292. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  293. package/dist/Model/filter/types/path/common.js +0 -2
  294. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  295. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  296. package/dist/Model/filter/types/path/eager.js +0 -31
  297. package/dist/Model/filter/types/path/index.d.ts +0 -4
  298. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  299. package/dist/Model/filter/types/path/index.js +0 -3
  300. package/dist/Model/filter/types/utils.d.ts +0 -79
  301. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  302. package/dist/Model/filter/types/utils.js +0 -2
  303. package/dist/Model/filter/types/validator.d.ts +0 -30
  304. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  305. package/dist/Model/filter/types/validator.js +0 -2
  306. package/dist/Model/filter/types.d.ts +0 -5
  307. package/dist/Model/filter/types.d.ts.map +0 -1
  308. package/dist/Model/filter/types.js +0 -7
  309. package/dist/Model/query/dsl.d.ts +0 -248
  310. package/dist/Model/query/dsl.d.ts.map +0 -1
  311. package/dist/Model/query/dsl.js +0 -104
  312. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  313. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  314. package/dist/Model/query/new-kid-interpreter.js +0 -165
  315. package/dist/Model/query.d.ts +0 -15
  316. package/dist/Model/query.d.ts.map +0 -1
  317. package/dist/Model/query.js +0 -3
  318. package/dist/Model.d.ts +0 -4
  319. package/dist/Model.d.ts.map +0 -1
  320. package/dist/Model.js +0 -4
  321. package/dist/Operations.d.ts +0 -55
  322. package/dist/Operations.d.ts.map +0 -1
  323. package/dist/Operations.js +0 -102
  324. package/dist/OperationsRepo.d.ts +0 -41
  325. package/dist/OperationsRepo.d.ts.map +0 -1
  326. package/dist/OperationsRepo.js +0 -14
  327. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  328. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  329. package/dist/QueueMaker/SQLQueue.js +0 -130
  330. package/dist/QueueMaker/memQueue.d.ts +0 -11
  331. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  332. package/dist/QueueMaker/memQueue.js +0 -76
  333. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  334. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  335. package/dist/QueueMaker/sbqueue.js +0 -91
  336. package/dist/QueueMaker/service.d.ts +0 -11
  337. package/dist/QueueMaker/service.d.ts.map +0 -1
  338. package/dist/QueueMaker/service.js +0 -4
  339. package/dist/RequestContext.d.ts +0 -63
  340. package/dist/RequestContext.d.ts.map +0 -1
  341. package/dist/RequestContext.js +0 -49
  342. package/dist/RequestFiberSet.d.ts +0 -36
  343. package/dist/RequestFiberSet.d.ts.map +0 -1
  344. package/dist/RequestFiberSet.js +0 -78
  345. package/dist/Store/ContextMapContainer.d.ts +0 -14
  346. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  347. package/dist/Store/ContextMapContainer.js +0 -16
  348. package/dist/Store/service.d.ts +0 -108
  349. package/dist/Store/service.d.ts.map +0 -1
  350. package/dist/Store/service.js +0 -71
  351. package/dist/Store.d.ts +0 -2
  352. package/dist/Store.d.ts.map +0 -1
  353. package/dist/Store.js +0 -2
  354. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  355. package/dist/adapters/SQL/Model.js +0 -478
  356. package/dist/adapters/SQL.d.ts.map +0 -1
  357. package/dist/adapters/ServiceBus.d.ts +0 -58
  358. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  359. package/dist/adapters/ServiceBus.js +0 -99
  360. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  361. package/dist/adapters/cosmos-client.js +0 -9
  362. package/dist/adapters/index.d.ts +0 -2
  363. package/dist/adapters/index.d.ts.map +0 -1
  364. package/dist/adapters/index.js +0 -2
  365. package/dist/adapters/logger.d.ts +0 -9
  366. package/dist/adapters/logger.d.ts.map +0 -1
  367. package/dist/adapters/logger.js +0 -3
  368. package/dist/adapters/memQueue.d.ts +0 -13
  369. package/dist/adapters/memQueue.d.ts.map +0 -1
  370. package/dist/adapters/memQueue.js +0 -20
  371. package/dist/adapters/mongo-client.d.ts.map +0 -1
  372. package/dist/adapters/mongo-client.js +0 -13
  373. package/dist/adapters/redis-client.d.ts.map +0 -1
  374. package/dist/adapters/redis-client.js +0 -94
  375. package/dist/api/ContextProvider.d.ts +0 -31
  376. package/dist/api/ContextProvider.d.ts.map +0 -1
  377. package/dist/api/ContextProvider.js +0 -38
  378. package/dist/api/codec.d.ts.map +0 -1
  379. package/dist/api/codec.js +0 -5
  380. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  381. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  382. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  383. package/dist/api/internal/auth.d.ts +0 -15
  384. package/dist/api/internal/auth.d.ts.map +0 -1
  385. package/dist/api/internal/auth.js +0 -47
  386. package/dist/api/internal/events.d.ts +0 -9
  387. package/dist/api/internal/events.d.ts.map +0 -1
  388. package/dist/api/internal/events.js +0 -42
  389. package/dist/api/internal/health.d.ts.map +0 -1
  390. package/dist/api/internal/health.js +0 -5
  391. package/dist/api/layerUtils.d.ts.map +0 -1
  392. package/dist/api/layerUtils.js +0 -16
  393. package/dist/api/middlewares.d.ts.map +0 -1
  394. package/dist/api/reportError.d.ts.map +0 -1
  395. package/dist/api/reportError.js +0 -27
  396. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  397. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  398. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  399. package/dist/api/routing/middleware/middleware.js +0 -92
  400. package/dist/api/routing/middleware.d.ts.map +0 -1
  401. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  402. package/dist/api/routing/schema/jwt.js +0 -12
  403. package/dist/api/routing/tsort.d.ts.map +0 -1
  404. package/dist/api/routing/tsort.js +0 -51
  405. package/dist/api/routing/utils.d.ts.map +0 -1
  406. package/dist/api/routing/utils.js +0 -44
  407. package/dist/api/routing.d.ts +0 -138
  408. package/dist/api/routing.d.ts.map +0 -1
  409. package/dist/api/routing.js +0 -166
  410. package/dist/api/setupRequest.d.ts +0 -12
  411. package/dist/api/setupRequest.d.ts.map +0 -1
  412. package/dist/api/setupRequest.js +0 -44
  413. package/dist/api/util.d.ts.map +0 -1
  414. package/dist/api/util.js +0 -14
  415. package/eslint.config.mjs +0 -24
  416. package/src/Emailer/service.ts +0 -52
  417. package/src/Emailer.ts +0 -1
  418. package/src/Model/Repository/ext.ts +0 -283
  419. package/src/Model/Repository/internal/internal.ts +0 -577
  420. package/src/Model/Repository/legacy.ts +0 -27
  421. package/src/Model/Repository/makeRepo.ts +0 -139
  422. package/src/Model/Repository/service.ts +0 -627
  423. package/src/Model/Repository/validation.ts +0 -31
  424. package/src/Model/Repository.ts +0 -5
  425. package/src/Model/dsl.ts +0 -128
  426. package/src/Model/filter/filterApi.ts +0 -60
  427. package/src/Model/filter/types/errors.ts +0 -47
  428. package/src/Model/filter/types/fields.ts +0 -50
  429. package/src/Model/filter/types/path/common.ts +0 -404
  430. package/src/Model/filter/types/path/eager.ts +0 -298
  431. package/src/Model/filter/types/path/index.ts +0 -4
  432. package/src/Model/filter/types/utils.ts +0 -128
  433. package/src/Model/filter/types/validator.ts +0 -46
  434. package/src/Model/filter/types.ts +0 -6
  435. package/src/Model/query/dsl.ts +0 -2110
  436. package/src/Model/query/new-kid-interpreter.ts +0 -210
  437. package/src/Model/query.ts +0 -13
  438. package/src/Model.ts +0 -3
  439. package/src/Operations.ts +0 -235
  440. package/src/OperationsRepo.ts +0 -16
  441. package/src/QueueMaker/SQLQueue.ts +0 -189
  442. package/src/QueueMaker/memQueue.ts +0 -130
  443. package/src/QueueMaker/sbqueue.ts +0 -137
  444. package/src/QueueMaker/service.ts +0 -17
  445. package/src/RequestContext.ts +0 -63
  446. package/src/RequestFiberSet.ts +0 -105
  447. package/src/Store/ContextMapContainer.ts +0 -20
  448. package/src/Store/index.test.ts.bak +0 -112
  449. package/src/Store/service.ts +0 -184
  450. package/src/Store.ts +0 -1
  451. package/src/adapters/SQL.ts +0 -1
  452. package/src/adapters/ServiceBus.ts +0 -209
  453. package/src/adapters/index.ts +0 -0
  454. package/src/adapters/logger.ts +0 -3
  455. package/src/adapters/memQueue.ts +0 -21
  456. package/src/api/internal/auth.ts +0 -68
  457. package/src/api/middlewares.ts +0 -10
  458. package/src/api/routing/middleware/middleware.ts +0 -128
  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,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
+ )