@effect-app/infra 4.0.0-beta.19 → 4.0.0-beta.190

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 (300) hide show
  1. package/CHANGELOG.md +1277 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +15 -7
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +10 -12
  6. package/dist/Emailer/Sendgrid.d.ts +14 -14
  7. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  8. package/dist/Emailer/Sendgrid.js +16 -15
  9. package/dist/Emailer/fake.d.ts +1 -1
  10. package/dist/Emailer/service.d.ts +9 -3
  11. package/dist/Emailer/service.d.ts.map +1 -1
  12. package/dist/Emailer/service.js +3 -3
  13. package/dist/Emailer.d.ts +1 -1
  14. package/dist/MainFiberSet.d.ts +5 -5
  15. package/dist/MainFiberSet.d.ts.map +1 -1
  16. package/dist/MainFiberSet.js +3 -3
  17. package/dist/Model/Repository/Registry.d.ts +20 -0
  18. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  19. package/dist/Model/Repository/Registry.js +17 -0
  20. package/dist/Model/Repository/ext.d.ts +33 -15
  21. package/dist/Model/Repository/ext.d.ts.map +1 -1
  22. package/dist/Model/Repository/ext.js +54 -2
  23. package/dist/Model/Repository/internal/internal.d.ts +6 -6
  24. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  25. package/dist/Model/Repository/internal/internal.js +43 -32
  26. package/dist/Model/Repository/legacy.d.ts +1 -1
  27. package/dist/Model/Repository/makeRepo.d.ts +7 -6
  28. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.js +5 -1
  30. package/dist/Model/Repository/service.d.ts +28 -23
  31. package/dist/Model/Repository/service.d.ts.map +1 -1
  32. package/dist/Model/Repository/validation.d.ts +142 -17
  33. package/dist/Model/Repository/validation.d.ts.map +1 -1
  34. package/dist/Model/Repository/validation.js +5 -5
  35. package/dist/Model/Repository.d.ts +2 -1
  36. package/dist/Model/Repository.d.ts.map +1 -1
  37. package/dist/Model/Repository.js +2 -1
  38. package/dist/Model/dsl.d.ts +4 -4
  39. package/dist/Model/dsl.d.ts.map +1 -1
  40. package/dist/Model/filter/filterApi.d.ts +5 -5
  41. package/dist/Model/filter/filterApi.d.ts.map +1 -1
  42. package/dist/Model/filter/types/errors.d.ts +1 -1
  43. package/dist/Model/filter/types/fields.d.ts +1 -1
  44. package/dist/Model/filter/types/path/common.d.ts +1 -1
  45. package/dist/Model/filter/types/path/eager.d.ts +1 -1
  46. package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
  47. package/dist/Model/filter/types/path/index.d.ts +1 -1
  48. package/dist/Model/filter/types/utils.d.ts +1 -1
  49. package/dist/Model/filter/types/validator.d.ts +1 -1
  50. package/dist/Model/filter/types.d.ts +1 -1
  51. package/dist/Model/query/dsl.d.ts +1 -1
  52. package/dist/Model/query/dsl.d.ts.map +1 -1
  53. package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
  54. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  55. package/dist/Model/query/new-kid-interpreter.js +3 -3
  56. package/dist/Model/query.d.ts +1 -1
  57. package/dist/Model.d.ts +2 -1
  58. package/dist/Model.d.ts.map +1 -1
  59. package/dist/Model.js +2 -1
  60. package/dist/Operations.d.ts +6 -6
  61. package/dist/Operations.d.ts.map +1 -1
  62. package/dist/Operations.js +56 -59
  63. package/dist/OperationsRepo.d.ts +11 -29
  64. package/dist/OperationsRepo.d.ts.map +1 -1
  65. package/dist/OperationsRepo.js +3 -3
  66. package/dist/QueueMaker/SQLQueue.d.ts +5 -7
  67. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  68. package/dist/QueueMaker/SQLQueue.js +105 -114
  69. package/dist/QueueMaker/errors.d.ts +2 -2
  70. package/dist/QueueMaker/errors.d.ts.map +1 -1
  71. package/dist/QueueMaker/memQueue.d.ts +7 -4
  72. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  73. package/dist/QueueMaker/memQueue.js +51 -62
  74. package/dist/QueueMaker/sbqueue.d.ts +6 -3
  75. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  76. package/dist/QueueMaker/sbqueue.js +37 -53
  77. package/dist/QueueMaker/service.d.ts +1 -1
  78. package/dist/RequestContext.d.ts +114 -26
  79. package/dist/RequestContext.d.ts.map +1 -1
  80. package/dist/RequestContext.js +7 -7
  81. package/dist/RequestFiberSet.d.ts +7 -7
  82. package/dist/RequestFiberSet.d.ts.map +1 -1
  83. package/dist/RequestFiberSet.js +5 -5
  84. package/dist/Store/ContextMapContainer.d.ts +19 -3
  85. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  86. package/dist/Store/ContextMapContainer.js +13 -3
  87. package/dist/Store/Cosmos/query.d.ts +1 -1
  88. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  89. package/dist/Store/Cosmos/query.js +8 -10
  90. package/dist/Store/Cosmos.d.ts +1 -1
  91. package/dist/Store/Cosmos.d.ts.map +1 -1
  92. package/dist/Store/Cosmos.js +308 -242
  93. package/dist/Store/Disk.d.ts +2 -2
  94. package/dist/Store/Disk.d.ts.map +1 -1
  95. package/dist/Store/Disk.js +25 -22
  96. package/dist/Store/Memory.d.ts +4 -4
  97. package/dist/Store/Memory.d.ts.map +1 -1
  98. package/dist/Store/Memory.js +27 -22
  99. package/dist/Store/SQL/Pg.d.ts +4 -0
  100. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  101. package/dist/Store/SQL/Pg.js +189 -0
  102. package/dist/Store/SQL/query.d.ts +38 -0
  103. package/dist/Store/SQL/query.d.ts.map +1 -0
  104. package/dist/Store/SQL/query.js +367 -0
  105. package/dist/Store/SQL.d.ts +20 -0
  106. package/dist/Store/SQL.d.ts.map +1 -0
  107. package/dist/Store/SQL.js +381 -0
  108. package/dist/Store/codeFilter.d.ts +1 -1
  109. package/dist/Store/codeFilter.d.ts.map +1 -1
  110. package/dist/Store/codeFilter.js +2 -1
  111. package/dist/Store/index.d.ts +5 -2
  112. package/dist/Store/index.d.ts.map +1 -1
  113. package/dist/Store/index.js +15 -3
  114. package/dist/Store/service.d.ts +17 -6
  115. package/dist/Store/service.d.ts.map +1 -1
  116. package/dist/Store/service.js +24 -6
  117. package/dist/Store/utils.d.ts +1 -1
  118. package/dist/Store/utils.d.ts.map +1 -1
  119. package/dist/Store/utils.js +3 -4
  120. package/dist/Store.d.ts +1 -1
  121. package/dist/adapters/SQL/Model.d.ts +28 -42
  122. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  123. package/dist/adapters/SQL/Model.js +2 -2
  124. package/dist/adapters/SQL.d.ts +1 -1
  125. package/dist/adapters/ServiceBus.d.ts +9 -9
  126. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  127. package/dist/adapters/ServiceBus.js +13 -15
  128. package/dist/adapters/cosmos-client.d.ts +3 -3
  129. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  130. package/dist/adapters/cosmos-client.js +3 -3
  131. package/dist/adapters/index.d.ts +8 -2
  132. package/dist/adapters/index.d.ts.map +1 -1
  133. package/dist/adapters/index.js +8 -2
  134. package/dist/adapters/logger.d.ts +1 -1
  135. package/dist/adapters/logger.d.ts.map +1 -1
  136. package/dist/adapters/memQueue.d.ts +3 -3
  137. package/dist/adapters/memQueue.d.ts.map +1 -1
  138. package/dist/adapters/memQueue.js +3 -3
  139. package/dist/adapters/mongo-client.d.ts +3 -3
  140. package/dist/adapters/mongo-client.d.ts.map +1 -1
  141. package/dist/adapters/mongo-client.js +3 -3
  142. package/dist/adapters/redis-client.d.ts +3 -3
  143. package/dist/adapters/redis-client.d.ts.map +1 -1
  144. package/dist/adapters/redis-client.js +3 -3
  145. package/dist/api/ContextProvider.d.ts +7 -7
  146. package/dist/api/ContextProvider.d.ts.map +1 -1
  147. package/dist/api/ContextProvider.js +6 -6
  148. package/dist/api/codec.d.ts +1 -1
  149. package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
  150. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  151. package/dist/api/internal/RequestContextMiddleware.js +2 -2
  152. package/dist/api/internal/auth.d.ts +44 -6
  153. package/dist/api/internal/auth.d.ts.map +1 -1
  154. package/dist/api/internal/auth.js +160 -29
  155. package/dist/api/internal/events.d.ts +3 -3
  156. package/dist/api/internal/events.d.ts.map +1 -1
  157. package/dist/api/internal/events.js +9 -7
  158. package/dist/api/internal/health.d.ts +1 -1
  159. package/dist/api/layerUtils.d.ts +6 -6
  160. package/dist/api/layerUtils.d.ts.map +1 -1
  161. package/dist/api/layerUtils.js +5 -5
  162. package/dist/api/middlewares.d.ts +1 -1
  163. package/dist/api/reportError.d.ts +1 -1
  164. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
  165. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  166. package/dist/api/routing/middleware/middleware.d.ts +50 -4
  167. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  168. package/dist/api/routing/middleware/middleware.js +75 -17
  169. package/dist/api/routing/middleware.d.ts +1 -2
  170. package/dist/api/routing/middleware.d.ts.map +1 -1
  171. package/dist/api/routing/middleware.js +1 -2
  172. package/dist/api/routing/schema/jwt.d.ts +1 -1
  173. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  174. package/dist/api/routing/tsort.d.ts +1 -1
  175. package/dist/api/routing/tsort.d.ts.map +1 -1
  176. package/dist/api/routing/utils.d.ts +3 -3
  177. package/dist/api/routing/utils.d.ts.map +1 -1
  178. package/dist/api/routing.d.ts +26 -18
  179. package/dist/api/routing.d.ts.map +1 -1
  180. package/dist/api/routing.js +70 -11
  181. package/dist/api/setupRequest.d.ts +8 -5
  182. package/dist/api/setupRequest.d.ts.map +1 -1
  183. package/dist/api/setupRequest.js +12 -7
  184. package/dist/api/util.d.ts +1 -1
  185. package/dist/arbs.d.ts +1 -1
  186. package/dist/arbs.d.ts.map +1 -1
  187. package/dist/arbs.js +5 -3
  188. package/dist/errorReporter.d.ts +4 -4
  189. package/dist/errorReporter.d.ts.map +1 -1
  190. package/dist/errorReporter.js +20 -25
  191. package/dist/errors.d.ts +1 -1
  192. package/dist/fileUtil.d.ts +1 -1
  193. package/dist/fileUtil.d.ts.map +1 -1
  194. package/dist/index.d.ts +1 -1
  195. package/dist/logger/jsonLogger.d.ts +1 -1
  196. package/dist/logger/logFmtLogger.d.ts +1 -1
  197. package/dist/logger/shared.d.ts +1 -1
  198. package/dist/logger/shared.js +2 -2
  199. package/dist/logger.d.ts +1 -1
  200. package/dist/logger.d.ts.map +1 -1
  201. package/dist/rateLimit.d.ts +9 -3
  202. package/dist/rateLimit.d.ts.map +1 -1
  203. package/dist/rateLimit.js +5 -11
  204. package/dist/test.d.ts +1 -1
  205. package/dist/test.d.ts.map +1 -1
  206. package/dist/vitest.d.ts +1 -1
  207. package/eslint.config.mjs +3 -3
  208. package/examples/query.ts +39 -35
  209. package/package.json +42 -36
  210. package/src/CUPS.ts +9 -11
  211. package/src/Emailer/Sendgrid.ts +17 -14
  212. package/src/Emailer/service.ts +8 -2
  213. package/src/MainFiberSet.ts +3 -3
  214. package/src/Model/Repository/Registry.ts +33 -0
  215. package/src/Model/Repository/ext.ts +93 -6
  216. package/src/Model/Repository/internal/internal.ts +97 -88
  217. package/src/Model/Repository/makeRepo.ts +12 -10
  218. package/src/Model/Repository/service.ts +31 -22
  219. package/src/Model/Repository/validation.ts +4 -4
  220. package/src/Model/Repository.ts +1 -0
  221. package/src/Model/dsl.ts +3 -3
  222. package/src/Model/query/new-kid-interpreter.ts +2 -2
  223. package/src/Model.ts +1 -0
  224. package/src/QueueMaker/SQLQueue.ts +121 -151
  225. package/src/QueueMaker/memQueue.ts +82 -103
  226. package/src/QueueMaker/sbqueue.ts +56 -86
  227. package/src/RequestContext.ts +8 -8
  228. package/src/RequestFiberSet.ts +4 -4
  229. package/src/Store/ContextMapContainer.ts +41 -2
  230. package/src/Store/Cosmos/query.ts +9 -11
  231. package/src/Store/Cosmos.ts +437 -343
  232. package/src/Store/Disk.ts +52 -49
  233. package/src/Store/Memory.ts +54 -48
  234. package/src/Store/SQL/Pg.ts +318 -0
  235. package/src/Store/SQL/query.ts +409 -0
  236. package/src/Store/SQL.ts +668 -0
  237. package/src/Store/codeFilter.ts +1 -0
  238. package/src/Store/index.ts +17 -2
  239. package/src/Store/service.ts +31 -7
  240. package/src/Store/utils.ts +23 -22
  241. package/src/adapters/SQL/Model.ts +10 -4
  242. package/src/adapters/ServiceBus.ts +111 -115
  243. package/src/adapters/cosmos-client.ts +2 -2
  244. package/src/adapters/index.ts +7 -0
  245. package/src/adapters/memQueue.ts +2 -2
  246. package/src/adapters/mongo-client.ts +2 -2
  247. package/src/adapters/redis-client.ts +2 -2
  248. package/src/api/ContextProvider.ts +11 -11
  249. package/src/api/internal/RequestContextMiddleware.ts +1 -1
  250. package/src/api/internal/auth.ts +246 -44
  251. package/src/api/internal/events.ts +12 -8
  252. package/src/api/layerUtils.ts +8 -8
  253. package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
  254. package/src/api/routing/middleware/middleware.ts +109 -15
  255. package/src/api/routing/middleware.ts +0 -2
  256. package/src/api/routing.ts +154 -13
  257. package/src/api/setupRequest.ts +28 -8
  258. package/src/arbs.ts +4 -2
  259. package/src/errorReporter.ts +62 -74
  260. package/src/logger/shared.ts +1 -1
  261. package/src/rateLimit.ts +30 -22
  262. package/test/auth.test.ts +101 -0
  263. package/test/contextProvider.test.ts +11 -11
  264. package/test/controller.test.ts +18 -14
  265. package/test/dist/auth.test.d.ts.map +1 -0
  266. package/test/dist/contextProvider.test.d.ts.map +1 -1
  267. package/test/dist/controller.test.d.ts.map +1 -1
  268. package/test/dist/date-query.test.d.ts.map +1 -0
  269. package/test/dist/fixtures.d.ts +26 -12
  270. package/test/dist/fixtures.d.ts.map +1 -1
  271. package/test/dist/fixtures.js +12 -10
  272. package/test/dist/query.test.d.ts.map +1 -1
  273. package/test/dist/rawQuery.test.d.ts.map +1 -1
  274. package/test/dist/repository-ext.test.d.ts.map +1 -0
  275. package/test/dist/requires.test.d.ts.map +1 -1
  276. package/test/dist/router-generator.test.d.ts.map +1 -0
  277. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  278. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  279. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  280. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  281. package/test/dist/sql-store.test.d.ts.map +1 -0
  282. package/test/fixtures.ts +11 -9
  283. package/test/query.test.ts +216 -34
  284. package/test/rawQuery.test.ts +23 -19
  285. package/test/repository-ext.test.ts +60 -0
  286. package/test/requires.test.ts +6 -6
  287. package/test/router-generator.test.ts +180 -0
  288. package/test/routing-interruptibility.test.ts +63 -0
  289. package/test/rpc-e2e-invalidation.test.ts +507 -0
  290. package/test/rpc-multi-middleware.test.ts +78 -9
  291. package/test/rpc-stream-fullstack.test.ts +181 -0
  292. package/test/sql-store.test.ts +1064 -0
  293. package/test/validateSample.test.ts +15 -12
  294. package/tsconfig.examples.json +1 -1
  295. package/tsconfig.json +0 -1
  296. package/tsconfig.json.bak +2 -2
  297. package/tsconfig.src.json +35 -35
  298. package/tsconfig.test.json +2 -2
  299. package/src/Operations.ts +0 -235
  300. package/src/OperationsRepo.ts +0 -16
@@ -0,0 +1,180 @@
1
+ import { type MakeContext, type MakeErrors, makeRouter } from "@effect-app/infra/api/routing"
2
+ import { makeAllDSL, makeOneDSL } from "@effect-app/infra/Model"
3
+ import { expectTypeOf, it } from "@effect/vitest"
4
+ import { Context, Effect, Layer, RpcX, S } from "effect-app"
5
+ import { InvalidStateError, makeRpcClient, UnauthorizedError } from "effect-app/client"
6
+ import { DefaultGenericMiddlewares } from "effect-app/middleware"
7
+ import { type FixEnv } from "effect-app/Pure"
8
+ import { MiddlewareMaker } from "effect-app/rpc"
9
+ import { type TypeTestId } from "effect-app/TypeTest"
10
+ import { type ConfigError } from "effect/Config"
11
+ import { type RpcSerialization } from "effect/unstable/rpc/RpcSerialization"
12
+ import { DefaultGenericMiddlewaresLive, DevModeMiddlewareLive } from "../src/api/routing/middleware.js"
13
+ import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElse, SomeService, Test, TestLive } from "./fixtures.js"
14
+
15
+ // Inline minimal context provider (provides `Some`)
16
+ class CtxProvider extends RpcX.RpcMiddleware.Tag<CtxProvider, { provides: Some }>()("CtxProvider") {
17
+ static Default = Layer.make(this, {
18
+ *make() {
19
+ return Effect.fnUntraced(function*(effect) {
20
+ return yield* Effect.provideService(effect, Some, Some.of({ a: 1 }))
21
+ })
22
+ }
23
+ })
24
+ }
25
+
26
+ // Provides `SomeElse` so AllowAnonymous's requirement is met.
27
+ class SomeElseProvider extends RpcX.RpcMiddleware.Tag<SomeElseProvider, { provides: SomeElse }>()("SomeElseProvider") {
28
+ static Default = Layer.make(this, {
29
+ *make() {
30
+ return Effect.fnUntraced(function*(effect) {
31
+ return yield* Effect.provideService(effect, SomeElse, SomeElse.of({ b: 2 }))
32
+ })
33
+ }
34
+ })
35
+ }
36
+
37
+ class mw extends MiddlewareMaker
38
+ .Tag<mw>()("mw", RequestContextMap)
39
+ .middleware(RequireRoles, Test)
40
+ .middleware(AllowAnonymous)
41
+ .middleware(CtxProvider)
42
+ .middleware(...DefaultGenericMiddlewares, SomeElseProvider)
43
+ {
44
+ static Default = this.layer.pipe(
45
+ Layer.provide([
46
+ RequireRolesLive,
47
+ TestLive,
48
+ AllowAnonymousLive,
49
+ CtxProvider.Default,
50
+ SomeElseProvider.Default,
51
+ DefaultGenericMiddlewaresLive,
52
+ DevModeMiddlewareLive,
53
+ SomeService.Default
54
+ ])
55
+ )
56
+ }
57
+
58
+ const { TaggedRequestFor } = makeRpcClient(RequestContextMap)
59
+ const Req = TaggedRequestFor("GenRouter")
60
+
61
+ class GetThing extends Req.Query<GetThing>()("GetThing", { id: S.String }, { success: S.String }) {}
62
+ class DoThing extends Req.Command<DoThing>()("DoThing", { id: S.String }, { success: S.Void }) {}
63
+
64
+ const Resource = { GetThing, DoThing }
65
+
66
+ const { Router, matchAll } = makeRouter(mw)
67
+
68
+ class ThingRepo extends Context.Service<ThingRepo>()("ThingRepo", {
69
+ make: Effect.succeed({ get: (id: string) => Effect.succeed(id + "!") })
70
+ }) {
71
+ static Default = Layer.effect(this, this.make)
72
+ }
73
+
74
+ // Case under test:
75
+ // `match({})` is given handlers as **shorthand generator methods** (`*GetThing(req) { ... }`).
76
+ // tsgo (>= 7 dev) infers `TNext = unknown` for these shorthand generators while TS6 infers `never`.
77
+ // `HandlerWithInputGen` in routing.ts must accept both — see the structural fix.
78
+ const router = Router(Resource)({
79
+ dependencies: [ThingRepo.Default],
80
+ *effect(match) {
81
+ const repo = yield* ThingRepo
82
+
83
+ if (Math.random() > 0.5) return yield* new InvalidStateError("nope")
84
+
85
+ return match({
86
+ *GetThing(req) {
87
+ const some = yield* Some
88
+ if (req.id === "boom") {
89
+ return yield* Effect.fail(new UnauthorizedError())
90
+ }
91
+ return yield* repo.get(req.id + String(some.a))
92
+ },
93
+ *DoThing(_req) {
94
+ yield* Effect.succeed(1)
95
+ }
96
+ })
97
+ }
98
+ })
99
+
100
+ // Same scenario but using the `raw:` variant — exercises the `raw` path of `HandlerWithInputGen`.
101
+ const routerRaw = Router({ GetThing })({
102
+ *effect(match) {
103
+ return match({
104
+ GetThing: {
105
+ *raw(req) {
106
+ const some = yield* Some
107
+ return yield* Effect.succeed(req.id + String(some.a))
108
+ }
109
+ }
110
+ })
111
+ }
112
+ })
113
+
114
+ it("router with generator-method handlers compiles", () => {
115
+ expectTypeOf(router).toMatchTypeOf<
116
+ Layer.Layer<never, ConfigError | InvalidStateError, SomeService | RpcSerialization>
117
+ >()
118
+ expectTypeOf(routerRaw).toMatchTypeOf<Layer.Layer<never, ConfigError, SomeService | RpcSerialization>>()
119
+ })
120
+
121
+ // Type-level assertions: verify generator yields propagate to MakeErrors / MakeContext
122
+ type Errors = MakeErrors<typeof router[TypeTestId]>
123
+ type Ctx = MakeContext<typeof router[TypeTestId]>
124
+ expectTypeOf<Errors>().toEqualTypeOf<InvalidStateError>()
125
+ expectTypeOf<Ctx>().toEqualTypeOf<ThingRepo>()
126
+
127
+ const matched = matchAll({ router })
128
+ expectTypeOf(matched).toMatchTypeOf<
129
+ Layer.Layer<never, ConfigError | InvalidStateError, SomeService | RpcSerialization>
130
+ >()
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // DSL R-inference regression
134
+ // ---------------------------------------------------------------------------
135
+ // `OneDSL`/`OneDSLExt.update`/`.modify` previously annotated the callback's
136
+ // effect R as `FixEnv<R, Evt, S1, S2>`. That deadlocked inference of `R`
137
+ // (TS6 → `never`, tsgo → `unknown`), causing yielded effects to leak
138
+ // `unknown` in the R slot when consumed by generator handlers.
139
+ // The fix uses bare `R` in the callback and `FixEnv<R, …>` only on the return.
140
+ class Item extends S.Class<Item>("Item")({ id: S.String, label: S.String }) {}
141
+ class Dep extends Context.Service<Dep>()("Dep", { make: Effect.succeed({ tag: "dep" as const }) }) {}
142
+
143
+ type Evt = { _tag: "Updated"; id: string }
144
+
145
+ const Items$ = makeAllDSL<Item, Evt>()
146
+ const Item$ = makeOneDSL<Item, Evt>()
147
+
148
+ // Callback body uses generator syntax (TNext = unknown under tsgo) and yields
149
+ // a service-dependent effect — R must be inferred as `Dep` (plus the
150
+ // canonical PureEnvEnv contributed by FixEnv on the return).
151
+ const oneUpdate = Item$.update((item) =>
152
+ Effect.gen(function*() {
153
+ const dep = yield* Dep
154
+ return new Item({ id: item.id, label: item.label + dep.tag })
155
+ })
156
+ )
157
+
158
+ const allUpdate = Items$.update((items) =>
159
+ Effect.gen(function*() {
160
+ const dep = yield* Dep
161
+ return items.map((_) => new Item({ id: _.id, label: _.label + dep.tag }))
162
+ })
163
+ )
164
+
165
+ const oneModify = Item$.modify((item, _dsl) =>
166
+ Effect.gen(function*() {
167
+ const dep = yield* Dep
168
+ return { ...item, tag: dep.tag }
169
+ })
170
+ )
171
+
172
+ // `R` should be `FixEnv<Dep, Evt, …>` — never collapsed to `unknown`/`never`.
173
+ // The regression manifested as `unknown` here, breaking `Dep` assignability.
174
+ expectTypeOf(oneUpdate).toMatchTypeOf<Effect.Effect<Item, never, FixEnv<Dep, Evt, Item, Item>>>()
175
+ expectTypeOf(allUpdate).toMatchTypeOf<
176
+ Effect.Effect<readonly Item[], never, FixEnv<Dep, Evt, readonly Item[], readonly Item[]>>
177
+ >()
178
+ expectTypeOf(oneModify).toMatchTypeOf<
179
+ Effect.Effect<{ tag: "dep"; id: string; label: string }, never, FixEnv<Dep, Evt, Item, Item>>
180
+ >()
@@ -0,0 +1,63 @@
1
+ import { describe, expect, it } from "@effect/vitest"
2
+ import { Effect, Fiber, Layer, Ref } from "effect"
3
+ import { S } from "effect-app"
4
+ import { ConfigureInterruptibilityMiddleware } from "effect-app/middleware"
5
+ import { Rpc, RpcGroup, RpcTest } from "effect/unstable/rpc"
6
+ import { applyRequestTypeInterruptibility } from "../src/api/routing.js"
7
+ import { ConfigureInterruptibilityMiddlewareLive, RequestType } from "../src/api/routing/middleware.js"
8
+
9
+ const InterruptibilityRpcs = RpcGroup.make(
10
+ Rpc
11
+ .make("doCommand", { success: S.Void })
12
+ .annotate(RequestType, "command")
13
+ .middleware(ConfigureInterruptibilityMiddleware),
14
+ Rpc
15
+ .make("doQuery", { success: S.Void })
16
+ .annotate(RequestType, "query")
17
+ .middleware(ConfigureInterruptibilityMiddleware)
18
+ )
19
+
20
+ const makeImplLayer = (commandDone: Ref.Ref<boolean>, queryDone: Ref.Ref<boolean>) =>
21
+ InterruptibilityRpcs.toLayer({
22
+ doCommand: () =>
23
+ applyRequestTypeInterruptibility(
24
+ "command",
25
+ Effect.sleep("120 millis").pipe(Effect.andThen(Ref.set(commandDone, true)))
26
+ ),
27
+ doQuery: () =>
28
+ applyRequestTypeInterruptibility(
29
+ "query",
30
+ Effect.sleep("120 millis").pipe(Effect.andThen(Ref.set(queryDone, true)))
31
+ )
32
+ })
33
+
34
+ describe("routing interruptibility", () => {
35
+ it.live(
36
+ "e2e: command continues after client interrupt, query does not",
37
+ () =>
38
+ Effect.gen(function*() {
39
+ const commandDone = yield* Ref.make(false)
40
+ const queryDone = yield* Ref.make(false)
41
+
42
+ const client = yield* RpcTest
43
+ .makeClient(InterruptibilityRpcs)
44
+ .pipe(
45
+ Effect.provide(
46
+ Layer.mergeAll(makeImplLayer(commandDone, queryDone), ConfigureInterruptibilityMiddlewareLive)
47
+ )
48
+ )
49
+
50
+ const commandFiber = yield* Effect.forkDetach(client.doCommand())
51
+ yield* Effect.sleep("20 millis")
52
+ yield* Fiber.interrupt(commandFiber)
53
+ yield* Effect.sleep("180 millis")
54
+ expect(yield* Ref.get(commandDone)).toBe(true)
55
+
56
+ const queryFiber = yield* Effect.forkDetach(client.doQuery())
57
+ yield* Effect.sleep("20 millis")
58
+ yield* Fiber.interrupt(queryFiber)
59
+ yield* Effect.sleep("180 millis")
60
+ expect(yield* Ref.get(queryDone)).toBe(false)
61
+ })
62
+ )
63
+ })