@effect-app/infra 3.0.0 → 3.0.2

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 (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/QueueMaker/errors.d.ts +1 -1
  3. package/dist/QueueMaker/errors.d.ts.map +1 -1
  4. package/dist/api/routing/middleware/RouterMiddleware.d.ts +1 -1
  5. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  6. package/dist/api/routing/middleware/middleware.d.ts +1 -2
  7. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  8. package/dist/api/routing/middleware/middleware.js +2 -3
  9. package/dist/api/routing/middleware.d.ts +0 -4
  10. package/dist/api/routing/middleware.d.ts.map +1 -1
  11. package/dist/api/routing/middleware.js +1 -5
  12. package/dist/api/routing.d.ts +5 -13
  13. package/dist/api/routing.d.ts.map +1 -1
  14. package/dist/api/routing.js +4 -13
  15. package/package.json +2 -22
  16. package/src/api/routing/middleware/RouterMiddleware.ts +1 -1
  17. package/src/api/routing/middleware/middleware.ts +1 -3
  18. package/src/api/routing/middleware.ts +0 -4
  19. package/src/api/routing.ts +20 -36
  20. package/test/controller.test.ts +13 -14
  21. package/test/dist/controller.test.d.ts.map +1 -1
  22. package/test/dist/fixtures.d.ts +9 -9
  23. package/test/dist/fixtures.js +2 -2
  24. package/test/dist/requires.test.d.ts.map +1 -1
  25. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  26. package/test/fixtures.ts +1 -1
  27. package/test/requires.test.ts +2 -2
  28. package/test/rpc-multi-middleware.test.ts +2 -2
  29. package/dist/api/routing/middleware/RpcMiddleware.d.ts +0 -188
  30. package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +0 -1
  31. package/dist/api/routing/middleware/RpcMiddleware.js +0 -13
  32. package/dist/api/routing/middleware/RpcMiddlewareX.d.ts +0 -18
  33. package/dist/api/routing/middleware/RpcMiddlewareX.d.ts.map +0 -1
  34. package/dist/api/routing/middleware/RpcMiddlewareX.js +0 -16
  35. package/dist/api/routing/middleware/generic-middleware.d.ts +0 -55
  36. package/dist/api/routing/middleware/generic-middleware.d.ts.map +0 -1
  37. package/dist/api/routing/middleware/generic-middleware.js +0 -67
  38. package/dist/api/routing/middleware/middleware-api.d.ts +0 -107
  39. package/dist/api/routing/middleware/middleware-api.d.ts.map +0 -1
  40. package/dist/api/routing/middleware/middleware-api.js +0 -88
  41. package/dist/api/routing/middleware/middleware-native.d.ts +0 -23
  42. package/dist/api/routing/middleware/middleware-native.d.ts.map +0 -1
  43. package/dist/api/routing/middleware/middleware-native.js +0 -19
  44. package/src/api/routing/middleware/RpcMiddleware.ts +0 -254
  45. package/src/api/routing/middleware/RpcMiddlewareX.ts +0 -70
  46. package/src/api/routing/middleware/generic-middleware.ts +0 -198
  47. package/src/api/routing/middleware/middleware-api.ts +0 -404
  48. package/src/api/routing/middleware/middleware-native.ts +0 -23
@@ -1,198 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { type RpcMiddleware } from "@effect/rpc"
3
- import { Context, Effect, type Layer, type NonEmptyReadonlyArray, Option, type S, type Scope } from "effect-app"
4
- import { type ContextTagArray, type GetContextConfig, type RPCContextMap } from "effect-app/client"
5
- import { type Tag } from "effect/Context"
6
- import { type Simplify } from "effect/Types"
7
- import { InfraLogger } from "../../../logger.js"
8
- import { type MakeTags, type MiddlewareMakerId } from "./middleware-api.js"
9
- import { type RpcMiddlewareWrap, type TagClassAny } from "./RpcMiddleware.js"
10
-
11
- // Effect rpc middleware does not support changing payload or headers, but we do..
12
-
13
- export interface MiddlewareMaker<
14
- RequestContextMap extends Record<string, RPCContextMap.Any>,
15
- MiddlewareProviders extends ReadonlyArray<MiddlewareMaker.Any>
16
- > extends
17
- RpcMiddleware.TagClass<
18
- MiddlewareMakerId,
19
- "MiddlewareMaker",
20
- Simplify<
21
- & { readonly wrap: true }
22
- & (Exclude<
23
- MiddlewareMaker.ManyRequired<MiddlewareProviders>,
24
- MiddlewareMaker.ManyProvided<MiddlewareProviders>
25
- > extends never ? {} : {
26
- readonly requires: MakeTags<
27
- Exclude<
28
- MiddlewareMaker.ManyRequired<MiddlewareProviders>,
29
- MiddlewareMaker.ManyProvided<MiddlewareProviders>
30
- >
31
- >
32
- })
33
- & (MiddlewareMaker.ManyErrors<MiddlewareProviders> extends never ? {}
34
- : {
35
- readonly failure: S.Schema<MiddlewareMaker.ManyErrors<MiddlewareProviders>>
36
- })
37
- & (MiddlewareMaker.ManyProvided<MiddlewareProviders> extends never ? {}
38
- : { readonly provides: MakeTags<MiddlewareMaker.ManyProvided<MiddlewareProviders>> })
39
- >
40
- >
41
- {
42
- readonly layer: Layer.Layer<MiddlewareMakerId, never, Tag.Identifier<MiddlewareProviders[number]>>
43
- readonly requestContext: RequestContextTag<RequestContextMap>
44
- readonly requestContextMap: RequestContextMap
45
- }
46
-
47
- export interface RequestContextTag<RequestContextMap extends Record<string, RPCContextMap.Any>>
48
- extends Context.Tag<"RequestContextConfig", GetContextConfig<RequestContextMap>>
49
- {}
50
-
51
- export namespace MiddlewareMaker {
52
- export type Any = TagClassAny
53
-
54
- export type ApplyServices<A extends TagClassAny, R> = Exclude<R, Provided<A>> | Required<A>
55
-
56
- export type ApplyManyServices<A extends NonEmptyReadonlyArray<TagClassAny>, R> =
57
- | Exclude<R, { [K in keyof A]: Provided<A[K]> }[number]>
58
- | { [K in keyof A]: Required<A[K]> }[number]
59
-
60
- export type ManyProvided<A extends ReadonlyArray<TagClassAny>> = A extends NonEmptyReadonlyArray<TagClassAny>
61
- ? { [K in keyof A]: Provided<A[K]> }[number]
62
- : Provided<A[number]>
63
- export type ManyRequired<A extends ReadonlyArray<TagClassAny>> = A extends NonEmptyReadonlyArray<TagClassAny>
64
- ? { [K in keyof A]: Required<A[K]> }[number]
65
- : Required<A[number]>
66
- export type ManyErrors<A extends ReadonlyArray<TagClassAny>> = A extends NonEmptyReadonlyArray<TagClassAny>
67
- ? { [K in keyof A]: Errors<A[K]> }[number]
68
- : Errors<A[number]>
69
-
70
- export type Provided<T> = T extends TagClassAny
71
- ? T extends { provides: Context.Tag<any, any> } ? Context.Tag.Identifier<T["provides"]>
72
- : T extends { provides: ContextTagArray } ? ContextTagArray.Identifier<T["provides"]>
73
- : never
74
- : never
75
-
76
- export type Errors<T> = T extends TagClassAny ? T extends { failure: S.Schema.Any } ? S.Schema.Type<T["failure"]>
77
- : never
78
- : never
79
-
80
- export type Required<T> = T extends TagClassAny
81
- ? T extends { requires: Context.Tag<any, any> } ? Context.Tag.Identifier<T["requires"]>
82
- : T extends { requires: ContextTagArray } ? ContextTagArray.Identifier<T["requires"]>
83
- : never
84
- : never
85
- }
86
-
87
- export const middlewareMaker = <
88
- MiddlewareProviders extends ReadonlyArray<MiddlewareMaker.Any>
89
- >(middlewares: MiddlewareProviders): Effect.Effect<
90
- RpcMiddlewareWrap<
91
- MiddlewareMaker.ManyProvided<MiddlewareProviders>,
92
- MiddlewareMaker.ManyErrors<MiddlewareProviders>,
93
- Exclude<
94
- MiddlewareMaker.ManyRequired<MiddlewareProviders>,
95
- MiddlewareMaker.ManyProvided<MiddlewareProviders>
96
- > extends never ? never
97
- : Exclude<MiddlewareMaker.ManyRequired<MiddlewareProviders>, MiddlewareMaker.ManyProvided<MiddlewareProviders>>
98
- >
99
- > => {
100
- // we want to run them in reverse order because latter middlewares will provide context to former ones
101
- middlewares = middlewares.toReversed() as any
102
-
103
- return Effect.gen(function*() {
104
- const context = yield* Effect.context()
105
-
106
- // returns a Effect/RpcMiddlewareWrap with Scope in requirements
107
- return (
108
- options: Parameters<
109
- RpcMiddlewareWrap<
110
- MiddlewareMaker.ManyProvided<MiddlewareProviders>,
111
- never,
112
- Scope.Scope
113
- >
114
- >[0]
115
- ) => {
116
- // we start with the actual handler
117
- let handler = options.next
118
-
119
- // inspired from Effect/RpcMiddleware
120
- for (const tag of middlewares) {
121
- if (tag.wrap) {
122
- // use the tag to get the middleware from context
123
- const middleware = Context.unsafeGet(context, tag)
124
-
125
- // wrap the current handler, allowing the middleware to run before and after it
126
- handler = InfraLogger.logDebug("Applying middleware wrap " + tag.key).pipe(
127
- Effect.zipRight(middleware({ ...options, next: handler }))
128
- ) as any
129
- } else if (tag.optional) {
130
- // use the tag to get the middleware from context
131
- // if the middleware fails to run, we will ignore the error
132
- const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
133
-
134
- const previous = handler
135
-
136
- // set the previous handler to run after the middleware
137
- // if the middleware is not present, we just return the previous handler
138
- // otherwise the middleware will provide some context to be provided to the previous handler
139
- handler = InfraLogger.logDebug("Applying middleware optional " + tag.key).pipe(
140
- Effect.zipRight(Effect.matchEffect(middleware(options), {
141
- onFailure: () => previous,
142
- onSuccess: tag.provides !== undefined
143
- ? (value) =>
144
- Context.isContext(value)
145
- ? Effect.provide(previous, value)
146
- : Effect.provideService(previous, tag.provides as any, value)
147
- : (_) => previous
148
- }))
149
- )
150
- } else if (tag.dynamic) {
151
- // use the tag to get the middleware from context
152
- const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
153
-
154
- const previous = handler
155
-
156
- // set the previous handler to run after the middleware
157
- // we do expect the middleware to be present, but the context might not be available
158
- // if it is, we provide it to the previous handler
159
- handler = InfraLogger.logDebug("Applying middleware dynamic " + tag.key, tag.dynamic).pipe(
160
- Effect.zipRight(
161
- middleware(options).pipe(
162
- Effect.flatMap((o) =>
163
- Option.isSome(o)
164
- ? Context.isContext(o.value)
165
- ? Effect.provide(previous, o.value)
166
- : Effect.provideService(previous, tag.dynamic!.settings.service!, /* TODO */ o.value)
167
- : previous
168
- )
169
- )
170
- )
171
- ) as any
172
- } else {
173
- // use the tag to get the middleware from context
174
- const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
175
-
176
- const previous = handler
177
-
178
- // set the previous handler to run after the middleware
179
- // we do expect both the middleware and the context to be present
180
- handler = InfraLogger.logDebug("Applying middleware " + tag.key).pipe(
181
- Effect.zipRight(
182
- tag.provides !== undefined
183
- ? middleware(options).pipe(
184
- Effect.flatMap((value) =>
185
- Context.isContext(value)
186
- ? Effect.provide(previous, value)
187
- : Effect.provideService(previous, tag.provides as any, value)
188
- )
189
- )
190
- : Effect.zipRight(middleware(options), previous)
191
- )
192
- ) as any
193
- }
194
- }
195
- return handler
196
- }
197
- }) as any
198
- }
@@ -1,404 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Rpc, type RpcGroup, type RpcMiddleware, type RpcSchema } from "@effect/rpc"
3
- import { type AnyWithProps } from "@effect/rpc/Rpc"
4
- import { type HandlersFrom } from "@effect/rpc/RpcGroup"
5
- import { Tag } from "@effect/rpc/RpcMiddleware"
6
- import { Context, type Effect, Layer, type NonEmptyArray, type NonEmptyReadonlyArray, S, type Schema, type Scope, type Stream } from "effect-app"
7
- import { type GetContextConfig, type GetEffectContext, type RPCContextMap } from "effect-app/client"
8
- import { typedValuesOf } from "effect-app/utils"
9
- import { type ReadonlyMailbox } from "effect/Mailbox"
10
- import { type TypeTestId } from "../../routing.js"
11
- import { type MiddlewareMaker, middlewareMaker, type RequestContextTag } from "./generic-middleware.js"
12
- import { type AnyDynamic, type RpcDynamic, type TagClassAny } from "./RpcMiddleware.js"
13
-
14
- /** Adapter used when setting the dynamic prop on a middleware implementation */
15
- export const contextMap = <
16
- RequestContextMap extends Record<string, RPCContextMap.Any>,
17
- Key extends (keyof RequestContextMap) & string
18
- >(rcm: RequestContextMap, key: Key): RpcDynamic<Key, RequestContextMap[Key]> => ({
19
- key,
20
- settings: { service: rcm[key]!["service"] } as RequestContextMap[Key]
21
- })
22
-
23
- const tag = Context.GenericTag("RequestContextConfig")
24
- /** Retrieves RequestContextConfig out of the RPC annotations */
25
- export const getConfig = <
26
- RequestContextMap extends Record<string, RPCContextMap.Any>
27
- >() =>
28
- (rpc: AnyWithProps): GetContextConfig<RequestContextMap> => {
29
- return Context.getOrElse(rpc.annotations, tag as any, () => ({}))
30
- }
31
-
32
- // the following implements sort of builder pattern
33
- // we support both sideways and upwards elimination of dependencies
34
-
35
- // it's for dynamic middlewares
36
- type GetDependsOnKeys<MW extends MiddlewareMaker.Any> = MW extends { dependsOn: NonEmptyReadonlyArray<TagClassAny> } ? {
37
- [K in keyof MW["dependsOn"]]: MW["dependsOn"][K] extends AnyDynamic ? MW["dependsOn"][K]["dynamic"]["key"]
38
- : never
39
- }[keyof MW["dependsOn"]]
40
- : never
41
-
42
- type FilterInDynamicMiddlewares<
43
- MWs extends ReadonlyArray<MiddlewareMaker.Any>,
44
- RequestContextMap extends Record<string, RPCContextMap.Any>
45
- > = {
46
- [K in keyof MWs]: MWs[K] extends { dynamic: RpcDynamic<any, RequestContextMap[keyof RequestContextMap]> } ? MWs[K]
47
- : never
48
- }
49
-
50
- type RecursiveHandleMWsSideways<
51
- MWs,
52
- R extends {
53
- rcm: Record<string, RPCContextMap.Any>
54
- provided: keyof R["rcm"] // that's fine
55
- middlewares: ReadonlyArray<MiddlewareMaker.Any>
56
- dmp: any
57
- middlewareR: any
58
- }
59
- > = MWs extends [
60
- infer F extends MiddlewareMaker.Any,
61
- ...infer Rest extends ReadonlyArray<MiddlewareMaker.Any>
62
- ] ? RecursiveHandleMWsSideways<Rest, {
63
- rcm: R["rcm"]
64
- // when one dynamic middleware depends on another, subtract the key to enforce the dependency to be provided after
65
- // (if already provided, it would have to be re-provided anyway, so better to provide it after)
66
- provided: Exclude<
67
- R["provided"] | FilterInDynamicMiddlewares<[F], R["rcm"]>[number]["dynamic"]["key"],
68
- // F is fine here because only dynamic middlewares will have 'dependsOn' prop
69
- GetDependsOnKeys<F>
70
- >
71
- middlewares: [...R["middlewares"], F]
72
- dmp: [FilterInDynamicMiddlewares<[F], R["rcm"]>[number]] extends [never] ? R["dmp"]
73
- :
74
- & R["dmp"]
75
- & {
76
- [U in FilterInDynamicMiddlewares<[F], R["rcm"]>[number] as U["dynamic"]["key"]]: U
77
- }
78
- middlewareR: MiddlewareMaker.ApplyManyServices<[F], R["middlewareR"]>
79
- }>
80
- : R
81
-
82
- export interface BuildingMiddleware<
83
- RequestContextMap extends Record<string, RPCContextMap.Any>,
84
- Provided extends keyof RequestContextMap,
85
- Middlewares extends ReadonlyArray<MiddlewareMaker.Any>,
86
- DynamicMiddlewareProviders,
87
- out MiddlewareR extends { _tag: string } = never
88
- > {
89
- rpc: <
90
- const Tag extends string,
91
- Payload extends Schema.Schema.Any | Schema.Struct.Fields = typeof Schema.Void,
92
- Success extends Schema.Schema.Any = typeof Schema.Void,
93
- Error extends Schema.Schema.All = typeof Schema.Never,
94
- const Stream extends boolean = false,
95
- Config extends GetContextConfig<RequestContextMap> = {}
96
- >(tag: Tag, options?: {
97
- readonly payload?: Payload
98
- readonly success?: Success
99
- readonly error?: Error
100
- readonly stream?: Stream
101
- readonly config?: Config
102
- readonly primaryKey?: [Payload] extends [Schema.Struct.Fields]
103
- ? ((payload: Schema.Simplify<Schema.Struct.Type<NoInfer<Payload>>>) => string)
104
- : never
105
- }) =>
106
- & Rpc.Rpc<
107
- Tag,
108
- Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
109
- Stream extends true ? RpcSchema.Stream<Success, Error> : Success,
110
- Stream extends true ? typeof Schema.Never : Error
111
- >
112
- & { readonly config: Config }
113
-
114
- middleware<MWs extends NonEmptyArray<MiddlewareMaker.Any>>(
115
- ...mw: MWs
116
- ): RecursiveHandleMWsSideways<MWs, {
117
- rcm: RequestContextMap
118
- provided: Provided
119
- middlewares: Middlewares
120
- dmp: DynamicMiddlewareProviders
121
- middlewareR: MiddlewareR
122
- }> extends infer Res extends {
123
- rcm: RequestContextMap
124
- provided: keyof RequestContextMap
125
- middlewares: ReadonlyArray<MiddlewareMaker.Any>
126
- dmp: any
127
- middlewareR: any
128
- } ? MiddlewaresBuilder<
129
- Res["rcm"],
130
- Res["provided"],
131
- Res["middlewares"],
132
- Res["dmp"],
133
- Res["middlewareR"]
134
- >
135
- : never
136
-
137
- // helps debugging what are the missing requirements (type only)
138
- readonly [TypeTestId]: {
139
- missingDynamicMiddlewares: Exclude<keyof RequestContextMap, Provided>
140
- missingContext: MiddlewareR
141
- }
142
- }
143
-
144
- export type MiddlewaresBuilder<
145
- RequestContextMap extends Record<string, RPCContextMap.Any>,
146
- Provided extends keyof RequestContextMap = never,
147
- Middlewares extends ReadonlyArray<MiddlewareMaker.Any> = [],
148
- DynamicMiddlewareProviders = unknown,
149
- MiddlewareR extends { _tag: string } = never
150
- > =
151
- & BuildingMiddleware<
152
- RequestContextMap,
153
- Provided,
154
- Middlewares,
155
- DynamicMiddlewareProviders,
156
- MiddlewareR
157
- >
158
- & // keyof Omit<RequestContextMap, Provided> extends never is true when all the dynamic middlewares are provided
159
- // MiddlewareR is never when all the required services from generic & dynamic middlewares are provided
160
- (keyof Omit<RequestContextMap, Provided> extends never ? [MiddlewareR] extends [never] ? MiddlewareMaker<
161
- RequestContextMap,
162
- Middlewares
163
- >
164
- : {}
165
- : {})
166
-
167
- const makeMiddlewareBasic =
168
- // by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
169
- <
170
- RequestContextMap extends Record<string, RPCContextMap.Any>,
171
- MiddlewareProviders extends ReadonlyArray<MiddlewareMaker.Any>
172
- >(
173
- rcm: RequestContextMap,
174
- ...make: MiddlewareProviders
175
- ) => {
176
- // reverse middlewares and wrap one after the other
177
- const middleware = middlewareMaker(make)
178
-
179
- const failures = make.map((_) => _.failure).filter(Boolean)
180
- const provides = make.flatMap((_) => !_.provides ? [] : Array.isArray(_.provides) ? _.provides : [_.provides])
181
- const requires = make
182
- .flatMap((_) => !_.requires ? [] : Array.isArray(_.requires) ? _.requires : [_.requires])
183
- .filter((_) => !provides.includes(_))
184
-
185
- const MiddlewareMaker = Tag<MiddlewareMakerId>()("MiddlewareMaker", {
186
- failure: (failures.length > 0
187
- ? S.Union(...failures)
188
- : S.Never) as unknown as MiddlewareMaker.ManyErrors<MiddlewareProviders> extends never ? never
189
- : S.Schema<MiddlewareMaker.ManyErrors<MiddlewareProviders>>,
190
- requires: (requires.length > 0
191
- ? requires
192
- : undefined) as unknown as Exclude<
193
- MiddlewareMaker.ManyRequired<MiddlewareProviders>,
194
- MiddlewareMaker.ManyProvided<MiddlewareProviders>
195
- > extends never ? never : [
196
- MakeTags<
197
- Exclude<
198
- MiddlewareMaker.ManyRequired<MiddlewareProviders>,
199
- MiddlewareMaker.ManyProvided<MiddlewareProviders>
200
- >
201
- >
202
- ],
203
- provides: (provides.length > 0
204
- ? provides
205
- : undefined) as unknown as MiddlewareMaker.ManyProvided<MiddlewareProviders> extends never ? never
206
- : MakeTags<MiddlewareMaker.ManyProvided<MiddlewareProviders>>,
207
- wrap: true
208
- })
209
-
210
- const layer = Layer
211
- .scoped(
212
- MiddlewareMaker,
213
- middleware as Effect<
214
- any, // TODO: why ?
215
- Effect.Error<typeof middleware>,
216
- Effect.Context<typeof middleware>
217
- >
218
- )
219
-
220
- // add to the tag a default implementation
221
- return Object.assign(MiddlewareMaker, {
222
- layer,
223
- // tag to be used to retrieve the RequestContextConfig from RPC annotations
224
- requestContext: Context.GenericTag<"RequestContextConfig", GetContextConfig<RequestContextMap>>(
225
- "RequestContextConfig"
226
- ),
227
- requestContextMap: rcm
228
- })
229
- }
230
-
231
- export const makeMiddleware = <
232
- RequestContextMap extends Record<string, RPCContextMap.Any>
233
- >(rcm: RequestContextMap): MiddlewaresBuilder<RequestContextMap> => {
234
- let allMiddleware: MiddlewareMaker.Any[] = []
235
- const requestContext = Context.GenericTag<"RequestContextConfig", GetContextConfig<RequestContextMap>>(
236
- "RequestContextConfig"
237
- )
238
- const it = {
239
- // rpc with config
240
- rpc: <
241
- const Tag extends string,
242
- Payload extends Schema.Schema.Any | Schema.Struct.Fields = typeof Schema.Void,
243
- Success extends Schema.Schema.Any = typeof Schema.Void,
244
- Error extends Schema.Schema.All = typeof Schema.Never,
245
- const Stream extends boolean = false,
246
- Config extends GetContextConfig<RequestContextMap> = {}
247
- >(tag: Tag, options?: {
248
- readonly payload?: Payload
249
- readonly success?: Success
250
- readonly error?: Error
251
- readonly stream?: Stream
252
- readonly config?: Config
253
- readonly primaryKey?: [Payload] extends [Schema.Struct.Fields]
254
- ? ((payload: Schema.Simplify<Schema.Struct.Type<NoInfer<Payload>>>) => string)
255
- : never
256
- }):
257
- & Rpc.Rpc<
258
- Tag,
259
- Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
260
- // TODO: enhance `Error`. type based on middleware config.
261
- Stream extends true ? RpcSchema.Stream<Success, Error> : Success,
262
- Stream extends true ? typeof Schema.Never : Error
263
- >
264
- & { config: Config } =>
265
- {
266
- const config = options?.config ?? {} as Config
267
-
268
- // based on the config, we must enhance (union) or set failures.
269
- // TODO: we should only include errors that are relevant based on the middleware config.ks
270
- const error = options?.error
271
- const errors = typedValuesOf(rcm).map((_) => _.error).filter((_) => _ && _ !== S.Never) // TODO: only the errors relevant based on config
272
- const newError = error ? S.Union(error, ...errors) : S.Union(...errors)
273
-
274
- const rpc = Rpc.make(tag, { ...options, error: newError }) as any
275
-
276
- return Object.assign(rpc.annotate(requestContext, config), { config })
277
- },
278
- middleware: (...middlewares: any[]) => {
279
- for (const mw of middlewares) {
280
- // recall that we run middlewares in reverse order
281
- allMiddleware = [mw, ...allMiddleware]
282
- }
283
- return allMiddleware.filter((m) => !!m.dynamic).length !== Object.keys(rcm).length
284
- // for sure, until all the dynamic middlewares are provided it's non sensical to call makeMiddlewareBasic
285
- ? it
286
- // actually, we don't know yet if MiddlewareR is never, but we can't easily check it at runtime
287
- : Object.assign(makeMiddlewareBasic<any, any>(rcm, ...allMiddleware), it)
288
- }
289
- }
290
- return it as any
291
- }
292
-
293
- // customised version of Rpc.AddMiddleware, so that we don't loose the `config`...
294
- // not needed if there's official support in Rpc.Rpc.
295
- export type AddMiddleware<R extends Rpc.Any, Middleware extends RpcMiddleware.TagClassAny> = R extends Rpc.Rpc<
296
- infer _Tag,
297
- infer _Payload,
298
- infer _Success,
299
- infer _Error,
300
- infer _Middleware
301
- > ?
302
- & Rpc.Rpc<
303
- _Tag,
304
- _Payload,
305
- _Success,
306
- _Error,
307
- _Middleware | Middleware
308
- >
309
- & { readonly config: R extends { readonly config: infer _C } ? _C : never }
310
- : never
311
-
312
- // alternatively consider group.serverMiddleware? hmmm
313
- export const middlewareGroup = <
314
- RequestContextMap extends Record<string, RPCContextMap.Any>,
315
- Middleware extends Context.Tag<MiddlewareMakerId, any> & RpcMiddleware.TagClassAny & {
316
- readonly requestContext: RequestContextTag<RequestContextMap>
317
- readonly requestContextMap: RequestContextMap
318
- }
319
- >(
320
- middleware: Middleware
321
- ) =>
322
- <R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>) => {
323
- type RN = AddMiddleware<R, typeof middleware>
324
- const middlewaredGroup = group.middleware(middleware) as unknown as RpcGroup.RpcGroup<RN>
325
- const toLayerOriginal = middlewaredGroup.toLayer.bind(middlewaredGroup)
326
- return Object.assign(middlewaredGroup, {
327
- toLayerDynamic: <
328
- Handlers extends HandlersFrom<RN>,
329
- EX = never,
330
- RX = never
331
- >(
332
- build:
333
- | Handlers
334
- | Effect.Effect<Handlers, EX, RX>
335
- ): Layer.Layer<
336
- Rpc.ToHandler<RN>,
337
- EX,
338
- | Exclude<RX, Scope>
339
- | HandlersContext<RN, Handlers>
340
- > => {
341
- return toLayerOriginal(build as any) as any // ??
342
- }
343
- })
344
- }
345
-
346
- // customized versions to handle dynamically eliminated context.
347
- export type HandlersContext<Rpcs extends Rpc.Any, Handlers> = keyof Handlers extends infer K
348
- ? K extends keyof Handlers & string ? HandlerContext<Rpcs, K, Handlers[K]> : never
349
- : never
350
-
351
- export type HandlerContext<Rpcs extends Rpc.Any, K extends Rpcs["_tag"], Handler> = [Rpc.IsStream<Rpcs, K>] extends
352
- [true] ? Handler extends (...args: any) =>
353
- | Stream.Stream<infer _A, infer _E, infer _R>
354
- | Rpc.Fork<Stream.Stream<infer _A, infer _E, infer _R>>
355
- | Effect.Effect<
356
- ReadonlyMailbox<infer _A, infer _E>,
357
- infer _EX,
358
- infer _R
359
- >
360
- | Rpc.Fork<
361
- Effect.Effect<
362
- ReadonlyMailbox<infer _A, infer _E>,
363
- infer _EX,
364
- infer _R
365
- >
366
- > ? Exclude<ExcludeProvides<_R, Rpcs, K>, Scope>
367
- : never
368
- : Handler extends (
369
- ...args: any
370
- ) => Effect.Effect<infer _A, infer _E, infer _R> | Rpc.Fork<Effect.Effect<infer _A, infer _E, infer _R>>
371
- ? ExcludeProvides<_R, Rpcs, K>
372
- : never
373
-
374
- // new
375
- export type ExtractDynamicallyProvides<R extends Rpc.Any, Tag extends string> = R extends
376
- Rpc.Rpc<Tag, infer _Payload, infer _Success, infer _Error, infer _Middleware> ? _Middleware extends {
377
- readonly requestContextMap: infer _RC
378
- } ? _RC extends Record<string, RPCContextMap.Any> // ? GetEffectContext<_RC, { allowAnonymous: false }>
379
- ? R extends { readonly config: infer _C } ? GetEffectContext<_RC, _C>
380
- : GetEffectContext<_RC, {}>
381
- : never
382
- : never
383
- : never
384
-
385
- export type ExtractProvides<R extends Rpc.Any, Tag extends string> = R extends
386
- Rpc.Rpc<Tag, infer _Payload, infer _Success, infer _Error, infer _Middleware> ? _Middleware extends {
387
- readonly provides: Context.Tag<infer _I, infer _S>
388
- } ? _I
389
- : never
390
- : never
391
-
392
- export type ExcludeProvides<Env, R extends Rpc.Any, Tag extends string> = Exclude<
393
- Env,
394
- // customisation is down here.
395
- ExtractProvides<R, Tag> | ExtractDynamicallyProvides<R, Tag>
396
- >
397
-
398
- //
399
- export interface MiddlewareMakerId {
400
- readonly _id: unique symbol
401
- }
402
-
403
- // TODO: actually end up with [Tag<A, A>, Tag<B, B>, ...] once `provides: []` is implemented
404
- export type MakeTags<A> = Context.Tag<A, A>
@@ -1,23 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { RpcMiddleware } from "@effect/rpc"
3
- import { Context } from "effect-app"
4
-
5
- export class DevMode extends Context.Reference<DevMode>()("DevMode", { defaultValue: () => false }) {}
6
-
7
- export class RequestCacheMiddleware
8
- extends RpcMiddleware.Tag<RequestCacheMiddleware>()("RequestCacheMiddleware", { wrap: true })
9
- {}
10
-
11
- export class ConfigureInterruptibilityMiddleware
12
- extends RpcMiddleware.Tag<ConfigureInterruptibilityMiddleware>()("ConfigureInterruptibilityMiddleware", {
13
- wrap: true
14
- })
15
- {}
16
-
17
- export class LoggerMiddleware extends RpcMiddleware.Tag<LoggerMiddleware>()("LoggerMiddleware", { wrap: true }) {}
18
-
19
- export const DefaultGenericMiddlewares = [
20
- RequestCacheMiddleware,
21
- ConfigureInterruptibilityMiddleware,
22
- LoggerMiddleware
23
- ] as const