@effect-app/infra 2.87.2 → 2.88.0

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 (36) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -22
  3. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  4. package/dist/api/routing/middleware/RouterMiddleware.js +1 -1
  5. package/dist/api/routing/middleware/RpcMiddleware.d.ts +13 -13
  6. package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -1
  7. package/dist/api/routing/middleware/RpcMiddleware.js +1 -1
  8. package/dist/api/routing/middleware/dynamic-middleware.d.ts +1 -9
  9. package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
  10. package/dist/api/routing/middleware/generic-middleware.d.ts +8 -8
  11. package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
  12. package/dist/api/routing/middleware/generic-middleware.js +23 -7
  13. package/dist/api/routing/middleware/middleware-api.d.ts +59 -30
  14. package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
  15. package/dist/api/routing/middleware/middleware-api.js +44 -35
  16. package/dist/api/routing/middleware/middleware.d.ts +7 -7
  17. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  18. package/dist/api/routing/middleware/middleware.js +5 -5
  19. package/package.json +2 -2
  20. package/src/api/routing/middleware/RouterMiddleware.ts +8 -86
  21. package/src/api/routing/middleware/RpcMiddleware.ts +13 -12
  22. package/src/api/routing/middleware/dynamic-middleware.ts +0 -47
  23. package/src/api/routing/middleware/generic-middleware.ts +45 -14
  24. package/src/api/routing/middleware/middleware-api.ts +147 -101
  25. package/src/api/routing/middleware/middleware.ts +5 -5
  26. package/test/contextProvider.test.ts +27 -24
  27. package/test/controller.test.ts +44 -9
  28. package/test/dist/contextProvider.test.d.ts.map +1 -1
  29. package/test/dist/controller.test.d.ts.map +1 -1
  30. package/test/dist/fixtures.d.ts +39 -45
  31. package/test/dist/fixtures.d.ts.map +1 -1
  32. package/test/dist/fixtures.js +21 -9
  33. package/test/dist/requires.test.d.ts.map +1 -1
  34. package/test/fixtures.ts +22 -13
  35. package/test/layerUtils.test.ts +1 -2
  36. package/test/requires.test.ts +119 -97
@@ -3,37 +3,22 @@ import { Context, Effect, Layer, type NonEmptyArray, type NonEmptyReadonlyArray
3
3
  import { type RPCContextMap } from "effect-app/client"
4
4
  import { type LayerUtils } from "../../layerUtils.js"
5
5
  import { type GenericMiddlewareMaker, genericMiddlewareMaker } from "./generic-middleware.js"
6
- import { makeRpcEffect, type MiddlewareMakerId, type RPCHandlerFactory } from "./RouterMiddleware.js"
6
+ import { makeRpcEffect, type RPCHandlerFactory } from "./RouterMiddleware.js"
7
7
  import { type AnyDynamic, type RpcDynamic, type TagClassAny } from "./RpcMiddleware.js"
8
8
 
9
- // TODO: don't expect service when it's wrap/never
10
- // perhaps RequestContextMap should be an object, instead of an interface, so that we don't need to provide anything here
11
- export const contextMap =
12
- <RequestContextMap extends Record<string, RPCContextMap.Any>>() =>
13
- <K extends keyof RequestContextMap>(a: K, service: RequestContextMap[K]["service"]) => ({
14
- key: a,
15
- settings: { service } as any as RequestContextMap[typeof a]
16
- })
17
-
18
- export interface MiddlewareM<
19
- RequestContext extends Record<string, RPCContextMap.Any>,
20
- Provided extends keyof RequestContext,
21
- Middlewares extends ReadonlyArray<GenericMiddlewareMaker>,
22
- DynamicMiddlewareProviders,
23
- // out MiddlewareR = never
24
- MiddlewareR = never
25
- > {
26
- middleware<MW extends NonEmptyArray<GenericMiddlewareMaker>>(
27
- ...mw: MW
28
- ): DynamicMiddlewareMakerrsss<
29
- RequestContext,
30
- Provided,
31
- [...Middlewares, ...MW],
32
- DynamicMiddlewareProviders,
33
- GenericMiddlewareMaker.ApplyManyServices<MW, MiddlewareR>
34
- >
35
- }
9
+ // adapter used when setting the dynamic prop on a middleware implementation
10
+ export const contextMap = <
11
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
12
+ Key extends (keyof RequestContextMap) & string
13
+ >(rcm: RequestContextMap, key: Key): RpcDynamic<Key, RequestContextMap[Key]> => ({
14
+ key,
15
+ settings: { service: rcm[key]!["service"] } as RequestContextMap[Key]
16
+ })
36
17
 
18
+ // the following implements sort of builder pattern
19
+ // we support both sideways and upwards elimination of dependencies
20
+
21
+ // it's for dynamic middlewares
37
22
  type GetDependsOnKeys<MW extends GenericMiddlewareMaker> = MW extends { dependsOn: NonEmptyReadonlyArray<TagClassAny> }
38
23
  ? {
39
24
  [K in keyof MW["dependsOn"]]: MW["dependsOn"][K] extends AnyDynamic ? MW["dependsOn"][K]["dynamic"]["key"]
@@ -41,112 +26,171 @@ type GetDependsOnKeys<MW extends GenericMiddlewareMaker> = MW extends { dependsO
41
26
  }[keyof MW["dependsOn"]]
42
27
  : never
43
28
 
44
- export interface MiddlewareDynamic<
45
- RequestContext extends Record<string, RPCContextMap.Any>,
46
- Provided extends keyof RequestContext,
29
+ type FilterInDynamicMiddlewares<
30
+ MWs extends ReadonlyArray<GenericMiddlewareMaker>,
31
+ RequestContextMap extends Record<string, RPCContextMap.Any>
32
+ > = {
33
+ [K in keyof MWs]: MWs[K] extends { dynamic: RpcDynamic<any, RequestContextMap[keyof RequestContextMap]> } ? MWs[K]
34
+ : never
35
+ }
36
+
37
+ type RecursiveHandleMWsSideways<
38
+ MWs,
39
+ R extends {
40
+ rcm: Record<string, RPCContextMap.Any>
41
+ provided: keyof R["rcm"] // that's fine
42
+ middlewares: ReadonlyArray<GenericMiddlewareMaker>
43
+ dmp: any
44
+ middlewareR: any
45
+ }
46
+ > = MWs extends [
47
+ infer F extends GenericMiddlewareMaker,
48
+ ...infer Rest extends ReadonlyArray<GenericMiddlewareMaker>
49
+ ] ? RecursiveHandleMWsSideways<Rest, {
50
+ rcm: R["rcm"]
51
+ // when one dynamic middleware depends on another, subtract the key to enforce the dependency to be provided after
52
+ // (if already provided, it would have to be re-provided anyway, so better to provide it after)
53
+ provided: Exclude<
54
+ R["provided"] | FilterInDynamicMiddlewares<[F], R["rcm"]>[number]["dynamic"]["key"],
55
+ // F is fine here because only dynamic middlewares will have 'dependsOn' prop
56
+ GetDependsOnKeys<F>
57
+ >
58
+ middlewares: [...R["middlewares"], F]
59
+ dmp: [FilterInDynamicMiddlewares<[F], R["rcm"]>[number]] extends [never] ? R["dmp"]
60
+ :
61
+ & R["dmp"]
62
+ & {
63
+ [U in FilterInDynamicMiddlewares<[F], R["rcm"]>[number] as U["dynamic"]["key"]]: U
64
+ }
65
+ middlewareR: GenericMiddlewareMaker.ApplyManyServices<[F], R["middlewareR"]>
66
+ }>
67
+ : R
68
+
69
+ export interface BuildingMiddleware<
70
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
71
+ Provided extends keyof RequestContextMap,
47
72
  Middlewares extends ReadonlyArray<GenericMiddlewareMaker>,
48
73
  DynamicMiddlewareProviders,
49
- out MiddlewareR
74
+ out MiddlewareR extends { _tag: string } = never
50
75
  > {
51
- middleware<MW extends NonEmptyArray<GenericMiddlewareMaker>>(
52
- ...mw: MW
53
- ): MW extends NonEmptyArray<{ dynamic: RpcDynamic<any, RequestContext[keyof RequestContext]> }>
54
- ? DynamicMiddlewareMakerrsss<
55
- RequestContext,
56
- // when one dynamic middleware depends on another, substract the key, to enforce the dependency to be provided after.
57
- Exclude<
58
- Provided | MW[number]["dynamic"]["key"],
59
- { [K in keyof MW]: GetDependsOnKeys<MW[K]> }[number]
60
- >,
61
- [...Middlewares, ...MW],
62
- & DynamicMiddlewareProviders
63
- & {
64
- [U in MW[number] as U["dynamic"]["key"]]: U
65
- },
66
- GenericMiddlewareMaker.ApplyManyServices<MW, MiddlewareR>
67
- >
68
- : DynamicMiddlewareMakerrsss<
69
- RequestContext,
70
- Provided,
71
- [...Middlewares, ...MW],
72
- DynamicMiddlewareProviders,
73
- GenericMiddlewareMaker.ApplyManyServices<MW, MiddlewareR>
76
+ middleware<MWs extends NonEmptyArray<GenericMiddlewareMaker>>(
77
+ ...mw: MWs
78
+ ): RecursiveHandleMWsSideways<MWs, {
79
+ rcm: RequestContextMap
80
+ provided: Provided
81
+ middlewares: Middlewares
82
+ dmp: DynamicMiddlewareProviders
83
+ middlewareR: MiddlewareR
84
+ }> extends infer Res extends {
85
+ rcm: RequestContextMap
86
+ provided: keyof RequestContextMap
87
+ middlewares: ReadonlyArray<GenericMiddlewareMaker>
88
+ dmp: any
89
+ middlewareR: any
90
+ } ? MiddlewaresBuilder<
91
+ Res["rcm"],
92
+ Res["provided"],
93
+ Res["middlewares"],
94
+ Res["dmp"],
95
+ Res["middlewareR"]
74
96
  >
97
+ : never
98
+
99
+ // helps debugging what are the missing requirements (type only)
100
+ missing: {
101
+ missingDynamicMiddlewares: Exclude<keyof RequestContextMap, Provided>
102
+ missingContext: MiddlewareR
103
+ }
75
104
  }
76
105
 
77
- type DynamicMiddlewareMakerrsss<
78
- RequestContext extends Record<string, RPCContextMap.Any>,
79
- Provided extends keyof RequestContext = never,
106
+ export type MiddlewaresBuilder<
107
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
108
+ Provided extends keyof RequestContextMap = never,
80
109
  Middlewares extends ReadonlyArray<GenericMiddlewareMaker> = [],
81
110
  DynamicMiddlewareProviders = unknown,
82
- MiddlewareR = never
83
- > = keyof Omit<RequestContext, Provided> extends never ? [MiddlewareR] extends [never] ?
84
- & ReturnType<
111
+ MiddlewareR extends { _tag: string } = never
112
+ > =
113
+ // keyof Omit<RequestContextMap, Provided> extends never is true when all the dynamic middlewares are provided
114
+ // MiddlewareR is never when all the required services from generic & dynamic middlewares are provided
115
+ keyof Omit<RequestContextMap, Provided> extends never ? [MiddlewareR] extends [never] ? ReturnType<
85
116
  typeof makeMiddlewareBasic<
86
- RequestContext,
117
+ RequestContextMap,
87
118
  Middlewares
88
119
  >
89
120
  >
90
- & MiddlewareM<
91
- RequestContext,
92
- Provided,
93
- Middlewares,
94
- DynamicMiddlewareProviders,
95
- MiddlewareR
96
- >
97
- : MiddlewareM<
98
- RequestContext,
99
- Provided,
100
- Middlewares,
101
- DynamicMiddlewareProviders,
102
- MiddlewareR
103
- >
104
- : MiddlewareDynamic<
105
- RequestContext,
106
- Provided,
107
- Middlewares,
108
- DynamicMiddlewareProviders,
109
- MiddlewareR
110
- >
121
+ : BuildingMiddleware<
122
+ RequestContextMap,
123
+ Provided,
124
+ Middlewares,
125
+ DynamicMiddlewareProviders,
126
+ MiddlewareR
127
+ >
128
+ : BuildingMiddleware<
129
+ RequestContextMap,
130
+ Provided,
131
+ Middlewares,
132
+ DynamicMiddlewareProviders,
133
+ MiddlewareR
134
+ >
111
135
 
112
136
  export const makeMiddleware: <
113
137
  RequestContextMap extends Record<string, RPCContextMap.Any>
114
- >() => DynamicMiddlewareMakerrsss<RequestContextMap> = () => {
138
+ >(rcm: RequestContextMap) => MiddlewaresBuilder<RequestContextMap> = (rcm) => {
115
139
  let allMiddleware: GenericMiddlewareMaker[] = []
116
140
  const it = {
117
141
  middleware: (...middlewares: any[]) => {
118
142
  for (const mw of middlewares) {
143
+ // recall that we run middlewares in reverse order
119
144
  allMiddleware = [mw, ...allMiddleware]
120
145
  }
121
- // TODO: support dynamic and generic intertwined. treat them as one
122
- return Object.assign(makeMiddlewareBasic<any, any>(...allMiddleware), it)
146
+ return allMiddleware.filter((m) => !!m.dynamic).length !== Object.keys(rcm).length
147
+ // for sure, until all the dynamic middlewares are provided it's non sensical to call makeMiddlewareBasic
148
+ ? it
149
+ // actually, we don't know yet if MiddlewareR is never, but we can't easily check it at runtime
150
+ : Object.assign(makeMiddlewareBasic<any, any>(rcm, ...allMiddleware), it)
123
151
  }
124
152
  }
125
153
  return it as any
126
154
  }
127
155
 
128
- export const makeMiddlewareBasic =
156
+ //
157
+ export const MiddlewareMakerTag = "MiddlewareMaker" as const
158
+
159
+ export interface MiddlewareMaker<E> {
160
+ readonly effect: E
161
+ readonly _tag: typeof MiddlewareMakerTag
162
+ }
163
+
164
+ export type MiddlewareMakerId = Pick<MiddlewareMaker<any>, "_tag">
165
+
166
+ export const buildMiddlewareMaker = <E>(eff: E) =>
167
+ ({
168
+ _tag: MiddlewareMakerTag,
169
+ effect: eff
170
+ }) satisfies MiddlewareMaker<E>
171
+
172
+ const makeMiddlewareBasic =
129
173
  // by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
130
174
  <
131
175
  RequestContextMap extends Record<string, RPCContextMap.Any>,
132
- // RequestContextProviders extends RequestContextMapProvider<RequestContextMap>, // how to resolve the dynamic middleware
133
176
  GenericMiddlewareProviders extends ReadonlyArray<GenericMiddlewareMaker>
134
177
  >(
178
+ _rcm: RequestContextMap,
135
179
  ...make: GenericMiddlewareProviders
136
180
  ) => {
137
181
  const MiddlewareMaker = Context.GenericTag<
138
182
  MiddlewareMakerId,
139
- {
140
- effect: RPCHandlerFactory<
183
+ MiddlewareMaker<
184
+ RPCHandlerFactory<
141
185
  RequestContextMap,
142
186
  GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
143
187
  >
144
- _tag: "MiddlewareMaker"
145
- }
188
+ >
146
189
  >(
147
- "MiddlewareMaker"
190
+ MiddlewareMakerTag
148
191
  )
149
192
 
193
+ // reverse middlewares and wrap one after the other
150
194
  const middlewares = genericMiddlewareMaker(...make)
151
195
 
152
196
  const l = Layer.scoped(
@@ -154,16 +198,16 @@ export const makeMiddlewareBasic =
154
198
  middlewares
155
199
  .effect
156
200
  .pipe(
157
- Effect.map((generic) => ({
158
- _tag: "MiddlewareMaker" as const,
159
- effect: makeRpcEffect<
201
+ Effect.map((generic) => (buildMiddlewareMaker(
202
+ makeRpcEffect<
160
203
  RequestContextMap,
161
204
  GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
162
205
  >()(
163
- (schema, next, moduleName) => {
206
+ (schema, handler, moduleName) => {
164
207
  return (payload, headers) =>
165
208
  Effect
166
209
  .gen(function*() {
210
+ // will be propagated to all the wrapped middlewares
167
211
  const basic = {
168
212
  config: schema.config ?? {},
169
213
  payload,
@@ -177,12 +221,12 @@ export const makeMiddlewareBasic =
177
221
  }
178
222
  return yield* generic({
179
223
  ...basic,
180
- next: next(payload, headers) as any
224
+ next: handler(payload, headers) as any
181
225
  })
182
- }) as any // why?
226
+ }) as any // why? because: Type 'SuccessValue' is not assignable to type 'Success<Req>' :P
183
227
  }
184
228
  )
185
- }))
229
+ )))
186
230
  )
187
231
  )
188
232
 
@@ -191,9 +235,11 @@ export const makeMiddlewareBasic =
191
235
  Layer.provide(middlewares.dependencies as any)
192
236
  ) as Layer.Layer<
193
237
  MiddlewareMakerId,
194
- LayerUtils.GetLayersError<typeof middlewares.dependencies>, // what could go wrong when building the dynamic middleware provider
238
+ // what could go wrong when building the dynamic middleware provider
239
+ LayerUtils.GetLayersError<typeof middlewares.dependencies>,
195
240
  LayerUtils.GetLayersContext<typeof middlewares.dependencies>
196
241
  >
197
242
 
243
+ // add to the tag a default implementation
198
244
  return Object.assign(MiddlewareMaker, { Default: middlewareLayer })
199
245
  }
@@ -23,8 +23,8 @@ export class RequestCacheMiddleware extends Tag<RequestCacheMiddleware>()("Reque
23
23
  }) {
24
24
  }
25
25
 
26
- export class ConfigureInterruptibility
27
- extends Tag<ConfigureInterruptibility>()("ConfigureInterruptibility", { wrap: true })({
26
+ export class ConfigureInterruptibilityMiddleware
27
+ extends Tag<ConfigureInterruptibilityMiddleware>()("ConfigureInterruptibilityMiddleware", { wrap: true })({
28
28
  effect: Effect.succeed(({ next }) =>
29
29
  next.pipe(
30
30
  // TODO: make this depend on query/command, and consider if middleware also should be affected. right now it's not.
@@ -35,7 +35,7 @@ export class ConfigureInterruptibility
35
35
  {
36
36
  }
37
37
 
38
- export class MiddlewareLogger extends Tag<MiddlewareLogger>()("MiddlewareLogger", { wrap: true })({
38
+ export class LoggerMiddleware extends Tag<LoggerMiddleware>()("LoggerMiddleware", { wrap: true })({
39
39
  effect: Effect.gen(function*() {
40
40
  const devMode = yield* DevMode
41
41
  return ({ headers, next, payload, rpc }) =>
@@ -98,6 +98,6 @@ export class MiddlewareLogger extends Tag<MiddlewareLogger>()("MiddlewareLogger"
98
98
 
99
99
  export const DefaultGenericMiddlewares = [
100
100
  RequestCacheMiddleware,
101
- ConfigureInterruptibility,
102
- MiddlewareLogger
101
+ ConfigureInterruptibilityMiddleware,
102
+ LoggerMiddleware
103
103
  ] as const
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
- import { expectTypeOf } from "@effect/vitest"
3
+ import { expectTypeOf, it } from "@effect/vitest"
4
4
  import { Context, Effect, Scope } from "effect-app"
5
5
  import { ContextProvider, mergeContextProviders, MergedContextProvider } from "../src/api/routing.js"
6
6
  import { CustomError1, Some, SomeElse, SomeService } from "./fixtures.js"
@@ -119,33 +119,36 @@ export const someContextProviderGen = ContextProvider({
119
119
  }
120
120
  })
121
121
  })
122
- expectTypeOf(someContextProvider).toEqualTypeOf<typeof someContextProviderGen>()
123
122
 
124
- const merged = mergeContextProviders(MyContextProvider)
125
- const mergedGen = mergeContextProviders(MyContextProviderGen)
123
+ it("works", () => {
124
+ expectTypeOf(someContextProvider).toEqualTypeOf<typeof someContextProviderGen>()
126
125
 
127
- export const contextProvider2 = ContextProvider(merged)
128
- export const contextProvider3 = MergedContextProvider(MyContextProvider)
129
- expectTypeOf(contextProvider2).toEqualTypeOf<typeof someContextProvider>()
130
- expectTypeOf(contextProvider3).toEqualTypeOf<typeof contextProvider2>()
126
+ const merged = mergeContextProviders(MyContextProvider)
127
+ const mergedGen = mergeContextProviders(MyContextProviderGen)
131
128
 
132
- export const contextProvider2Gen = ContextProvider(mergedGen)
133
- export const contextProvider3Gen = MergedContextProvider(MyContextProviderGen)
134
- expectTypeOf(contextProvider2Gen).toEqualTypeOf<typeof someContextProvider>()
135
- expectTypeOf(contextProvider3Gen).toEqualTypeOf<typeof contextProvider2Gen>()
129
+ const contextProvider2 = ContextProvider(merged)
130
+ const contextProvider3 = MergedContextProvider(MyContextProvider)
131
+ expectTypeOf(contextProvider2).toEqualTypeOf<typeof someContextProvider>()
132
+ expectTypeOf(contextProvider3).toEqualTypeOf<typeof contextProvider2>()
136
133
 
137
- expectTypeOf(contextProvider2Gen).toEqualTypeOf<typeof contextProvider2>()
138
- expectTypeOf(contextProvider3Gen).toEqualTypeOf<typeof contextProvider3>()
134
+ const contextProvider2Gen = ContextProvider(mergedGen)
135
+ const contextProvider3Gen = MergedContextProvider(MyContextProviderGen)
136
+ expectTypeOf(contextProvider2Gen).toEqualTypeOf<typeof someContextProvider>()
137
+ expectTypeOf(contextProvider3Gen).toEqualTypeOf<typeof contextProvider2Gen>()
139
138
 
140
- const merged2 = mergeContextProviders(MyContextProvider, MyContextProvider2)
141
- export const contextProvider22 = ContextProvider(merged2)
142
- export const contextProvider23 = MergedContextProvider(MyContextProvider, MyContextProvider2)
143
- expectTypeOf(contextProvider23).toEqualTypeOf<typeof contextProvider22>()
139
+ expectTypeOf(contextProvider2Gen).toEqualTypeOf<typeof contextProvider2>()
140
+ expectTypeOf(contextProvider3Gen).toEqualTypeOf<typeof contextProvider3>()
144
141
 
145
- const merged2Gen = mergeContextProviders(MyContextProviderGen, MyContextProvider2Gen)
146
- export const contextProvider22Gen = ContextProvider(merged2Gen)
147
- export const contextProvider23Gen = MergedContextProvider(MyContextProviderGen, MyContextProvider2Gen)
148
- expectTypeOf(contextProvider23Gen).toEqualTypeOf<typeof contextProvider22Gen>()
142
+ const merged2 = mergeContextProviders(MyContextProvider, MyContextProvider2)
143
+ const contextProvider22 = ContextProvider(merged2)
144
+ const contextProvider23 = MergedContextProvider(MyContextProvider, MyContextProvider2)
145
+ expectTypeOf(contextProvider23).toEqualTypeOf<typeof contextProvider22>()
149
146
 
150
- expectTypeOf(contextProvider22Gen).toEqualTypeOf<typeof contextProvider22>()
151
- expectTypeOf(contextProvider23Gen).toEqualTypeOf<typeof contextProvider23>()
147
+ const merged2Gen = mergeContextProviders(MyContextProviderGen, MyContextProvider2Gen)
148
+ const contextProvider22Gen = ContextProvider(merged2Gen)
149
+ const contextProvider23Gen = MergedContextProvider(MyContextProviderGen, MyContextProvider2Gen)
150
+ expectTypeOf(contextProvider23Gen).toEqualTypeOf<typeof contextProvider22Gen>()
151
+
152
+ expectTypeOf(contextProvider22Gen).toEqualTypeOf<typeof contextProvider22>()
153
+ expectTypeOf(contextProvider23Gen).toEqualTypeOf<typeof contextProvider23>()
154
+ })
@@ -6,7 +6,7 @@ import { Context, Effect, type Layer, S, Scope } from "effect-app"
6
6
  import { InvalidStateError, makeRpcClient, NotLoggedInError, UnauthorizedError } from "effect-app/client"
7
7
  import { DefaultGenericMiddlewares, makeMiddleware, Middleware, Tag } from "../src/api/routing/middleware.js"
8
8
  import { sort } from "../src/api/routing/tsort.js"
9
- import { AllowAnonymous, CustomError1, type RequestContextMap, RequireRoles, Some, SomeElse, SomeService, Test } from "./fixtures.js"
9
+ import { AllowAnonymous, CustomError1, RequestContextMap, RequireRoles, Some, SomeElse, SomeService, Test } from "./fixtures.js"
10
10
 
11
11
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
12
12
  class MyContextProvider extends Middleware.Tag<MyContextProvider>()("MyContextProvider", {
@@ -55,7 +55,6 @@ class MyContextProvider2 extends Middleware.Tag<MyContextProvider2>()("MyContext
55
55
  const Str = Context.GenericTag<"str", "str">("str")
56
56
 
57
57
  export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
58
- provides: SomeService,
59
58
  wrap: true
60
59
  })({
61
60
  effect: Effect.gen(function*() {
@@ -64,7 +63,7 @@ export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
64
63
  return ({ next }) =>
65
64
  Effect.gen(function*() {
66
65
  // yield* Effect.context<"test-dep2">()
67
- return yield* next.pipe(Effect.provideService(SomeService, null as any))
66
+ return yield* next
68
67
  })
69
68
  })
70
69
  }) {
@@ -76,23 +75,59 @@ const genericMiddlewares = [
76
75
  MyContextProvider2
77
76
  ] as const
78
77
 
79
- const middleware = makeMiddleware<RequestContextMap>()
78
+ const middleware = makeMiddleware<RequestContextMap>(RequestContextMap)
80
79
  .middleware(MyContextProvider)
81
80
  .middleware(
82
81
  RequireRoles,
83
82
  Test
84
83
  )
84
+ // AllowAnonymous provided after RequireRoles so that RequireRoles can access what AllowAnonymous provides
85
85
  .middleware(AllowAnonymous)
86
86
  .middleware(...genericMiddlewares)
87
- // dependencies: [Layer.effect(Str2, Str)],
88
87
 
89
- const middleware2 = makeMiddleware<RequestContextMap>()
88
+ const middlewareBis = makeMiddleware<RequestContextMap>(RequestContextMap)
89
+ .middleware(MyContextProvider)
90
+ .middleware(
91
+ RequireRoles,
92
+ Test
93
+ )
94
+ // testing sideways elimination
95
+ .middleware(AllowAnonymous, ...genericMiddlewares)
96
+
97
+ expectTypeOf(middleware).toEqualTypeOf<typeof middlewareBis>()
98
+
99
+ const middlewareTrisWip = makeMiddleware<RequestContextMap>(RequestContextMap)
100
+ .middleware(
101
+ MyContextProvider,
102
+ RequireRoles,
103
+ Test
104
+ )
105
+ .missing
106
+
107
+ expectTypeOf(middlewareTrisWip).toEqualTypeOf<{
108
+ missingDynamicMiddlewares: "allowAnonymous"
109
+ missingContext: SomeElse
110
+ }>()
111
+
112
+ // testing more sideways elimination]
113
+ const middlewareQuater = makeMiddleware<RequestContextMap>(RequestContextMap)
114
+ .middleware(
115
+ MyContextProvider,
116
+ RequireRoles,
117
+ Test,
118
+ AllowAnonymous,
119
+ ...genericMiddlewares
120
+ )
121
+
122
+ expectTypeOf(middleware).toEqualTypeOf<typeof middlewareQuater>()
123
+
124
+ const middleware2 = makeMiddleware<RequestContextMap>(RequestContextMap)
90
125
  .middleware(MyContextProvider)
91
126
  .middleware(RequireRoles, Test)
92
127
  .middleware(AllowAnonymous)
93
128
  .middleware(...DefaultGenericMiddlewares, BogusMiddleware, MyContextProvider2)
94
129
 
95
- export const middleware3 = makeMiddleware<RequestContextMap>()
130
+ export const middleware3 = makeMiddleware<RequestContextMap>(RequestContextMap)
96
131
  .middleware(...genericMiddlewares)
97
132
  .middleware(AllowAnonymous, RequireRoles)
98
133
  .middleware(Test)
@@ -246,7 +281,7 @@ it("sorts based on requirements", () => {
246
281
 
247
282
  // eslint-disable-next-line unused-imports/no-unused-vars
248
283
  const matched = matchAll({ router })
249
- expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | Some | "str">()
284
+ expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | "str">()
250
285
 
251
286
  type makeContext = MakeContext<typeof router.make>
252
287
  expectTypeOf({} as MakeErrors<typeof router.make>).toEqualTypeOf<InvalidStateError>()
@@ -307,7 +342,7 @@ const router2 = r2.Router(Something)({
307
342
 
308
343
  // eslint-disable-next-line unused-imports/no-unused-vars
309
344
  const matched2 = matchAll({ router: router2 })
310
- expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<Some | SomeService | "str">()
345
+ expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<SomeService | "str">()
311
346
 
312
347
  type makeContext2 = MakeContext<typeof router2.make>
313
348
  expectTypeOf({} as MakeErrors<typeof router2.make>).toEqualTypeOf<InvalidStateError>()
@@ -1 +1 @@
1
- {"version":3,"file":"contextProvider.test.d.ts","sourceRoot":"","sources":["../contextProvider.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AA8EzE,eAAO,MAAM,mBAAmB;;CAkB9B,CAAA;AACF,eAAO,MAAM,sBAAsB;;CAkBjC,CAAA;AAMF,eAAO,MAAM,gBAAgB;;CAA0B,CAAA;AACvD,eAAO,MAAM,gBAAgB,kMAA2C,CAAA;AAIxE,eAAO,MAAM,mBAAmB;;CAA6B,CAAA;AAC7D,eAAO,MAAM,mBAAmB,kMAA8C,CAAA;AAQ9E,eAAO,MAAM,iBAAiB;;CAA2B,CAAA;AACzD,eAAO,MAAM,iBAAiB,6MAA+D,CAAA;AAI7F,eAAO,MAAM,oBAAoB;;CAA8B,CAAA;AAC/D,eAAO,MAAM,oBAAoB,6MAAqE,CAAA"}
1
+ {"version":3,"file":"contextProvider.test.d.ts","sourceRoot":"","sources":["../contextProvider.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,IAAI,EAAY,WAAW,EAAE,MAAM,eAAe,CAAA;AA8EzE,eAAO,MAAM,mBAAmB;;CAkB9B,CAAA;AACF,eAAO,MAAM,sBAAsB;;CAkBjC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"controller.test.d.ts","sourceRoot":"","sources":["../controller.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAc,MAAM,+BAA+B,CAAA;AAE7F,OAAO,EAAW,MAAM,EAAE,KAAK,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElE,OAAO,EAA6C,UAAU,EAAO,MAAM,kCAAkC,CAAA;AAE7G,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;;;;;;AAgCrI,cAAM,kBAAmB,SAAQ,uBAU/B;CAAG;;;;;;;AAML,qBAAa,eAAgB,SAAQ,oBAanC;CACD;AAwBD,eAAO,MAAM,WAAW;;;;;YAIM,CAAA;AAE9B,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,cAAc,CAAC,EAAE,IAAI,CAAA;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/B,CAAA;AACD,eAAO,MAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAI/B,CAAA;;;;;;;;;;AAEF,qBAAa,GAAI,SAAQ,QAA0C;CAAG;;;;;;;;;;AACtE,qBAAa,GAAI,SAAQ,QAA0C;CAAG;;;;;;;;;;;;AAEtE,qBAAa,WAAY,SAAQ,gBAEV;CAAG;;;;;;;;;;;;AAgB1B,qBAAa,YAAa,SAAQ,iBAET;CAAG;;;;;;;;;;;;AAE5B,qBAAa,aAAc,SAAQ,kBAEA;CAAG;;;;;AAItC,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;;;;;AASL,qBAAa,aAAc,SAAQ,kBAOjC;CAAG;;;;;AAEL,qBAAa,iBAAkB,SAAQ,sBAKrC;CAAG;AAEL,eAAO,MAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAE,QAAQ;;;;;2HAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAAiC,CAAA;AAE1E,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAgC,CAAA"}
1
+ {"version":3,"file":"controller.test.d.ts","sourceRoot":"","sources":["../controller.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAc,MAAM,+BAA+B,CAAA;AAE7F,OAAO,EAAW,MAAM,EAAE,KAAK,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElE,OAAO,EAA6C,UAAU,EAAO,MAAM,kCAAkC,CAAA;AAE7G,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;;;;;;AAgChI,cAAM,kBAAmB,SAAQ,uBAU/B;CAAG;;;;;;AAML,qBAAa,eAAgB,SAAQ,oBAYnC;CACD;AA4DD,eAAO,MAAM,WAAW;;;;;;YAIM,CAAA;AAE9B,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,cAAc,CAAC,EAAE,IAAI,CAAA;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/B,CAAA;AACD,eAAO,MAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAI/B,CAAA;;;;;;;;;;AAEF,qBAAa,GAAI,SAAQ,QAA0C;CAAG;;;;;;;;;;AACtE,qBAAa,GAAI,SAAQ,QAA0C;CAAG;;;;;;;;;;;;AAEtE,qBAAa,WAAY,SAAQ,gBAEV;CAAG;;;;;;;;;;;;AAgB1B,qBAAa,YAAa,SAAQ,iBAET;CAAG;;;;;;;;;;;;AAE5B,qBAAa,aAAc,SAAQ,kBAEA;CAAG;;;;;AAItC,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;;;;;AASL,qBAAa,aAAc,SAAQ,kBAOjC;CAAG;;;;;AAEL,qBAAa,iBAAkB,SAAQ,sBAKrC;CAAG;AAEL,eAAO,MAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAE,QAAQ;;;;;2HAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAAiC,CAAA;AAE1E,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAgC,CAAA"}