@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.
- package/CHANGELOG.md +14 -0
- package/dist/QueueMaker/errors.d.ts +1 -1
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.d.ts +1 -2
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +2 -3
- package/dist/api/routing/middleware.d.ts +0 -4
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +1 -5
- package/dist/api/routing.d.ts +5 -13
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +4 -13
- package/package.json +2 -22
- package/src/api/routing/middleware/RouterMiddleware.ts +1 -1
- package/src/api/routing/middleware/middleware.ts +1 -3
- package/src/api/routing/middleware.ts +0 -4
- package/src/api/routing.ts +20 -36
- package/test/controller.test.ts +13 -14
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/fixtures.d.ts +9 -9
- package/test/dist/fixtures.js +2 -2
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/fixtures.ts +1 -1
- package/test/requires.test.ts +2 -2
- package/test/rpc-multi-middleware.test.ts +2 -2
- package/dist/api/routing/middleware/RpcMiddleware.d.ts +0 -188
- package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/RpcMiddleware.js +0 -13
- package/dist/api/routing/middleware/RpcMiddlewareX.d.ts +0 -18
- package/dist/api/routing/middleware/RpcMiddlewareX.d.ts.map +0 -1
- package/dist/api/routing/middleware/RpcMiddlewareX.js +0 -16
- package/dist/api/routing/middleware/generic-middleware.d.ts +0 -55
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/generic-middleware.js +0 -67
- package/dist/api/routing/middleware/middleware-api.d.ts +0 -107
- package/dist/api/routing/middleware/middleware-api.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware-api.js +0 -88
- package/dist/api/routing/middleware/middleware-native.d.ts +0 -23
- package/dist/api/routing/middleware/middleware-native.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware-native.js +0 -19
- package/src/api/routing/middleware/RpcMiddleware.ts +0 -254
- package/src/api/routing/middleware/RpcMiddlewareX.ts +0 -70
- package/src/api/routing/middleware/generic-middleware.ts +0 -198
- package/src/api/routing/middleware/middleware-api.ts +0 -404
- 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
|