@effect-app/infra 2.86.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.
- package/CHANGELOG.md +11 -0
- package/dist/api/layerUtils.d.ts +1 -5
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +3 -11
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +33 -0
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -0
- package/dist/api/routing/middleware/RouterMiddleware.js +5 -0
- package/dist/api/routing/middleware/RpcMiddleware.d.ts +199 -0
- package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -0
- package/dist/api/routing/middleware/RpcMiddleware.js +14 -0
- package/dist/api/routing/middleware/dynamic-middleware.d.ts +2 -12
- package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/dynamic-middleware.js +2 -18
- package/dist/api/routing/middleware/generic-middleware.d.ts +4 -23
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +13 -9
- package/dist/api/routing/middleware/middleware-api.d.ts +43 -7
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +47 -22
- package/dist/api/routing/middleware/middleware.d.ts +3 -3
- package/dist/api/routing/middleware/middleware.js +2 -2
- package/dist/api/routing/middleware.d.ts +2 -1
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +3 -2
- package/dist/api/routing/tsort.d.ts +2 -2
- package/dist/api/routing/tsort.d.ts.map +1 -1
- package/dist/api/routing/tsort.js +1 -1
- package/package.json +9 -5
- package/src/api/layerUtils.ts +4 -18
- package/src/api/routing/middleware/RouterMiddleware.ts +149 -0
- package/src/api/routing/middleware/RpcMiddleware.ts +287 -0
- package/src/api/routing/middleware/dynamic-middleware.ts +5 -52
- package/src/api/routing/middleware/generic-middleware.ts +23 -34
- package/src/api/routing/middleware/middleware-api.ts +142 -59
- package/src/api/routing/middleware/middleware.ts +1 -1
- package/src/api/routing/middleware.ts +2 -1
- package/src/api/routing/tsort.ts +2 -2
- package/test/controller.test.ts +22 -58
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/fixtures.d.ts +4 -2
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +21 -9
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/fixtures.ts +29 -12
- package/test/requires.test.ts +98 -17
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +0 -229
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/DynamicMiddleware.js +0 -168
- package/src/api/routing/middleware/DynamicMiddleware.ts +0 -715
|
@@ -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 {
|
|
3
|
-
import { type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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,
|
|
@@ -48,47 +45,3 @@ export namespace ContextWithLayer {
|
|
|
48
45
|
any
|
|
49
46
|
>
|
|
50
47
|
}
|
|
51
|
-
|
|
52
|
-
// 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.
|
|
53
|
-
export const implementMiddleware = <T extends Record<string, RPCContextMap.Any>>() =>
|
|
54
|
-
<
|
|
55
|
-
TI extends {
|
|
56
|
-
[K in keyof T]: ContextWithLayer.Base<
|
|
57
|
-
{ [K in keyof T]?: T[K]["contextActivation"] },
|
|
58
|
-
T[K]["service"],
|
|
59
|
-
S.Schema.Type<T[K]["error"]>
|
|
60
|
-
>
|
|
61
|
-
}
|
|
62
|
-
>(implementations: TI) => ({
|
|
63
|
-
dependencies: typedValuesOf(implementations).map((_) => _.Default) as {
|
|
64
|
-
[K in keyof TI]: TI[K]["Default"]
|
|
65
|
-
}[keyof TI][],
|
|
66
|
-
effect: Effect.gen(function*() {
|
|
67
|
-
const sorted = sort(typedValuesOf(implementations))
|
|
68
|
-
|
|
69
|
-
const makers = yield* Effect.all(sorted)
|
|
70
|
-
return Effect.fnUntraced(
|
|
71
|
-
function*(options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }) {
|
|
72
|
-
const ctx = yield* mergeOptionContexts(
|
|
73
|
-
Array.map(
|
|
74
|
-
makers,
|
|
75
|
-
(_, i) => ({ maker: sorted[i], handle: (_ as any)(options) as any }) as any
|
|
76
|
-
)
|
|
77
|
-
)
|
|
78
|
-
return ctx as Context.Context<
|
|
79
|
-
GetEffectContext<T, typeof options["config"]>
|
|
80
|
-
>
|
|
81
|
-
}
|
|
82
|
-
)
|
|
83
|
-
}) as unknown as Effect<
|
|
84
|
-
(
|
|
85
|
-
options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }
|
|
86
|
-
) => Effect.Effect<
|
|
87
|
-
Context.Context<GetEffectContext<T, typeof options["config"]>>,
|
|
88
|
-
Effect.Error<ReturnType<Tag.Service<TI[keyof TI]>>>,
|
|
89
|
-
Effect.Context<ReturnType<Tag.Service<TI[keyof TI]>>>
|
|
90
|
-
>,
|
|
91
|
-
never,
|
|
92
|
-
Tag.Identifier<{ [K in keyof TI]: TI[K] }[keyof TI]>
|
|
93
|
-
>
|
|
94
|
-
})
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { type Rpc, type RpcMiddleware } from "@effect/rpc"
|
|
3
|
-
import { type SuccessValue
|
|
4
|
-
import { type Array, Context, Effect, type Layer, type NonEmptyReadonlyArray,
|
|
5
|
-
import { type
|
|
3
|
+
import { type SuccessValue } from "@effect/rpc/RpcMiddleware"
|
|
4
|
+
import { type Array, Context, Effect, type Layer, type NonEmptyReadonlyArray, Option, type Scope } from "effect-app"
|
|
5
|
+
import { type ContextRepr } from "effect-app/client"
|
|
6
6
|
import { type HttpHeaders } from "effect-app/http"
|
|
7
|
-
import { type Tag } from "effect/Context"
|
|
8
7
|
import { InfraLogger } from "../../../logger.js"
|
|
9
|
-
import { type
|
|
10
|
-
|
|
11
|
-
export type ContextRepr = NonEmptyReadonlyArray<Context.Tag<any, any>>
|
|
12
|
-
export namespace ContextRepr {
|
|
13
|
-
export type Identifier<A> = A extends ContextRepr ? Tag.Identifier<A[number]> : never
|
|
14
|
-
export type Service<A> = A extends ContextRepr ? Tag.Service<A[number]> : never
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface TagClassAny extends Context.Tag<any, any> {
|
|
18
|
-
readonly [TypeId]: TypeId
|
|
19
|
-
readonly optional: boolean
|
|
20
|
-
readonly provides?: Context.Tag<any, any> | ContextRepr | undefined
|
|
21
|
-
readonly requires?: Context.Tag<any, any> | ContextRepr | undefined
|
|
22
|
-
readonly failure: Schema.Schema.All
|
|
23
|
-
readonly requiredForClient: boolean
|
|
24
|
-
readonly wrap: boolean
|
|
25
|
-
}
|
|
8
|
+
import { type TagClassAny } from "./RpcMiddleware.js"
|
|
26
9
|
|
|
27
10
|
export interface GenericMiddlewareOptions<E> {
|
|
28
11
|
// Effect rpc middleware does not support changing payload or headers, but we do..
|
|
@@ -34,9 +17,6 @@ export interface GenericMiddlewareOptions<E> {
|
|
|
34
17
|
}
|
|
35
18
|
|
|
36
19
|
export type GenericMiddlewareMaker = TagClassAny & { Default: Layer.Layer.Any } // todo; and Layer..
|
|
37
|
-
export type DynamicMiddlewareMaker<RequestContext extends Record<string, RPCContextMap.Any>> =
|
|
38
|
-
& TagClassDynamicAny<RequestContext>
|
|
39
|
-
& { Default: Layer.Layer.Any } // todo; and Layer..
|
|
40
20
|
|
|
41
21
|
export namespace GenericMiddlewareMaker {
|
|
42
22
|
export type ApplyServices<A extends TagClassAny, R> = Exclude<R, Provided<A>> | Required<A>
|
|
@@ -56,8 +36,6 @@ export namespace GenericMiddlewareMaker {
|
|
|
56
36
|
: never
|
|
57
37
|
}
|
|
58
38
|
|
|
59
|
-
export const genericMiddleware = (i: GenericMiddlewareMaker) => i
|
|
60
|
-
|
|
61
39
|
export const genericMiddlewareMaker = <
|
|
62
40
|
T extends Array<GenericMiddlewareMaker>
|
|
63
41
|
>(...middlewares: T): {
|
|
@@ -70,11 +48,6 @@ export const genericMiddlewareMaker = <
|
|
|
70
48
|
dependencies: middlewares.map((_) => _.Default),
|
|
71
49
|
effect: Effect.gen(function*() {
|
|
72
50
|
const context = yield* Effect.context()
|
|
73
|
-
// const middlewares: readonly (RpcMiddlewareWrap<any, any> | RpcMiddleware.RpcMiddleware<any, any>)[] =
|
|
74
|
-
// (yield* Effect.all(
|
|
75
|
-
// middlewares
|
|
76
|
-
// )) as any
|
|
77
|
-
|
|
78
51
|
return <E>(
|
|
79
52
|
options: GenericMiddlewareOptions<E>
|
|
80
53
|
) => {
|
|
@@ -83,13 +56,13 @@ export const genericMiddlewareMaker = <
|
|
|
83
56
|
for (const tag of middlewares) {
|
|
84
57
|
if (tag.wrap) {
|
|
85
58
|
const middleware = Context.unsafeGet(context, tag)
|
|
86
|
-
handler = InfraLogger.logDebug("Applying middleware " + tag.key).pipe(
|
|
87
|
-
Effect.zipRight(middleware({ ...options, next: handler
|
|
59
|
+
handler = InfraLogger.logDebug("Applying middleware wrap " + tag.key).pipe(
|
|
60
|
+
Effect.zipRight(middleware({ ...options, next: handler }))
|
|
88
61
|
) as any
|
|
89
62
|
} else if (tag.optional) {
|
|
90
63
|
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
91
64
|
const previous = handler
|
|
92
|
-
handler = InfraLogger.logDebug("Applying middleware " + tag.key).pipe(
|
|
65
|
+
handler = InfraLogger.logDebug("Applying middleware optional " + tag.key).pipe(
|
|
93
66
|
Effect.zipRight(Effect.matchEffect(middleware(options), {
|
|
94
67
|
onFailure: () => previous,
|
|
95
68
|
onSuccess: tag.provides !== undefined
|
|
@@ -100,6 +73,22 @@ export const genericMiddlewareMaker = <
|
|
|
100
73
|
: (_) => previous
|
|
101
74
|
}))
|
|
102
75
|
)
|
|
76
|
+
} else if (tag.dynamic) {
|
|
77
|
+
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
78
|
+
const previous = handler
|
|
79
|
+
handler = InfraLogger.logDebug("Applying middleware dynamic " + tag.key, tag.dynamic).pipe(
|
|
80
|
+
Effect.zipRight(
|
|
81
|
+
middleware(options).pipe(
|
|
82
|
+
Effect.flatMap((value) =>
|
|
83
|
+
Option.isSome(value)
|
|
84
|
+
? Context.isContext(value.value)
|
|
85
|
+
? Effect.provide(previous, value.value)
|
|
86
|
+
: Effect.provideService(previous, tag.dynamic!.settings.service!, /* TODO */ value.value)
|
|
87
|
+
: previous
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
)
|
|
103
92
|
} else {
|
|
104
93
|
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
105
94
|
const previous = handler
|