@effect-app/infra 2.88.0 → 2.89.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.
- package/CHANGELOG.md +11 -0
- package/dist/api/{routing/middleware/ContextProvider.d.ts → ContextProvider.d.ts} +1 -1
- package/dist/api/ContextProvider.d.ts.map +1 -0
- package/dist/api/ContextProvider.js +38 -0
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +15 -10
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.js +2 -5
- package/dist/api/routing/middleware/RpcMiddleware.d.ts +6 -10
- package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/RpcMiddleware.js +1 -1
- package/dist/api/routing/middleware/generic-middleware.d.ts +19 -17
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +2 -2
- package/dist/api/routing/middleware/middleware-api.d.ts +29 -26
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +31 -40
- package/dist/api/routing/middleware.d.ts +0 -1
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +1 -2
- package/dist/api/routing.d.ts +1 -1
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +12 -10
- package/package.json +6 -6
- package/src/api/{routing/middleware/ContextProvider.ts → ContextProvider.ts} +1 -1
- package/src/api/routing/middleware/RouterMiddleware.ts +22 -56
- package/src/api/routing/middleware/RpcMiddleware.ts +15 -11
- package/src/api/routing/middleware/generic-middleware.ts +44 -26
- package/src/api/routing/middleware/middleware-api.ts +80 -95
- package/src/api/routing/middleware.ts +0 -1
- package/src/api/routing.ts +22 -20
- package/test/contextProvider.test.ts +1 -1
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +7 -6
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/fixtures.ts +7 -5
- package/test/requires.test.ts +42 -21
- package/dist/api/routing/middleware/ContextProvider.d.ts.map +0 -1
- package/dist/api/routing/middleware/ContextProvider.js +0 -38
|
@@ -1,38 +1,41 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { type
|
|
3
|
-
import { type
|
|
4
|
-
import { type Array, Context, Effect, type Layer, type NonEmptyReadonlyArray, Option, type Scope } from "effect-app"
|
|
2
|
+
import { type RpcMiddleware } from "@effect/rpc"
|
|
3
|
+
import { Context, Effect, type Layer, type NonEmptyReadonlyArray, Option, type S, type Scope } from "effect-app"
|
|
5
4
|
import { type ContextTagArray } from "effect-app/client"
|
|
6
|
-
import { type HttpHeaders } from "effect-app/http"
|
|
7
5
|
import { InfraLogger } from "../../../logger.js"
|
|
8
|
-
import { type TagClassAny } from "./RpcMiddleware.js"
|
|
6
|
+
import { type RpcMiddlewareWrap, type TagClassAny } from "./RpcMiddleware.js"
|
|
9
7
|
|
|
10
8
|
// Effect rpc middleware does not support changing payload or headers, but we do..
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
export interface GenericMiddlewareOptions<E> {
|
|
14
|
-
readonly clientId: number
|
|
15
|
-
readonly rpc: Rpc.AnyWithProps
|
|
16
|
-
readonly payload: unknown
|
|
17
|
-
readonly headers: HttpHeaders.Headers
|
|
18
|
-
readonly next: Effect.Effect<SuccessValue, E, Scope.Scope>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type GenericMiddlewareMaker = TagClassAny & { Default: Layer.Layer.Any } // todo; and Layer..
|
|
10
|
+
export type MiddlewareMaker = TagClassAny & { Default: Layer.Layer.Any } // todo; and Layer..
|
|
22
11
|
|
|
23
|
-
export namespace
|
|
12
|
+
export namespace MiddlewareMaker {
|
|
24
13
|
export type ApplyServices<A extends TagClassAny, R> = Exclude<R, Provided<A>> | Required<A>
|
|
25
14
|
|
|
26
15
|
export type ApplyManyServices<A extends NonEmptyReadonlyArray<TagClassAny>, R> =
|
|
27
16
|
| Exclude<R, { [K in keyof A]: Provided<A[K]> }[number]>
|
|
28
17
|
| { [K in keyof A]: Required<A[K]> }[number]
|
|
29
18
|
|
|
19
|
+
export type ManyProvided<A extends ReadonlyArray<TagClassAny>> = A extends NonEmptyReadonlyArray<TagClassAny>
|
|
20
|
+
? { [K in keyof A]: Provided<A[K]> }[number]
|
|
21
|
+
: Provided<A[number]>
|
|
22
|
+
export type ManyRequired<A extends ReadonlyArray<TagClassAny>> = A extends NonEmptyReadonlyArray<TagClassAny>
|
|
23
|
+
? { [K in keyof A]: Required<A[K]> }[number]
|
|
24
|
+
: Required<A[number]>
|
|
25
|
+
export type ManyErrors<A extends ReadonlyArray<TagClassAny>> = A extends NonEmptyReadonlyArray<TagClassAny>
|
|
26
|
+
? { [K in keyof A]: Errors<A[K]> }[number]
|
|
27
|
+
: Errors<A[number]>
|
|
28
|
+
|
|
30
29
|
export type Provided<T> = T extends TagClassAny
|
|
31
30
|
? T extends { provides: Context.Tag<any, any> } ? Context.Tag.Identifier<T["provides"]>
|
|
32
31
|
: T extends { provides: ContextTagArray } ? ContextTagArray.Identifier<T["provides"]>
|
|
33
32
|
: never
|
|
34
33
|
: never
|
|
35
34
|
|
|
35
|
+
export type Errors<T> = T extends TagClassAny ? T extends { failure: S.Schema.Any } ? S.Schema.Type<T["failure"]>
|
|
36
|
+
: never
|
|
37
|
+
: never
|
|
38
|
+
|
|
36
39
|
export type Required<T> = T extends TagClassAny
|
|
37
40
|
? T extends { requires: Context.Tag<any, any> } ? Context.Tag.Identifier<T["requires"]>
|
|
38
41
|
: T extends { requires: ContextTagArray } ? ContextTagArray.Identifier<T["requires"]>
|
|
@@ -40,11 +43,21 @@ export namespace GenericMiddlewareMaker {
|
|
|
40
43
|
: never
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
export const
|
|
44
|
-
|
|
45
|
-
>(
|
|
46
|
-
dependencies: { [K in keyof
|
|
47
|
-
effect: Effect.Effect<
|
|
46
|
+
export const middlewareMaker = <
|
|
47
|
+
MiddlewareProviders extends ReadonlyArray<MiddlewareMaker>
|
|
48
|
+
>(middlewares: MiddlewareProviders): {
|
|
49
|
+
dependencies: { [K in keyof MiddlewareProviders]: MiddlewareProviders[K]["Default"] }
|
|
50
|
+
effect: Effect.Effect<
|
|
51
|
+
RpcMiddlewareWrap<
|
|
52
|
+
MiddlewareMaker.ManyProvided<MiddlewareProviders>,
|
|
53
|
+
MiddlewareMaker.ManyErrors<MiddlewareProviders>,
|
|
54
|
+
Exclude<
|
|
55
|
+
MiddlewareMaker.ManyRequired<MiddlewareProviders>,
|
|
56
|
+
MiddlewareMaker.ManyProvided<MiddlewareProviders>
|
|
57
|
+
> extends never ? never
|
|
58
|
+
: Exclude<MiddlewareMaker.ManyRequired<MiddlewareProviders>, MiddlewareMaker.ManyProvided<MiddlewareProviders>>
|
|
59
|
+
>
|
|
60
|
+
>
|
|
48
61
|
} => {
|
|
49
62
|
// we want to run them in reverse order because latter middlewares will provide context to former ones
|
|
50
63
|
middlewares = middlewares.toReversed() as any
|
|
@@ -55,8 +68,14 @@ export const genericMiddlewareMaker = <
|
|
|
55
68
|
const context = yield* Effect.context()
|
|
56
69
|
|
|
57
70
|
// returns a Effect/RpcMiddlewareWrap with Scope in requirements
|
|
58
|
-
return
|
|
59
|
-
options:
|
|
71
|
+
return (
|
|
72
|
+
options: Parameters<
|
|
73
|
+
RpcMiddlewareWrap<
|
|
74
|
+
MiddlewareMaker.ManyProvided<MiddlewareProviders>,
|
|
75
|
+
never,
|
|
76
|
+
Scope.Scope
|
|
77
|
+
>
|
|
78
|
+
>[0]
|
|
60
79
|
) => {
|
|
61
80
|
// we start with the actual handler
|
|
62
81
|
let handler = options.next
|
|
@@ -113,7 +132,7 @@ export const genericMiddlewareMaker = <
|
|
|
113
132
|
)
|
|
114
133
|
)
|
|
115
134
|
)
|
|
116
|
-
)
|
|
135
|
+
) as any
|
|
117
136
|
} else {
|
|
118
137
|
// use the tag to get the middleware from context
|
|
119
138
|
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
@@ -134,10 +153,9 @@ export const genericMiddlewareMaker = <
|
|
|
134
153
|
)
|
|
135
154
|
: Effect.zipRight(middleware(options), previous)
|
|
136
155
|
)
|
|
137
|
-
)
|
|
156
|
+
) as any
|
|
138
157
|
}
|
|
139
158
|
}
|
|
140
|
-
|
|
141
159
|
return handler
|
|
142
160
|
}
|
|
143
161
|
})
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { type
|
|
4
|
-
import { type
|
|
5
|
-
import { type
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// adapter used when setting the dynamic prop on a middleware implementation
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { type AnyWithProps } from "@effect/rpc/Rpc"
|
|
3
|
+
import { Context, type Effect, type NonEmptyArray, type NonEmptyReadonlyArray, S } from "effect-app"
|
|
4
|
+
import { type GetContextConfig, type RPCContextMap } from "effect-app/client"
|
|
5
|
+
import { type MiddlewareMaker, middlewareMaker } from "./generic-middleware.js"
|
|
6
|
+
import { type AnyDynamic, type RpcDynamic, Tag, type TagClassAny } from "./RpcMiddleware.js"
|
|
7
|
+
|
|
8
|
+
/** Adapter used when setting the dynamic prop on a middleware implementation */
|
|
10
9
|
export const contextMap = <
|
|
11
10
|
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
12
11
|
Key extends (keyof RequestContextMap) & string
|
|
@@ -15,19 +14,26 @@ export const contextMap = <
|
|
|
15
14
|
settings: { service: rcm[key]!["service"] } as RequestContextMap[Key]
|
|
16
15
|
})
|
|
17
16
|
|
|
17
|
+
/** Retrieves RequestContextConfig out of the RPC annotations */
|
|
18
|
+
export const getConfig = <
|
|
19
|
+
RequestContextMap extends Record<string, RPCContextMap.Any>
|
|
20
|
+
>() =>
|
|
21
|
+
(rpc: AnyWithProps): GetContextConfig<RequestContextMap> => {
|
|
22
|
+
return Context.unsafeGet(rpc.annotations, Context.GenericTag("RequestContextConfig"))
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
// the following implements sort of builder pattern
|
|
19
26
|
// we support both sideways and upwards elimination of dependencies
|
|
20
27
|
|
|
21
28
|
// it's for dynamic middlewares
|
|
22
|
-
type GetDependsOnKeys<MW extends
|
|
23
|
-
? {
|
|
29
|
+
type GetDependsOnKeys<MW extends MiddlewareMaker> = MW extends { dependsOn: NonEmptyReadonlyArray<TagClassAny> } ? {
|
|
24
30
|
[K in keyof MW["dependsOn"]]: MW["dependsOn"][K] extends AnyDynamic ? MW["dependsOn"][K]["dynamic"]["key"]
|
|
25
31
|
: never
|
|
26
32
|
}[keyof MW["dependsOn"]]
|
|
27
33
|
: never
|
|
28
34
|
|
|
29
35
|
type FilterInDynamicMiddlewares<
|
|
30
|
-
MWs extends ReadonlyArray<
|
|
36
|
+
MWs extends ReadonlyArray<MiddlewareMaker>,
|
|
31
37
|
RequestContextMap extends Record<string, RPCContextMap.Any>
|
|
32
38
|
> = {
|
|
33
39
|
[K in keyof MWs]: MWs[K] extends { dynamic: RpcDynamic<any, RequestContextMap[keyof RequestContextMap]> } ? MWs[K]
|
|
@@ -39,13 +45,13 @@ type RecursiveHandleMWsSideways<
|
|
|
39
45
|
R extends {
|
|
40
46
|
rcm: Record<string, RPCContextMap.Any>
|
|
41
47
|
provided: keyof R["rcm"] // that's fine
|
|
42
|
-
middlewares: ReadonlyArray<
|
|
48
|
+
middlewares: ReadonlyArray<MiddlewareMaker>
|
|
43
49
|
dmp: any
|
|
44
50
|
middlewareR: any
|
|
45
51
|
}
|
|
46
52
|
> = MWs extends [
|
|
47
|
-
infer F extends
|
|
48
|
-
...infer Rest extends ReadonlyArray<
|
|
53
|
+
infer F extends MiddlewareMaker,
|
|
54
|
+
...infer Rest extends ReadonlyArray<MiddlewareMaker>
|
|
49
55
|
] ? RecursiveHandleMWsSideways<Rest, {
|
|
50
56
|
rcm: R["rcm"]
|
|
51
57
|
// when one dynamic middleware depends on another, subtract the key to enforce the dependency to be provided after
|
|
@@ -62,18 +68,18 @@ type RecursiveHandleMWsSideways<
|
|
|
62
68
|
& {
|
|
63
69
|
[U in FilterInDynamicMiddlewares<[F], R["rcm"]>[number] as U["dynamic"]["key"]]: U
|
|
64
70
|
}
|
|
65
|
-
middlewareR:
|
|
71
|
+
middlewareR: MiddlewareMaker.ApplyManyServices<[F], R["middlewareR"]>
|
|
66
72
|
}>
|
|
67
73
|
: R
|
|
68
74
|
|
|
69
75
|
export interface BuildingMiddleware<
|
|
70
76
|
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
71
77
|
Provided extends keyof RequestContextMap,
|
|
72
|
-
Middlewares extends ReadonlyArray<
|
|
78
|
+
Middlewares extends ReadonlyArray<MiddlewareMaker>,
|
|
73
79
|
DynamicMiddlewareProviders,
|
|
74
80
|
out MiddlewareR extends { _tag: string } = never
|
|
75
81
|
> {
|
|
76
|
-
middleware<MWs extends NonEmptyArray<
|
|
82
|
+
middleware<MWs extends NonEmptyArray<MiddlewareMaker>>(
|
|
77
83
|
...mw: MWs
|
|
78
84
|
): RecursiveHandleMWsSideways<MWs, {
|
|
79
85
|
rcm: RequestContextMap
|
|
@@ -84,7 +90,7 @@ export interface BuildingMiddleware<
|
|
|
84
90
|
}> extends infer Res extends {
|
|
85
91
|
rcm: RequestContextMap
|
|
86
92
|
provided: keyof RequestContextMap
|
|
87
|
-
middlewares: ReadonlyArray<
|
|
93
|
+
middlewares: ReadonlyArray<MiddlewareMaker>
|
|
88
94
|
dmp: any
|
|
89
95
|
middlewareR: any
|
|
90
96
|
} ? MiddlewaresBuilder<
|
|
@@ -106,7 +112,7 @@ export interface BuildingMiddleware<
|
|
|
106
112
|
export type MiddlewaresBuilder<
|
|
107
113
|
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
108
114
|
Provided extends keyof RequestContextMap = never,
|
|
109
|
-
Middlewares extends ReadonlyArray<
|
|
115
|
+
Middlewares extends ReadonlyArray<MiddlewareMaker> = [],
|
|
110
116
|
DynamicMiddlewareProviders = unknown,
|
|
111
117
|
MiddlewareR extends { _tag: string } = never
|
|
112
118
|
> =
|
|
@@ -136,7 +142,7 @@ export type MiddlewaresBuilder<
|
|
|
136
142
|
export const makeMiddleware: <
|
|
137
143
|
RequestContextMap extends Record<string, RPCContextMap.Any>
|
|
138
144
|
>(rcm: RequestContextMap) => MiddlewaresBuilder<RequestContextMap> = (rcm) => {
|
|
139
|
-
let allMiddleware:
|
|
145
|
+
let allMiddleware: MiddlewareMaker[] = []
|
|
140
146
|
const it = {
|
|
141
147
|
middleware: (...middlewares: any[]) => {
|
|
142
148
|
for (const mw of middlewares) {
|
|
@@ -154,92 +160,71 @@ export const makeMiddleware: <
|
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
//
|
|
157
|
-
export
|
|
158
|
-
|
|
159
|
-
export interface MiddlewareMaker<E> {
|
|
160
|
-
readonly effect: E
|
|
161
|
-
readonly _tag: typeof MiddlewareMakerTag
|
|
163
|
+
export interface MiddlewareMakerId {
|
|
164
|
+
readonly _id: unique symbol
|
|
162
165
|
}
|
|
163
166
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
export const buildMiddlewareMaker = <E>(eff: E) =>
|
|
167
|
-
({
|
|
168
|
-
_tag: MiddlewareMakerTag,
|
|
169
|
-
effect: eff
|
|
170
|
-
}) satisfies MiddlewareMaker<E>
|
|
167
|
+
// TODO: actually end up with [Tag<A, A>, Tag<B, B>, ...]
|
|
168
|
+
type MakeTags<A> = Context.Tag<A, A>
|
|
171
169
|
|
|
172
170
|
const makeMiddlewareBasic =
|
|
173
171
|
// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
|
|
174
172
|
<
|
|
175
173
|
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
176
|
-
|
|
174
|
+
MiddlewareProviders extends ReadonlyArray<MiddlewareMaker>
|
|
177
175
|
>(
|
|
178
176
|
_rcm: RequestContextMap,
|
|
179
|
-
...make:
|
|
177
|
+
...make: MiddlewareProviders
|
|
180
178
|
) => {
|
|
181
|
-
const MiddlewareMaker = Context.GenericTag<
|
|
182
|
-
MiddlewareMakerId,
|
|
183
|
-
MiddlewareMaker<
|
|
184
|
-
RPCHandlerFactory<
|
|
185
|
-
RequestContextMap,
|
|
186
|
-
GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
187
|
-
>
|
|
188
|
-
>
|
|
189
|
-
>(
|
|
190
|
-
MiddlewareMakerTag
|
|
191
|
-
)
|
|
192
|
-
|
|
193
179
|
// reverse middlewares and wrap one after the other
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
180
|
+
const middleware = middlewareMaker(make)
|
|
181
|
+
|
|
182
|
+
const failures = make.map((_) => _.failure).filter(Boolean)
|
|
183
|
+
const provides = make.flatMap((_) => !_.provides ? [] : Array.isArray(_.provides) ? _.provides : [_.provides])
|
|
184
|
+
const requires = make
|
|
185
|
+
.flatMap((_) => !_.requires ? [] : Array.isArray(_.requires) ? _.requires : [_.requires])
|
|
186
|
+
.filter((_) => !provides.includes(_))
|
|
187
|
+
|
|
188
|
+
const MiddlewareMaker = Tag<MiddlewareMakerId>()("MiddlewareMaker", {
|
|
189
|
+
failure: (failures.length > 0
|
|
190
|
+
? S.Union(...failures)
|
|
191
|
+
: S.Never) as unknown as MiddlewareMaker.ManyErrors<MiddlewareProviders> extends never ? never
|
|
192
|
+
: S.Schema<MiddlewareMaker.ManyErrors<MiddlewareProviders>>,
|
|
193
|
+
requires: (requires.length > 0
|
|
194
|
+
? requires
|
|
195
|
+
: undefined) as unknown as Exclude<
|
|
196
|
+
MiddlewareMaker.ManyRequired<MiddlewareProviders>,
|
|
197
|
+
MiddlewareMaker.ManyProvided<MiddlewareProviders>
|
|
198
|
+
> extends never ? never : [
|
|
199
|
+
MakeTags<
|
|
200
|
+
Exclude<
|
|
201
|
+
MiddlewareMaker.ManyRequired<MiddlewareProviders>,
|
|
202
|
+
MiddlewareMaker.ManyProvided<MiddlewareProviders>
|
|
203
|
+
>
|
|
204
|
+
>
|
|
205
|
+
],
|
|
206
|
+
provides: (provides.length > 0
|
|
207
|
+
? provides
|
|
208
|
+
: undefined) as unknown as MiddlewareMaker.ManyProvided<MiddlewareProviders> extends never ? never : [
|
|
209
|
+
MakeTags<MiddlewareMaker.ManyProvided<MiddlewareProviders>>
|
|
210
|
+
],
|
|
211
|
+
wrap: true
|
|
212
|
+
})(
|
|
213
|
+
middleware as {
|
|
214
|
+
dependencies: typeof middleware["dependencies"]
|
|
215
|
+
effect: Effect<
|
|
216
|
+
any, // TODO: why ?
|
|
217
|
+
Effect.Error<typeof middleware["effect"]>,
|
|
218
|
+
Effect.Context<typeof middleware["effect"]>
|
|
219
|
+
>
|
|
220
|
+
}
|
|
231
221
|
)
|
|
232
222
|
|
|
233
|
-
const middlewareLayer = l
|
|
234
|
-
.pipe(
|
|
235
|
-
Layer.provide(middlewares.dependencies as any)
|
|
236
|
-
) as Layer.Layer<
|
|
237
|
-
MiddlewareMakerId,
|
|
238
|
-
// what could go wrong when building the dynamic middleware provider
|
|
239
|
-
LayerUtils.GetLayersError<typeof middlewares.dependencies>,
|
|
240
|
-
LayerUtils.GetLayersContext<typeof middlewares.dependencies>
|
|
241
|
-
>
|
|
242
|
-
|
|
243
223
|
// add to the tag a default implementation
|
|
244
|
-
return Object.assign(MiddlewareMaker, {
|
|
224
|
+
return Object.assign(MiddlewareMaker, {
|
|
225
|
+
// tag to be used to retrieve the RequestContextConfig from RPC annotations
|
|
226
|
+
requestContext: Context.GenericTag<"RequestContextConfig", GetContextConfig<RequestContextMap>>(
|
|
227
|
+
"RequestContextConfig"
|
|
228
|
+
)
|
|
229
|
+
})
|
|
245
230
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// codegen:start {preset: barrel, include: ./middleware/*.ts, nodir: false }
|
|
2
|
-
export * from "./middleware/ContextProvider.js"
|
|
3
2
|
export * from "./middleware/dynamic-middleware.js"
|
|
4
3
|
export * from "./middleware/generic-middleware.js"
|
|
5
4
|
export * from "./middleware/middleware-api.js"
|
package/src/api/routing.ts
CHANGED
|
@@ -167,13 +167,17 @@ export const makeRouter = <
|
|
|
167
167
|
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
168
168
|
MakeMiddlewareE,
|
|
169
169
|
MakeMiddlewareR,
|
|
170
|
-
ContextProviderA
|
|
170
|
+
ContextProviderA,
|
|
171
|
+
ContextProviderE,
|
|
172
|
+
ContextProviderR
|
|
171
173
|
>(
|
|
172
174
|
middleware: RouterMiddleware<
|
|
173
175
|
RequestContextMap,
|
|
174
176
|
MakeMiddlewareE,
|
|
175
177
|
MakeMiddlewareR,
|
|
176
|
-
ContextProviderA
|
|
178
|
+
ContextProviderA,
|
|
179
|
+
ContextProviderE,
|
|
180
|
+
ContextProviderR
|
|
177
181
|
>,
|
|
178
182
|
devMode: boolean
|
|
179
183
|
) => {
|
|
@@ -370,7 +374,6 @@ export const makeRouter = <
|
|
|
370
374
|
: make
|
|
371
375
|
|
|
372
376
|
const controllers = yield* make
|
|
373
|
-
const rpc = yield* middleware
|
|
374
377
|
|
|
375
378
|
// return make.pipe(Effect.map((c) => controllers(c, dependencies)))
|
|
376
379
|
const mapped = typedKeysOf(requestModules).reduce((acc, cur) => {
|
|
@@ -400,16 +403,12 @@ export const makeRouter = <
|
|
|
400
403
|
}
|
|
401
404
|
} as any
|
|
402
405
|
: resource,
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
})
|
|
410
|
-
),
|
|
411
|
-
meta.moduleName
|
|
412
|
-
),
|
|
406
|
+
(payload: any, headers: any) =>
|
|
407
|
+
handle(payload, headers).pipe(
|
|
408
|
+
Effect.withSpan("Request." + resource._tag, {
|
|
409
|
+
captureStackTrace: () => handler.stack // capturing the handler stack is the main reason why we are doing the span here
|
|
410
|
+
})
|
|
411
|
+
),
|
|
413
412
|
meta.moduleName
|
|
414
413
|
] as const
|
|
415
414
|
return acc
|
|
@@ -431,16 +430,19 @@ export const makeRouter = <
|
|
|
431
430
|
]
|
|
432
431
|
}
|
|
433
432
|
|
|
434
|
-
const rpcs = RpcGroup
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
433
|
+
const rpcs = RpcGroup
|
|
434
|
+
.make(
|
|
435
|
+
...typedValuesOf(mapped).map(([resource]) => {
|
|
436
|
+
return Rpc.fromTaggedRequest(resource).annotate(middleware.requestContext, resource.config ?? {})
|
|
437
|
+
})
|
|
438
|
+
)
|
|
439
|
+
.prefix(`${meta.moduleName}.`)
|
|
440
|
+
.middleware(middleware as any)
|
|
439
441
|
const rpcLayer = rpcs.toLayer(Effect.gen(function*() {
|
|
440
442
|
return typedValuesOf(mapped).reduce((acc, [resource, handler]) => {
|
|
441
|
-
acc[resource._tag] = handler
|
|
443
|
+
acc[`${meta.moduleName}.${resource._tag}`] = handler
|
|
442
444
|
return acc
|
|
443
|
-
}, {} as Record<string, any>)
|
|
445
|
+
}, {} as Record<string, any>) as any // TODO
|
|
444
446
|
})) as unknown as Layer<
|
|
445
447
|
{ [K in keyof RequestModules]: Rpc.Handler<K> },
|
|
446
448
|
| Layer.Error<typeof middleware.Default>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
3
3
|
import { expectTypeOf, it } from "@effect/vitest"
|
|
4
4
|
import { Context, Effect, Scope } from "effect-app"
|
|
5
|
-
import { ContextProvider, mergeContextProviders, MergedContextProvider } from "../src/api/
|
|
5
|
+
import { ContextProvider, mergeContextProviders, MergedContextProvider } from "../src/api/ContextProvider.js"
|
|
6
6
|
import { CustomError1, Some, SomeElse, SomeService } from "./fixtures.js"
|
|
7
7
|
|
|
8
8
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAU,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEtF,OAAO,
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAU,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEtF,OAAO,EAAyB,UAAU,EAAE,MAAM,uBAAuB,CAAA;;;;;;;;;;;;;AAEzE,qBAAa,WAAY,SAAQ,gBAKhC;CACA;;;;;;;;;;;;;;;;;;;;;;;;;AAED,qBAAa,IAAK,SAAQ,SAA2D;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AACxF,qBAAa,QAAS,SAAQ,aAAmE;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AAEpG,qBAAa,WAAY,SAAQ,gBAAgE;CAAG;AASpG,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAA;AAEV,KAAK,kBAAkB,GAAG,OAAO,iBAAiB,CAAA;AAClD,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;CAAG;;;;;;;AAEhE,qBAAa,cAAe,SAAQ,mBA4BlC;CACD;;;;;;;;AAID,qBAAa,YAAa,SAAQ,iBA6BhC;CACD;;;;;;;AAGD,qBAAa,IAAK,SAAQ,SASxB;CAAG;;;;AAEL,qBAAa,YAAa,SAAQ,iBAAmD;CAAG;;;;AACxF,qBAAa,YAAa,SAAQ,iBAAmD;CAAG"}
|
package/test/dist/fixtures.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context, Effect, Option, S, Scope } from "effect-app";
|
|
2
2
|
import { NotLoggedInError, RPCContextMap, UnauthorizedError } from "effect-app/client";
|
|
3
3
|
import { TaggedError } from "effect-app/Schema";
|
|
4
|
-
import { contextMap, Middleware } from "../src/api/routing.js";
|
|
4
|
+
import { contextMap, getConfig, Middleware } from "../src/api/routing.js";
|
|
5
5
|
export class UserProfile extends Context.assignTag("UserProfile")(S.Class("UserProfile")({
|
|
6
6
|
id: S.String,
|
|
7
7
|
roles: S.Array(S.String)
|
|
@@ -14,6 +14,7 @@ export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b:
|
|
|
14
14
|
const MakeSomeService = Effect.succeed({ a: 1 });
|
|
15
15
|
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)() {
|
|
16
16
|
}
|
|
17
|
+
const requestConfig = getConfig();
|
|
17
18
|
// TODO: null as never sucks
|
|
18
19
|
// why [UserProfile] is needed? AllowAnonymous triggers an error if just UserProfile without []
|
|
19
20
|
// [] requires return Context, non [] requires return the Service instance
|
|
@@ -29,12 +30,12 @@ export class AllowAnonymous extends Middleware.Tag()("AllowAnonymous", {
|
|
|
29
30
|
requires: SomeElse
|
|
30
31
|
})({
|
|
31
32
|
effect: Effect.gen(function* () {
|
|
32
|
-
return Effect.fnUntraced(function* ({
|
|
33
|
+
return Effect.fnUntraced(function* ({ headers, rpc }) {
|
|
33
34
|
yield* SomeElse;
|
|
34
35
|
yield* Scope.Scope; // provided by HttpRouter.HttpRouter.Provided
|
|
35
36
|
const isLoggedIn = !!headers["x-user"];
|
|
36
37
|
if (!isLoggedIn) {
|
|
37
|
-
if (!
|
|
38
|
+
if (!requestConfig(rpc).allowAnonymous) {
|
|
38
39
|
return yield* new NotLoggedInError({ message: "Not logged in" });
|
|
39
40
|
}
|
|
40
41
|
return Option.none();
|
|
@@ -59,10 +60,10 @@ export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
|
59
60
|
})({
|
|
60
61
|
effect: Effect.gen(function* () {
|
|
61
62
|
yield* SomeService;
|
|
62
|
-
return Effect.fnUntraced(function* ({
|
|
63
|
+
return Effect.fnUntraced(function* ({ next, rpc }) {
|
|
63
64
|
// we don't know if the service will be provided or not, so we use option..
|
|
64
65
|
const userProfile = yield* Effect.serviceOption(UserProfile);
|
|
65
|
-
const { requireRoles } =
|
|
66
|
+
const { requireRoles } = requestConfig(rpc);
|
|
66
67
|
console.dir({
|
|
67
68
|
userProfile,
|
|
68
69
|
requireRoles
|
|
@@ -91,4 +92,4 @@ export class CustomError1 extends TaggedError()("CustomError1", {}) {
|
|
|
91
92
|
}
|
|
92
93
|
export class CustomError2 extends TaggedError()("CustomError1", {}) {
|
|
93
94
|
}
|
|
94
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9maXh0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDdEYsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBRXpFLE1BQU0sT0FBTyxXQUFZLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBMkIsYUFBYSxDQUFDLENBQ3pGLENBQUMsQ0FBQyxLQUFLLENBQWMsYUFBYSxDQUFDLENBQUM7SUFDbEMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNO0lBQ1osS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztDQUN6QixDQUFDLENBQ0g7Q0FDQTtBQUVELE1BQU0sT0FBTyxJQUFLLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQVE7Q0FBRztBQUN4RixNQUFNLE9BQU8sUUFBUyxTQUFRLE9BQU8sQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFZO0NBQUc7QUFDcEcsTUFBTSxlQUFlLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQ2hELE1BQU0sT0FBTyxXQUFZLFNB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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requires.test.d.ts","sourceRoot":"","sources":["../requires.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"requires.test.d.ts","sourceRoot":"","sources":["../requires.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAA2B,KAAK,EAAK,MAAM,YAAY,CAAA;AAG9D,OAAO,EAAkB,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAmD,IAAI,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAA;;;;;;AAElH,qBAAa,cAAe,SAAQ,mBAUlC;CACD;;;;;;;AAGD,qBAAa,kBAAmB,SAAQ,uBAQtC;CACD;;;;;;;AAED,qBAAa,kBAAmB,SAAQ,uBAYtC;CACD;;;;;;;AAED,qBAAa,sBAAuB,SAAQ,2BAa1C;CACD"}
|
package/test/fixtures.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context, Effect, Option, S, Scope } from "effect-app"
|
|
2
2
|
import { NotLoggedInError, RPCContextMap, UnauthorizedError } from "effect-app/client"
|
|
3
3
|
import { TaggedError } from "effect-app/Schema"
|
|
4
|
-
import { contextMap, Middleware } from "../src/api/routing.js"
|
|
4
|
+
import { contextMap, getConfig, Middleware } from "../src/api/routing.js"
|
|
5
5
|
|
|
6
6
|
export class UserProfile extends Context.assignTag<UserProfile, UserProfile>("UserProfile")(
|
|
7
7
|
S.Class<UserProfile>("UserProfile")({
|
|
@@ -16,6 +16,8 @@ export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b:
|
|
|
16
16
|
const MakeSomeService = Effect.succeed({ a: 1 })
|
|
17
17
|
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)<SomeService>() {}
|
|
18
18
|
|
|
19
|
+
const requestConfig = getConfig<RequestContextMap>()
|
|
20
|
+
|
|
19
21
|
// TODO: null as never sucks
|
|
20
22
|
// why [UserProfile] is needed? AllowAnonymous triggers an error if just UserProfile without []
|
|
21
23
|
// [] requires return Context, non [] requires return the Service instance
|
|
@@ -36,12 +38,12 @@ export class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnony
|
|
|
36
38
|
})({
|
|
37
39
|
effect: Effect.gen(function*() {
|
|
38
40
|
return Effect.fnUntraced(
|
|
39
|
-
function*({
|
|
41
|
+
function*({ headers, rpc }) {
|
|
40
42
|
yield* SomeElse
|
|
41
43
|
yield* Scope.Scope // provided by HttpRouter.HttpRouter.Provided
|
|
42
44
|
const isLoggedIn = !!headers["x-user"]
|
|
43
45
|
if (!isLoggedIn) {
|
|
44
|
-
if (!
|
|
46
|
+
if (!requestConfig(rpc).allowAnonymous) {
|
|
45
47
|
return yield* new NotLoggedInError({ message: "Not logged in" })
|
|
46
48
|
}
|
|
47
49
|
return Option.none()
|
|
@@ -74,10 +76,10 @@ export class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles",
|
|
|
74
76
|
effect: Effect.gen(function*() {
|
|
75
77
|
yield* SomeService
|
|
76
78
|
return Effect.fnUntraced(
|
|
77
|
-
function*({
|
|
79
|
+
function*({ next, rpc }) {
|
|
78
80
|
// we don't know if the service will be provided or not, so we use option..
|
|
79
81
|
const userProfile = yield* Effect.serviceOption(UserProfile)
|
|
80
|
-
const { requireRoles } =
|
|
82
|
+
const { requireRoles } = requestConfig(rpc)
|
|
81
83
|
console.dir(
|
|
82
84
|
{
|
|
83
85
|
userProfile,
|