@effect-app/infra 2.85.0 → 2.87.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 (66) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/api/layerUtils.d.ts +4 -8
  3. package/dist/api/layerUtils.d.ts.map +1 -1
  4. package/dist/api/layerUtils.js +3 -11
  5. package/dist/api/routing/middleware/ContextProvider.d.ts +2 -2
  6. package/dist/api/routing/middleware/ContextProvider.d.ts.map +1 -1
  7. package/dist/api/routing/middleware/RouterMiddleware.d.ts +33 -0
  8. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -0
  9. package/dist/api/routing/middleware/RouterMiddleware.js +5 -0
  10. package/dist/api/routing/middleware/RpcMiddleware.d.ts +199 -0
  11. package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -0
  12. package/dist/api/routing/middleware/RpcMiddleware.js +14 -0
  13. package/dist/api/routing/middleware/dynamic-middleware.d.ts +3 -13
  14. package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
  15. package/dist/api/routing/middleware/dynamic-middleware.js +2 -18
  16. package/dist/api/routing/middleware/generic-middleware.d.ts +15 -22
  17. package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
  18. package/dist/api/routing/middleware/generic-middleware.js +13 -9
  19. package/dist/api/routing/middleware/middleware-api.d.ts +55 -8
  20. package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
  21. package/dist/api/routing/middleware/middleware-api.js +50 -14
  22. package/dist/api/routing/middleware/middleware.d.ts +8 -7
  23. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  24. package/dist/api/routing/middleware/middleware.js +6 -5
  25. package/dist/api/routing/middleware.d.ts +2 -1
  26. package/dist/api/routing/middleware.d.ts.map +1 -1
  27. package/dist/api/routing/middleware.js +3 -2
  28. package/dist/api/routing/tsort.d.ts +2 -2
  29. package/dist/api/routing/tsort.d.ts.map +1 -1
  30. package/dist/api/routing/tsort.js +1 -1
  31. package/dist/api/routing.d.ts +0 -1
  32. package/dist/api/routing.d.ts.map +1 -1
  33. package/dist/api/routing.js +2 -3
  34. package/package.json +9 -5
  35. package/src/api/layerUtils.ts +7 -21
  36. package/src/api/routing/middleware/ContextProvider.ts +5 -5
  37. package/src/api/routing/middleware/RouterMiddleware.ts +149 -0
  38. package/src/api/routing/middleware/RpcMiddleware.ts +287 -0
  39. package/src/api/routing/middleware/dynamic-middleware.ts +9 -54
  40. package/src/api/routing/middleware/generic-middleware.ts +33 -33
  41. package/src/api/routing/middleware/middleware-api.ts +202 -32
  42. package/src/api/routing/middleware/middleware.ts +13 -5
  43. package/src/api/routing/middleware.ts +2 -1
  44. package/src/api/routing/tsort.ts +2 -2
  45. package/src/api/routing.ts +1 -9
  46. package/test/contextProvider.test.ts +1 -2
  47. package/test/controller.test.ts +35 -155
  48. package/test/dist/contextProvider.test.d.ts.map +1 -1
  49. package/test/dist/controller.test.d.ts.map +1 -1
  50. package/test/dist/fixtures.d.ts +146 -0
  51. package/test/dist/fixtures.d.ts.map +1 -0
  52. package/test/dist/fixtures.js +82 -0
  53. package/test/dist/layerUtils.test.d.ts.map +1 -0
  54. package/test/dist/query.test.d.ts.map +1 -1
  55. package/test/dist/requires.d.ts +21 -0
  56. package/test/dist/requires.d.ts.map +1 -0
  57. package/test/dist/requires.js +27 -0
  58. package/test/dist/requires.test.d.ts.map +1 -0
  59. package/test/fixtures.ts +102 -0
  60. package/test/layerUtils.test.ts +19 -0
  61. package/test/query.test.ts +2 -4
  62. package/test/requires.test.ts +156 -0
  63. package/dist/api/routing/middleware/DynamicMiddleware.d.ts +0 -215
  64. package/dist/api/routing/middleware/DynamicMiddleware.d.ts.map +0 -1
  65. package/dist/api/routing/middleware/DynamicMiddleware.js +0 -168
  66. package/src/api/routing/middleware/DynamicMiddleware.ts +0 -693
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "2.85.0",
3
+ "version": "2.87.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -13,7 +13,7 @@
13
13
  "proper-lockfile": "^4.1.2",
14
14
  "pure-rand": "7.0.1",
15
15
  "query-string": "^9.2.2",
16
- "effect-app": "2.51.0"
16
+ "effect-app": "2.52.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@azure/cosmos": "^4.5.0",
@@ -306,9 +306,13 @@
306
306
  "types": "./dist/api/routing/middleware/ContextProvider.d.ts",
307
307
  "default": "./dist/api/routing/middleware/ContextProvider.js"
308
308
  },
309
- "./api/routing/middleware/DynamicMiddleware": {
310
- "types": "./dist/api/routing/middleware/DynamicMiddleware.d.ts",
311
- "default": "./dist/api/routing/middleware/DynamicMiddleware.js"
309
+ "./api/routing/middleware/RouterMiddleware": {
310
+ "types": "./dist/api/routing/middleware/RouterMiddleware.d.ts",
311
+ "default": "./dist/api/routing/middleware/RouterMiddleware.js"
312
+ },
313
+ "./api/routing/middleware/RpcMiddleware": {
314
+ "types": "./dist/api/routing/middleware/RpcMiddleware.d.ts",
315
+ "default": "./dist/api/routing/middleware/RpcMiddleware.js"
312
316
  },
313
317
  "./api/routing/middleware/dynamic-middleware": {
314
318
  "types": "./dist/api/routing/middleware/dynamic-middleware.d.ts",
@@ -7,19 +7,19 @@ export namespace LayerUtils {
7
7
  NonEmptyReadonlyArray<Layer.Layer.Any> ? {
8
8
  [k in keyof Layers]: Layer.Layer.Success<Layers[k]>
9
9
  }[number]
10
- : never
10
+ : Layer.Layer.Success<Layers[number]>
11
11
 
12
12
  export type GetLayersContext<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
13
13
  NonEmptyReadonlyArray<Layer.Layer.Any> ? {
14
14
  [k in keyof Layers]: Layer.Layer.Context<Layers[k]>
15
15
  }[number]
16
- : never
16
+ : Layer.Layer.Context<Layers[number]>
17
17
 
18
18
  export type GetLayersError<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
19
19
  NonEmptyReadonlyArray<Layer.Layer.Any> ? {
20
20
  [k in keyof Layers]: Layer.Layer.Error<Layers[k]>
21
21
  }[number]
22
- : never
22
+ : Layer.Layer.Error<Layers[number]>
23
23
  }
24
24
 
25
25
  export type ContextTagWithDefault<Id, A, LayerE, LayerR> =
@@ -35,25 +35,11 @@ export namespace ContextTagWithDefault {
35
35
  export type GetContext<T> = T extends Context.Context<infer Y> ? Y : never
36
36
 
37
37
  export const mergeContexts = Effect.fnUntraced(
38
- function*<T extends readonly { maker: any; handle: Effect<Context<any>> }[]>(makers: T) {
38
+ function*<T extends readonly { maker: any; handle: Effect<Context<any> | Option<Context<any>>> }[]>(makers: T) {
39
39
  let context = Context.empty()
40
40
  for (const mw of makers) {
41
- const moreContext = yield* mw.handle.pipe(Effect.provide(context))
42
- yield* InfraLogger.logDebug(
43
- "Built dynamic context for middleware" + (mw.maker.key ?? mw.maker),
44
- (moreContext as any).toJSON().services
45
- )
46
- context = Context.merge(context, moreContext)
47
- }
48
- return context as Context.Context<Effect.Success<T[number]["handle"]>>
49
- }
50
- )
51
-
52
- export const mergeOptionContexts = Effect.fnUntraced(
53
- function*<T extends readonly { maker: any; handle: Effect<Option<Context<any>>> }[]>(makers: T) {
54
- let context = Context.empty()
55
- for (const mw of makers) {
56
- const moreContext = yield* mw.handle.pipe(Effect.provide(context))
41
+ const ctx = yield* mw.handle.pipe(Effect.provide(context))
42
+ const moreContext = Context.isContext(ctx) ? Option.some(ctx) : ctx
57
43
  yield* InfraLogger.logDebug(
58
44
  "Built dynamic context for middleware" + (mw.maker.key ?? mw.maker),
59
45
  Option.map(moreContext, (c) => (c as any).toJSON().services)
@@ -62,6 +48,6 @@ export const mergeOptionContexts = Effect.fnUntraced(
62
48
  context = Context.merge(context, moreContext.value)
63
49
  }
64
50
  }
65
- return context
51
+ return context as Context.Context<Effect.Success<T[number]["handle"]>>
66
52
  }
67
53
  )
@@ -87,9 +87,9 @@ export const mergeContextProviders = <
87
87
  effect: Effect.Effect<
88
88
  Effect.Effect<
89
89
  // we need to merge all contexts into one
90
- Context.Context<GetContext<EffectGenUtils.Success<Tag.Service<TDeps[number]>>>>,
90
+ Context.Context<GetContext<EffectGenUtils.Success<Tag.Identifier<TDeps[number]>>>>,
91
91
  never,
92
- EffectGenUtils.Context<Tag.Service<TDeps[number]>>
92
+ EffectGenUtils.Context<Tag.Identifier<TDeps[number]>>
93
93
  >,
94
94
  LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
95
95
  LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
@@ -174,13 +174,13 @@ export const MergedContextProvider = <
174
174
  ContextProviderId,
175
175
  Effect.Effect<
176
176
  // we need to merge all contexts into one
177
- Context.Context<GetContext<EffectGenUtils.Success<Tag.Service<TDeps[number]>>>>,
177
+ Context.Context<GetContext<EffectGenUtils.Success<Tag.Identifier<TDeps[number]>>>>,
178
178
  never,
179
- EffectGenUtils.Context<Tag.Service<TDeps[number]>>
179
+ EffectGenUtils.Context<Tag.Identifier<TDeps[number]>>
180
180
  >,
181
181
  LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
182
182
  | Exclude<
183
- Tag.Service<TDeps[number]>,
183
+ Tag.Identifier<TDeps[number]>,
184
184
  LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
185
185
  >
186
186
  | LayerUtils.GetLayersContext<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
@@ -0,0 +1,149 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
3
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4
+ import { type Effect, type Request, type S, type Scope } from "effect-app"
5
+ import type { GetEffectContext, RPCContextMap } from "effect-app/client/req"
6
+ import type * as EffectRequest from "effect/Request"
7
+ import { type ContextTagWithDefault } from "../../layerUtils.js"
8
+ import { type ContextWithLayer } from "./dynamic-middleware.js"
9
+
10
+ // module:
11
+ //
12
+ export type MakeRPCHandlerFactory<
13
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
14
+ MiddlewareR
15
+ > = <
16
+ T extends {
17
+ config?: Partial<Record<keyof RequestContextMap, any>>
18
+ },
19
+ Req extends S.TaggedRequest.All,
20
+ HandlerR
21
+ >(
22
+ schema: T & S.Schema<Req, any, never>,
23
+ next: (
24
+ request: Req,
25
+ headers: any
26
+ ) => Effect.Effect<
27
+ EffectRequest.Request.Success<Req>,
28
+ EffectRequest.Request.Error<Req>,
29
+ // dynamic middlewares removes the dynamic context from HandlerR
30
+ Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>
31
+ >,
32
+ moduleName: string
33
+ ) => (
34
+ req: Req,
35
+ headers: any
36
+ ) => Effect.Effect<
37
+ Request.Request.Success<Req>,
38
+ Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
39
+ // the middleware will remove from HandlerR the dynamic context, but will also add some requirements
40
+ | MiddlewareR
41
+ // & S.Schema<Req, any, never> is useless here but useful when creating the middleware
42
+ | Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>
43
+ >
44
+
45
+ export type RPCHandlerFactory<
46
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
47
+ ContextProviderA
48
+ > = <
49
+ T extends {
50
+ config?: Partial<Record<keyof RequestContextMap, any>>
51
+ },
52
+ Req extends S.TaggedRequest.All,
53
+ HandlerR
54
+ >(
55
+ schema: T & S.Schema<Req, any, never>,
56
+ next: (
57
+ request: Req,
58
+ headers: any
59
+ ) => Effect.Effect<
60
+ EffectRequest.Request.Success<Req>,
61
+ EffectRequest.Request.Error<Req>,
62
+ HandlerR
63
+ >,
64
+ moduleName: string
65
+ ) => (
66
+ req: Req,
67
+ headers: any
68
+ ) => Effect.Effect<
69
+ Request.Request.Success<Req>,
70
+ Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
71
+ | Scope.Scope // because of the context provider and the middleware (Middleware)
72
+ | Exclude<
73
+ // the middleware will remove from HandlerR the dynamic context
74
+ // & S.Schema<Req, any, never> is useless here but useful when creating the middleware
75
+ Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>,
76
+ // the context provider provides additional stuff both to the middleware and the next
77
+ ContextProviderA
78
+ >
79
+ >
80
+
81
+ export type RequestContextMapProvider<RequestContextMap extends Record<string, RPCContextMap.Any>> = {
82
+ [K in keyof RequestContextMap]: ContextWithLayer.Base<
83
+ { [K in keyof RequestContextMap]?: RequestContextMap[K]["contextActivation"] },
84
+ RequestContextMap[K]["service"],
85
+ S.Schema.Type<RequestContextMap[K]["error"]>
86
+ >
87
+ }
88
+
89
+ export interface MiddlewareMakerId {
90
+ _tag: "MiddlewareMaker"
91
+ }
92
+
93
+ export type RouterMiddleware<
94
+ RequestContextMap extends Record<string, RPCContextMap.Any>, // what services will the middlware provide dynamically to the next, or raise errors.
95
+ MakeMiddlewareE, // what the middleware construction can fail with
96
+ MakeMiddlewareR, // what the middlware requires to be constructed
97
+ ContextProviderA // what the context provider provides
98
+ > = ContextTagWithDefault<
99
+ MiddlewareMakerId,
100
+ {
101
+ _tag: "MiddlewareMaker"
102
+ effect: RPCHandlerFactory<RequestContextMap, ContextProviderA>
103
+ },
104
+ MakeMiddlewareE,
105
+ MakeMiddlewareR
106
+ >
107
+
108
+ export type RequestContextMapErrors<RequestContextMap extends Record<string, RPCContextMap.Any>> = S.Schema.Type<
109
+ RequestContextMap[keyof RequestContextMap]["error"]
110
+ >
111
+
112
+ // it just provides the right types without cluttering the implementation with them
113
+ export function makeRpcEffect<
114
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
115
+ ContextProviderA
116
+ >() {
117
+ return (
118
+ cb: <
119
+ T extends {
120
+ config?: Partial<Record<keyof RequestContextMap, any>>
121
+ },
122
+ Req extends S.TaggedRequest.All,
123
+ HandlerR
124
+ >(
125
+ schema: T & S.Schema<Req, any, never>,
126
+ next: (
127
+ request: Req,
128
+ headers: any
129
+ ) => Effect.Effect<
130
+ EffectRequest.Request.Success<Req>,
131
+ EffectRequest.Request.Error<Req>,
132
+ HandlerR
133
+ >,
134
+ moduleName: string
135
+ ) => (
136
+ req: Req,
137
+ headers: any
138
+ ) => Effect.Effect<
139
+ Request.Request.Success<Req>,
140
+ Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
141
+ | Scope.Scope // the context provider may require Scope to run
142
+ | Exclude<
143
+ // it can also be removed from HandlerR
144
+ Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>,
145
+ ContextProviderA
146
+ >
147
+ >
148
+ ) => cb
149
+ }
@@ -0,0 +1,287 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
3
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4
+ import { type Rpc, RpcMiddleware } from "@effect/rpc"
5
+ import { type SuccessValue, type TypeId } from "@effect/rpc/RpcMiddleware"
6
+ import { type Context, type Effect, Layer, type NonEmptyReadonlyArray, type Option, type S, type Schema, type Scope, Unify } from "effect-app"
7
+ import type { AnyService, ContextRepr, RPCContextMap } from "effect-app/client/req"
8
+ import { type HttpHeaders } from "effect-app/http"
9
+ import { type TagUnify, type TagUnifyIgnore } from "effect/Context"
10
+ import { type LayerUtils } from "../../layerUtils.js"
11
+
12
+ // updated to support Scope.Scope
13
+ export interface RpcMiddleware<Provides, E, Requires> {
14
+ (options: {
15
+ readonly clientId: number
16
+ readonly rpc: Rpc.AnyWithProps
17
+ readonly payload: unknown
18
+ readonly headers: HttpHeaders.Headers
19
+ }): Effect.Effect<Provides, E, Scope.Scope | Requires>
20
+ }
21
+ export interface RpcMiddlewareWrap<Provides, E, Requires> {
22
+ (options: {
23
+ readonly clientId: number
24
+ readonly rpc: Rpc.AnyWithProps
25
+ readonly payload: unknown
26
+ readonly headers: HttpHeaders.Headers
27
+ readonly next: Effect.Effect<SuccessValue, E, Provides | Scope.Scope | Requires>
28
+ }): Effect.Effect<SuccessValue, E, Scope.Scope | Requires>
29
+ }
30
+
31
+ type RpcOptionsOriginal = {
32
+ readonly wrap?: boolean
33
+ readonly optional?: boolean
34
+ readonly failure?: Schema.Schema.All
35
+ readonly provides?: AnyService
36
+ readonly requiredForClient?: boolean
37
+ }
38
+
39
+ export type RpcDynamic<Key extends string, A extends RPCContextMap.Any> = {
40
+ key: Key
41
+ settings: A
42
+ }
43
+
44
+ export type AnyDynamic = { dynamic: RpcDynamic<any, any> }
45
+
46
+ export type DependsOn = {
47
+ readonly dependsOn: NonEmptyReadonlyArray<AnyDynamic> | undefined
48
+ }
49
+
50
+ type RpcOptionsDynamic<Key extends string, A extends RPCContextMap.Any> = RpcOptionsOriginal & {
51
+ readonly dynamic: RpcDynamic<Key, A>
52
+ readonly dependsOn?: NonEmptyReadonlyArray<AnyDynamic> | undefined
53
+ }
54
+
55
+ export type Dynamic<Options> = Options extends RpcOptionsDynamic<any, any> ? true : false
56
+
57
+ export interface RpcMiddlewareDynamicWrap<E, R, Config> {
58
+ (options: {
59
+ readonly next: Effect.Effect<SuccessValue, E, Scope.Scope | R>
60
+ readonly config: Config // todo
61
+ readonly clientId: number
62
+ readonly rpc: Rpc.AnyWithProps
63
+ readonly payload: unknown
64
+ readonly headers: HttpHeaders.Headers
65
+ }): Effect.Effect<
66
+ SuccessValue,
67
+ E,
68
+ Scope.Scope | R
69
+ >
70
+ }
71
+
72
+ export interface RpcMiddlewareDynamicNormal<A, E, R, Config> {
73
+ (options: {
74
+ readonly config: Config // todo
75
+ readonly clientId: number
76
+ readonly rpc: Rpc.AnyWithProps
77
+ readonly payload: unknown
78
+ readonly headers: HttpHeaders.Headers
79
+ }): Effect.Effect<
80
+ Option.Option<A>,
81
+ E,
82
+ Scope.Scope | R
83
+ >
84
+ }
85
+
86
+ export interface TagClassAny extends Context.Tag<any, any> {
87
+ readonly [TypeId]: TypeId
88
+ readonly optional: boolean
89
+ readonly provides?: Context.Tag<any, any> | ContextRepr | undefined
90
+ readonly requires?: Context.Tag<any, any> | ContextRepr | undefined
91
+ readonly failure: Schema.Schema.All
92
+ readonly requiredForClient: boolean
93
+ readonly wrap: boolean
94
+ readonly dynamic?: RpcDynamic<any, any> | undefined
95
+ readonly dependsOn?: NonEmptyReadonlyArray<AnyDynamic> | undefined
96
+ }
97
+
98
+ export declare namespace TagClass {
99
+ /**
100
+ * @since 1.0.0
101
+ * @category models
102
+ */
103
+ export type Provides<Options> = Options extends {
104
+ readonly provides: Context.Tag<any, any>
105
+ readonly optional?: false
106
+ } ? Context.Tag.Identifier<Options["provides"]>
107
+ : Options extends {
108
+ readonly provides: ContextRepr
109
+ readonly optional?: false
110
+ } ? ContextRepr.Identifier<Options["provides"]>
111
+ : never
112
+
113
+ /**
114
+ * @since 1.0.0
115
+ * @category models
116
+ */
117
+ export type Requires<Options> = Options extends {
118
+ readonly requires: Context.Tag<any, any>
119
+ } ? Context.Tag.Identifier<Options["requires"]>
120
+ : Options extends {
121
+ readonly requires: ContextRepr
122
+ } ? ContextRepr.Identifier<Options["requires"]>
123
+ : never
124
+
125
+ /**
126
+ * @since 1.0.0
127
+ * @category models
128
+ */
129
+ export type Service<Options> = Options extends { readonly provides: Context.Tag<any, any> }
130
+ ? Context.Tag.Service<Options["provides"]>
131
+ : Options extends { readonly dynamic: RpcDynamic<any, infer A> }
132
+ ? Options extends { wrap: true } ? void : AnyService.Bla<A["service"]>
133
+ : Options extends { readonly provides: ContextRepr } ? Context.Context<ContextRepr.Identifier<Options["provides"]>>
134
+ : void
135
+
136
+ /**
137
+ * @since 1.0.0
138
+ * @category models
139
+ */
140
+ export type FailureSchema<Options> = Options extends
141
+ { readonly failure: Schema.Schema.All; readonly optional?: false } ? Options["failure"]
142
+ : Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["error"]
143
+ : typeof Schema.Never
144
+
145
+ /**
146
+ * @since 1.0.0
147
+ * @category models
148
+ */
149
+ export type Failure<Options> = Options extends
150
+ { readonly failure: Schema.Schema<infer _A, infer _I, infer _R>; readonly optional?: false } ? _A
151
+ : Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? S.Schema.Type<A["error"]>
152
+ : never
153
+
154
+ /**
155
+ * @since 1.0.0
156
+ * @category models
157
+ */
158
+ export type FailureContext<Options> = Schema.Schema.Context<FailureSchema<Options>>
159
+
160
+ /**
161
+ * @since 1.0.0
162
+ * @category models
163
+ */
164
+ export type FailureService<Options> = Optional<Options> extends true ? unknown : Failure<Options>
165
+
166
+ /**
167
+ * @since 1.0.0
168
+ * @category models
169
+ */
170
+ export type Optional<Options> = Options extends { readonly optional: true } ? true : false
171
+
172
+ /**
173
+ * @since 1.0.0
174
+ * @category models
175
+ */
176
+ export type RequiredForClient<Options> = Options extends { readonly requiredForClient: true } ? true : false
177
+
178
+ /**
179
+ * @since 1.0.0
180
+ * @category models
181
+ */
182
+ export type Wrap<Options> = Options extends { readonly wrap: true } ? true : false
183
+
184
+ /**
185
+ * @since 1.0.0
186
+ * @category models
187
+ */
188
+ export interface Base<Self, Name extends string, Options, Service> extends Context.Tag<Self, Service> {
189
+ new(_: never): Context.TagClassShape<Name, Service>
190
+ readonly [TypeId]: TypeId
191
+ readonly optional: Optional<Options>
192
+ readonly failure: FailureSchema<Options>
193
+ readonly provides: Options extends { readonly provides: Context.Tag<any, any> } ? Options["provides"]
194
+ : Options extends { readonly provides: ContextRepr } ? Options["provides"]
195
+ : undefined
196
+ readonly requires: Options extends { readonly requires: Context.Tag<any, any> } ? Options["requires"]
197
+ : Options extends { readonly requires: ContextRepr } ? Options["requires"]
198
+ : undefined
199
+ readonly dynamic: Options extends RpcOptionsDynamic<any, any> ? Options["dynamic"]
200
+ : undefined
201
+ readonly dependsOn: Options extends DependsOn ? Options["dependsOn"] : undefined
202
+ readonly requiredForClient: RequiredForClient<Options>
203
+ readonly wrap: Wrap<Options>
204
+ }
205
+ }
206
+
207
+ export interface TagClass<
208
+ Self,
209
+ Name extends string,
210
+ Options
211
+ > extends
212
+ TagClass.Base<
213
+ Self,
214
+ Name,
215
+ Options,
216
+ Options extends RpcOptionsDynamic<any, any> ? TagClass.Wrap<Options> extends true ? RpcMiddlewareDynamicWrap<
217
+ TagClass.FailureService<Options>,
218
+ TagClass.Requires<Options>,
219
+ { [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
220
+ >
221
+ : RpcMiddlewareDynamicNormal<
222
+ TagClass.Service<Options>,
223
+ TagClass.FailureService<Options>,
224
+ TagClass.Requires<Options>,
225
+ { [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
226
+ >
227
+ : TagClass.Wrap<Options> extends true ? RpcMiddlewareWrap<
228
+ TagClass.Provides<Options>,
229
+ TagClass.Requires<Options>,
230
+ TagClass.Failure<Options>
231
+ >
232
+ : RpcMiddleware<
233
+ TagClass.Service<Options>,
234
+ TagClass.FailureService<Options>,
235
+ TagClass.Requires<Options>
236
+ >
237
+ >
238
+ {}
239
+
240
+ export const Tag = <Self>() =>
241
+ <
242
+ const Name extends string,
243
+ const Options extends RpcOptionsOriginal | RpcOptionsDynamic<any, any>
244
+ >(
245
+ id: Name,
246
+ options?: Options | undefined
247
+ ) =>
248
+ <E, R, L extends NonEmptyReadonlyArray<Layer.Layer.Any>>(opts: {
249
+ effect: Effect.Effect<
250
+ Options extends RpcOptionsDynamic<any, any> ? TagClass.Wrap<Options> extends true ? RpcMiddlewareDynamicWrap<
251
+ TagClass.FailureService<Options>,
252
+ TagClass.Requires<Options>,
253
+ { [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
254
+ >
255
+ : RpcMiddlewareDynamicNormal<
256
+ TagClass.Service<Options>,
257
+ TagClass.FailureService<Options>,
258
+ TagClass.Requires<Options>,
259
+ { [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
260
+ >
261
+ : TagClass.Wrap<Options> extends true ? RpcMiddlewareWrap<
262
+ TagClass.Provides<Options>,
263
+ TagClass.Failure<Options>,
264
+ TagClass.Requires<Options>
265
+ >
266
+ : RpcMiddleware<
267
+ TagClass.Service<Options>,
268
+ TagClass.FailureService<Options>,
269
+ TagClass.Requires<Options>
270
+ >,
271
+ E,
272
+ R
273
+ >
274
+ dependencies?: L
275
+ }): TagClass<Self, Name, Options> & {
276
+ Default: Layer.Layer<Self, E | LayerUtils.GetLayersError<L>, Exclude<R, LayerUtils.GetLayersSuccess<L>>>
277
+ } =>
278
+ class extends RpcMiddleware.Tag<Self>()(id, options as any) {
279
+ static readonly dynamic = options && "dynamic" in options ? options.dynamic : undefined
280
+ static readonly dependsOn = options && "dependsOn" in options ? options.dependsOn : undefined
281
+ static readonly Default = Layer.scoped(this, opts.effect as any).pipe(
282
+ Layer.provide([Layer.empty, ...opts.dependencies ?? []])
283
+ )
284
+ static override [Unify.typeSymbol]?: unknown
285
+ static override [Unify.unifySymbol]?: TagUnify<typeof this>
286
+ static override [Unify.ignoreSymbol]?: TagUnifyIgnore
287
+ } as any
@@ -1,12 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Array, type Context, Effect, type S } from "effect-app"
3
- import { type GetEffectContext, type RPCContextMap } from "effect-app/client"
4
- import { type Tag } from "effect-app/Context"
5
- import { type HttpHeaders } from "effect-app/http"
6
- import { typedValuesOf } from "effect-app/utils"
7
- import { type ContextTagWithDefault, mergeOptionContexts } from "../../layerUtils.js"
8
- import { sort } from "../tsort.js"
9
- import { type RpcMiddlewareDynamic } from "./DynamicMiddleware.js"
2
+ import { type ContextTagWithDefault } from "../../layerUtils.js"
3
+ import { type RpcMiddlewareDynamicNormal, type RpcMiddlewareDynamicWrap } from "./RpcMiddleware.js"
4
+
5
+ export type RpcMiddlewareDynamic<A, E, R, Config> = [A] extends [void] ? RpcMiddlewareDynamicWrap<E, R, Config>
6
+ : RpcMiddlewareDynamicNormal<A, E, R, Config>
10
7
 
11
8
  export type ContextWithLayer<
12
9
  Config,
@@ -20,13 +17,15 @@ export type ContextWithLayer<
20
17
  & (
21
18
  | ContextTagWithDefault<
22
19
  Id,
23
- RpcMiddlewareDynamic<Service, Error, Config>,
20
+ // todo
21
+ RpcMiddlewareDynamic<Service, Error, any, Config>,
24
22
  LayerE,
25
23
  LayerR
26
24
  >
27
25
  | ContextTagWithDefault<
28
26
  Id,
29
- RpcMiddlewareDynamic<Service, Error, Config>,
27
+ // todo
28
+ RpcMiddlewareDynamic<Service, Error, never, Config>,
30
29
  LayerE,
31
30
  LayerR
32
31
  >
@@ -46,47 +45,3 @@ export namespace ContextWithLayer {
46
45
  any
47
46
  >
48
47
  }
49
-
50
- // Effect Rpc Middleware: no substitute atm. though maybe something could be achieved with Wrap, we just don't have type safety on the Request input etc.
51
- export const implementMiddleware = <T extends Record<string, RPCContextMap.Any>>() =>
52
- <
53
- TI extends {
54
- [K in keyof T]: ContextWithLayer.Base<
55
- { [K in keyof T]?: T[K]["contextActivation"] },
56
- T[K]["service"],
57
- S.Schema.Type<T[K]["error"]>
58
- >
59
- }
60
- >(implementations: TI) => ({
61
- dependencies: typedValuesOf(implementations).map((_) => _.Default) as {
62
- [K in keyof TI]: TI[K]["Default"]
63
- }[keyof TI][],
64
- effect: Effect.gen(function*() {
65
- const sorted = sort(typedValuesOf(implementations))
66
-
67
- const makers = yield* Effect.all(sorted)
68
- return Effect.fnUntraced(
69
- function*(options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }) {
70
- const ctx = yield* mergeOptionContexts(
71
- Array.map(
72
- makers,
73
- (_, i) => ({ maker: sorted[i], handle: (_ as any)(options) as any }) as any
74
- )
75
- )
76
- return ctx as Context.Context<
77
- GetEffectContext<T, typeof options["config"]>
78
- >
79
- }
80
- )
81
- }) as unknown as Effect<
82
- (
83
- options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }
84
- ) => Effect.Effect<
85
- Context.Context<GetEffectContext<T, typeof options["config"]>>,
86
- Effect.Error<ReturnType<Tag.Service<TI[keyof TI]>>>,
87
- Effect.Context<ReturnType<Tag.Identifier<TI[keyof TI]>>>
88
- >,
89
- never,
90
- Tag.Identifier<{ [K in keyof TI]: TI[K] }[keyof TI]>
91
- >
92
- })