@effect-app/infra 2.87.2 → 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 +24 -1
- 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 -28
- 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 +19 -23
- 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/dynamic-middleware.d.ts +1 -9
- package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.d.ts +24 -22
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +24 -8
- package/dist/api/routing/middleware/middleware-api.d.ts +68 -36
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +45 -45
- package/dist/api/routing/middleware/middleware.d.ts +7 -7
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +5 -5
- 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 -134
- package/src/api/routing/middleware/RpcMiddleware.ts +28 -23
- package/src/api/routing/middleware/dynamic-middleware.ts +0 -47
- package/src/api/routing/middleware/generic-middleware.ts +84 -35
- package/src/api/routing/middleware/middleware-api.ts +190 -159
- package/src/api/routing/middleware/middleware.ts +5 -5
- package/src/api/routing/middleware.ts +0 -1
- package/src/api/routing.ts +22 -20
- package/test/contextProvider.test.ts +28 -25
- package/test/controller.test.ts +44 -9
- package/test/dist/contextProvider.test.d.ts.map +1 -1
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/fixtures.d.ts +39 -45
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +27 -14
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/fixtures.ts +29 -18
- package/test/layerUtils.test.ts +1 -2
- package/test/requires.test.ts +146 -103
- package/dist/api/routing/middleware/ContextProvider.d.ts.map +0 -1
- package/dist/api/routing/middleware/ContextProvider.js +0 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.89.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"proper-lockfile": "^4.1.2",
|
|
14
14
|
"pure-rand": "7.0.1",
|
|
15
15
|
"query-string": "^9.2.2",
|
|
16
|
-
"effect-app": "2.
|
|
16
|
+
"effect-app": "2.53.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@azure/cosmos": "^4.5.0",
|
|
@@ -278,6 +278,10 @@
|
|
|
278
278
|
"types": "./dist/adapters/redis-client.d.ts",
|
|
279
279
|
"default": "./dist/adapters/redis-client.js"
|
|
280
280
|
},
|
|
281
|
+
"./api/ContextProvider": {
|
|
282
|
+
"types": "./dist/api/ContextProvider.d.ts",
|
|
283
|
+
"default": "./dist/api/ContextProvider.js"
|
|
284
|
+
},
|
|
281
285
|
"./api/codec": {
|
|
282
286
|
"types": "./dist/api/codec.d.ts",
|
|
283
287
|
"default": "./dist/api/codec.js"
|
|
@@ -302,10 +306,6 @@
|
|
|
302
306
|
"types": "./dist/api/routing/middleware.d.ts",
|
|
303
307
|
"default": "./dist/api/routing/middleware.js"
|
|
304
308
|
},
|
|
305
|
-
"./api/routing/middleware/ContextProvider": {
|
|
306
|
-
"types": "./dist/api/routing/middleware/ContextProvider.d.ts",
|
|
307
|
-
"default": "./dist/api/routing/middleware/ContextProvider.js"
|
|
308
|
-
},
|
|
309
309
|
"./api/routing/middleware/RouterMiddleware": {
|
|
310
310
|
"types": "./dist/api/routing/middleware/RouterMiddleware.d.ts",
|
|
311
311
|
"default": "./dist/api/routing/middleware/RouterMiddleware.js"
|
|
@@ -4,7 +4,7 @@ import { Context, Effect, Layer, type NonEmptyReadonlyArray, pipe, type Scope }
|
|
|
4
4
|
import { type HttpRouter } from "effect-app/http"
|
|
5
5
|
import { type Tag } from "effect/Context"
|
|
6
6
|
import { type YieldWrap } from "effect/Utils"
|
|
7
|
-
import { type ContextTagWithDefault, type GetContext, type LayerUtils, mergeContexts } from "
|
|
7
|
+
import { type ContextTagWithDefault, type GetContext, type LayerUtils, mergeContexts } from "./layerUtils.js"
|
|
8
8
|
|
|
9
9
|
export namespace EffectGenUtils {
|
|
10
10
|
export type Success<EG> = EG extends Effect<infer A, infer _E, infer _R> ? A
|
|
@@ -1,149 +1,37 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
-
import { type
|
|
5
|
-
import type {
|
|
6
|
-
import type
|
|
7
|
-
import { type
|
|
8
|
-
import { type ContextWithLayer } from "./dynamic-middleware.js"
|
|
4
|
+
import { type Context, type Layer, type S } from "effect-app"
|
|
5
|
+
import type { GetContextConfig, RPCContextMap } from "effect-app/client/req"
|
|
6
|
+
import { type MiddlewareMakerId } from "./middleware-api.js"
|
|
7
|
+
import { type TagClass } from "./RpcMiddleware.js"
|
|
9
8
|
|
|
10
9
|
// module:
|
|
11
10
|
//
|
|
12
|
-
export type MakeRPCHandlerFactory<
|
|
13
|
-
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
14
|
-
MiddlewareR
|
|
15
|
-
> = <
|
|
16
|
-
T extends {
|
|
17
|
-
config?: Partial<Record<keyof RequestContextMap, any>>
|
|
18
|
-
},
|
|
19
|
-
Req extends S.TaggedRequest.All,
|
|
20
|
-
HandlerR
|
|
21
|
-
>(
|
|
22
|
-
schema: T & S.Schema<Req, any, never>,
|
|
23
|
-
next: (
|
|
24
|
-
request: Req,
|
|
25
|
-
headers: any
|
|
26
|
-
) => Effect.Effect<
|
|
27
|
-
EffectRequest.Request.Success<Req>,
|
|
28
|
-
EffectRequest.Request.Error<Req>,
|
|
29
|
-
// dynamic middlewares removes the dynamic context from HandlerR
|
|
30
|
-
Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>
|
|
31
|
-
>,
|
|
32
|
-
moduleName: string
|
|
33
|
-
) => (
|
|
34
|
-
req: Req,
|
|
35
|
-
headers: any
|
|
36
|
-
) => Effect.Effect<
|
|
37
|
-
Request.Request.Success<Req>,
|
|
38
|
-
Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
|
|
39
|
-
// the middleware will remove from HandlerR the dynamic context, but will also add some requirements
|
|
40
|
-
| MiddlewareR
|
|
41
|
-
// & S.Schema<Req, any, never> is useless here but useful when creating the middleware
|
|
42
|
-
| Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>
|
|
43
|
-
>
|
|
44
|
-
|
|
45
|
-
export type RPCHandlerFactory<
|
|
46
|
-
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
47
|
-
ContextProviderA
|
|
48
|
-
> = <
|
|
49
|
-
T extends {
|
|
50
|
-
config?: Partial<Record<keyof RequestContextMap, any>>
|
|
51
|
-
},
|
|
52
|
-
Req extends S.TaggedRequest.All,
|
|
53
|
-
HandlerR
|
|
54
|
-
>(
|
|
55
|
-
schema: T & S.Schema<Req, any, never>,
|
|
56
|
-
next: (
|
|
57
|
-
request: Req,
|
|
58
|
-
headers: any
|
|
59
|
-
) => Effect.Effect<
|
|
60
|
-
EffectRequest.Request.Success<Req>,
|
|
61
|
-
EffectRequest.Request.Error<Req>,
|
|
62
|
-
HandlerR
|
|
63
|
-
>,
|
|
64
|
-
moduleName: string
|
|
65
|
-
) => (
|
|
66
|
-
req: Req,
|
|
67
|
-
headers: any
|
|
68
|
-
) => Effect.Effect<
|
|
69
|
-
Request.Request.Success<Req>,
|
|
70
|
-
Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
|
|
71
|
-
| Scope.Scope // because of the context provider and the middleware (Middleware)
|
|
72
|
-
| Exclude<
|
|
73
|
-
// the middleware will remove from HandlerR the dynamic context
|
|
74
|
-
// & S.Schema<Req, any, never> is useless here but useful when creating the middleware
|
|
75
|
-
Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>,
|
|
76
|
-
// the context provider provides additional stuff both to the middleware and the next
|
|
77
|
-
ContextProviderA
|
|
78
|
-
>
|
|
79
|
-
>
|
|
80
|
-
|
|
81
|
-
export type RequestContextMapProvider<RequestContextMap extends Record<string, RPCContextMap.Any>> = {
|
|
82
|
-
[K in keyof RequestContextMap]: ContextWithLayer.Base<
|
|
83
|
-
{ [K in keyof RequestContextMap]?: RequestContextMap[K]["contextActivation"] },
|
|
84
|
-
RequestContextMap[K]["service"],
|
|
85
|
-
S.Schema.Type<RequestContextMap[K]["error"]>
|
|
86
|
-
>
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface MiddlewareMakerId {
|
|
90
|
-
_tag: "MiddlewareMaker"
|
|
91
|
-
}
|
|
92
11
|
|
|
93
12
|
export type RouterMiddleware<
|
|
94
13
|
RequestContextMap extends Record<string, RPCContextMap.Any>, // what services will the middlware provide dynamically to the next, or raise errors.
|
|
95
14
|
MakeMiddlewareE, // what the middleware construction can fail with
|
|
96
15
|
MakeMiddlewareR, // what the middlware requires to be constructed
|
|
97
|
-
ContextProviderA // what the context provider provides
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
>
|
|
16
|
+
ContextProviderA, // what the context provider provides
|
|
17
|
+
ContextProviderE, // what the context provider may fail with
|
|
18
|
+
ContextProviderR // what the context provider may error with
|
|
19
|
+
> =
|
|
20
|
+
& TagClass<
|
|
21
|
+
MiddlewareMakerId,
|
|
22
|
+
"MiddlewareMaker",
|
|
23
|
+
{
|
|
24
|
+
wrap: true
|
|
25
|
+
provides: [Context.Tag<ContextProviderA, ContextProviderA>] // ContextProviderA extends never ? never : [Context.Tag<ContextProviderA, ContextProviderA>] // TODO: Tag<A>, Tag<B>
|
|
26
|
+
requires: [Context.Tag<ContextProviderR, ContextProviderR>] // ContextProviderE extends never ? never : [Context.Tag<ContextProviderR, ContextProviderR>] // TODO: Tag<A>, Tag<B>
|
|
27
|
+
failure: ContextProviderE
|
|
28
|
+
}
|
|
29
|
+
>
|
|
30
|
+
& {
|
|
31
|
+
Default: Layer.Layer<MiddlewareMakerId, MakeMiddlewareE, MakeMiddlewareR>
|
|
32
|
+
requestContext: Context.Tag<"RequestContextConfig", GetContextConfig<RequestContextMap>>
|
|
33
|
+
}
|
|
107
34
|
|
|
108
35
|
export type RequestContextMapErrors<RequestContextMap extends Record<string, RPCContextMap.Any>> = S.Schema.Type<
|
|
109
36
|
RequestContextMap[keyof RequestContextMap]["error"]
|
|
110
37
|
>
|
|
111
|
-
|
|
112
|
-
// it just provides the right types without cluttering the implementation with them
|
|
113
|
-
export function makeRpcEffect<
|
|
114
|
-
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
115
|
-
ContextProviderA
|
|
116
|
-
>() {
|
|
117
|
-
return (
|
|
118
|
-
cb: <
|
|
119
|
-
T extends {
|
|
120
|
-
config?: Partial<Record<keyof RequestContextMap, any>>
|
|
121
|
-
},
|
|
122
|
-
Req extends S.TaggedRequest.All,
|
|
123
|
-
HandlerR
|
|
124
|
-
>(
|
|
125
|
-
schema: T & S.Schema<Req, any, never>,
|
|
126
|
-
next: (
|
|
127
|
-
request: Req,
|
|
128
|
-
headers: any
|
|
129
|
-
) => Effect.Effect<
|
|
130
|
-
EffectRequest.Request.Success<Req>,
|
|
131
|
-
EffectRequest.Request.Error<Req>,
|
|
132
|
-
HandlerR
|
|
133
|
-
>,
|
|
134
|
-
moduleName: string
|
|
135
|
-
) => (
|
|
136
|
-
req: Req,
|
|
137
|
-
headers: any
|
|
138
|
-
) => Effect.Effect<
|
|
139
|
-
Request.Request.Success<Req>,
|
|
140
|
-
Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
|
|
141
|
-
| Scope.Scope // the context provider may require Scope to run
|
|
142
|
-
| Exclude<
|
|
143
|
-
// it can also be removed from HandlerR
|
|
144
|
-
Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>,
|
|
145
|
-
ContextProviderA
|
|
146
|
-
>
|
|
147
|
-
>
|
|
148
|
-
) => cb
|
|
149
|
-
}
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
import { type Rpc, RpcMiddleware } from "@effect/rpc"
|
|
5
5
|
import { type SuccessValue, type TypeId } from "@effect/rpc/RpcMiddleware"
|
|
6
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,
|
|
7
|
+
import type { AnyService, ContextTagArray, RPCContextMap } from "effect-app/client/req"
|
|
8
8
|
import { type HttpHeaders } from "effect-app/http"
|
|
9
9
|
import { type TagUnify, type TagUnifyIgnore } from "effect/Context"
|
|
10
10
|
import { type LayerUtils } from "../../layerUtils.js"
|
|
11
11
|
|
|
12
|
-
// updated to support Scope.Scope
|
|
12
|
+
// updated to support Scope.Scope and Requires
|
|
13
13
|
export interface RpcMiddleware<Provides, E, Requires> {
|
|
14
14
|
(options: {
|
|
15
15
|
readonly clientId: number
|
|
@@ -47,19 +47,18 @@ export type DependsOn = {
|
|
|
47
47
|
readonly dependsOn: NonEmptyReadonlyArray<AnyDynamic> | undefined
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
interface RpcOptionsDynamic<Key extends string, A extends RPCContextMap.Any> extends RpcOptionsOriginal {
|
|
51
51
|
readonly dynamic: RpcDynamic<Key, A>
|
|
52
52
|
readonly dependsOn?: NonEmptyReadonlyArray<AnyDynamic> | undefined
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export type Dynamic<Options> = Options extends RpcOptionsDynamic<any, any> ? true : false
|
|
56
56
|
|
|
57
|
-
export interface RpcMiddlewareDynamicWrap<E, R,
|
|
57
|
+
export interface RpcMiddlewareDynamicWrap<E, R, _Config> {
|
|
58
58
|
(options: {
|
|
59
59
|
readonly next: Effect.Effect<SuccessValue, E, Scope.Scope | R>
|
|
60
|
-
readonly config: Config // todo
|
|
61
60
|
readonly clientId: number
|
|
62
|
-
readonly rpc: Rpc.AnyWithProps
|
|
61
|
+
readonly rpc: Rpc.AnyWithProps // TODO & { annotations: Context.Context<RequestContextMap<Config>> }
|
|
63
62
|
readonly payload: unknown
|
|
64
63
|
readonly headers: HttpHeaders.Headers
|
|
65
64
|
}): Effect.Effect<
|
|
@@ -69,11 +68,10 @@ export interface RpcMiddlewareDynamicWrap<E, R, Config> {
|
|
|
69
68
|
>
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
export interface RpcMiddlewareDynamicNormal<A, E, R,
|
|
71
|
+
export interface RpcMiddlewareDynamicNormal<A, E, R, _Config> {
|
|
73
72
|
(options: {
|
|
74
|
-
readonly config: Config // todo
|
|
75
73
|
readonly clientId: number
|
|
76
|
-
readonly rpc: Rpc.AnyWithProps
|
|
74
|
+
readonly rpc: Rpc.AnyWithProps // TODO & { annotations: Context.Context<RequestContextMap<Config>> }
|
|
77
75
|
readonly payload: unknown
|
|
78
76
|
readonly headers: HttpHeaders.Headers
|
|
79
77
|
}): Effect.Effect<
|
|
@@ -86,8 +84,8 @@ export interface RpcMiddlewareDynamicNormal<A, E, R, Config> {
|
|
|
86
84
|
export interface TagClassAny extends Context.Tag<any, any> {
|
|
87
85
|
readonly [TypeId]: TypeId
|
|
88
86
|
readonly optional: boolean
|
|
89
|
-
readonly provides?: Context.Tag<any, any> |
|
|
90
|
-
readonly requires?: Context.Tag<any, any> |
|
|
87
|
+
readonly provides?: Context.Tag<any, any> | ContextTagArray | undefined
|
|
88
|
+
readonly requires?: Context.Tag<any, any> | ContextTagArray | undefined
|
|
91
89
|
readonly failure: Schema.Schema.All
|
|
92
90
|
readonly requiredForClient: boolean
|
|
93
91
|
readonly wrap: boolean
|
|
@@ -105,9 +103,9 @@ export declare namespace TagClass {
|
|
|
105
103
|
readonly optional?: false
|
|
106
104
|
} ? Context.Tag.Identifier<Options["provides"]>
|
|
107
105
|
: Options extends {
|
|
108
|
-
readonly provides:
|
|
106
|
+
readonly provides: ContextTagArray
|
|
109
107
|
readonly optional?: false
|
|
110
|
-
} ?
|
|
108
|
+
} ? ContextTagArray.Identifier<Options["provides"]>
|
|
111
109
|
: never
|
|
112
110
|
|
|
113
111
|
/**
|
|
@@ -118,8 +116,8 @@ export declare namespace TagClass {
|
|
|
118
116
|
readonly requires: Context.Tag<any, any>
|
|
119
117
|
} ? Context.Tag.Identifier<Options["requires"]>
|
|
120
118
|
: Options extends {
|
|
121
|
-
readonly requires:
|
|
122
|
-
} ?
|
|
119
|
+
readonly requires: ContextTagArray
|
|
120
|
+
} ? ContextTagArray.Identifier<Options["requires"]>
|
|
123
121
|
: never
|
|
124
122
|
|
|
125
123
|
/**
|
|
@@ -130,7 +128,8 @@ export declare namespace TagClass {
|
|
|
130
128
|
? Context.Tag.Service<Options["provides"]>
|
|
131
129
|
: Options extends { readonly dynamic: RpcDynamic<any, infer A> }
|
|
132
130
|
? Options extends { wrap: true } ? void : AnyService.Bla<A["service"]>
|
|
133
|
-
: Options extends { readonly provides:
|
|
131
|
+
: Options extends { readonly provides: ContextTagArray }
|
|
132
|
+
? Context.Context<ContextTagArray.Identifier<Options["provides"]>>
|
|
134
133
|
: void
|
|
135
134
|
|
|
136
135
|
/**
|
|
@@ -139,7 +138,8 @@ export declare namespace TagClass {
|
|
|
139
138
|
*/
|
|
140
139
|
export type FailureSchema<Options> = Options extends
|
|
141
140
|
{ readonly failure: Schema.Schema.All; readonly optional?: false } ? Options["failure"]
|
|
142
|
-
|
|
141
|
+
// actually not, the Failure depends on Dynamic Middleware Configuration!
|
|
142
|
+
// : Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["error"]
|
|
143
143
|
: typeof Schema.Never
|
|
144
144
|
|
|
145
145
|
/**
|
|
@@ -148,6 +148,7 @@ export declare namespace TagClass {
|
|
|
148
148
|
*/
|
|
149
149
|
export type Failure<Options> = Options extends
|
|
150
150
|
{ readonly failure: Schema.Schema<infer _A, infer _I, infer _R>; readonly optional?: false } ? _A
|
|
151
|
+
// actually not, the Failure depends on Dynamic Middleware Configuration!
|
|
151
152
|
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? S.Schema.Type<A["error"]>
|
|
152
153
|
: never
|
|
153
154
|
|
|
@@ -191,10 +192,10 @@ export declare namespace TagClass {
|
|
|
191
192
|
readonly optional: Optional<Options>
|
|
192
193
|
readonly failure: FailureSchema<Options>
|
|
193
194
|
readonly provides: Options extends { readonly provides: Context.Tag<any, any> } ? Options["provides"]
|
|
194
|
-
: Options extends { readonly provides:
|
|
195
|
+
: Options extends { readonly provides: ContextTagArray } ? Options["provides"]
|
|
195
196
|
: undefined
|
|
196
197
|
readonly requires: Options extends { readonly requires: Context.Tag<any, any> } ? Options["requires"]
|
|
197
|
-
: Options extends { readonly requires:
|
|
198
|
+
: Options extends { readonly requires: ContextTagArray } ? Options["requires"]
|
|
198
199
|
: undefined
|
|
199
200
|
readonly dynamic: Options extends RpcOptionsDynamic<any, any> ? Options["dynamic"]
|
|
200
201
|
: undefined
|
|
@@ -226,8 +227,8 @@ export interface TagClass<
|
|
|
226
227
|
>
|
|
227
228
|
: TagClass.Wrap<Options> extends true ? RpcMiddlewareWrap<
|
|
228
229
|
TagClass.Provides<Options>,
|
|
229
|
-
TagClass.
|
|
230
|
-
TagClass.
|
|
230
|
+
TagClass.Failure<Options>,
|
|
231
|
+
TagClass.Requires<Options>
|
|
231
232
|
>
|
|
232
233
|
: RpcMiddleware<
|
|
233
234
|
TagClass.Service<Options>,
|
|
@@ -245,7 +246,7 @@ export const Tag = <Self>() =>
|
|
|
245
246
|
id: Name,
|
|
246
247
|
options?: Options | undefined
|
|
247
248
|
) =>
|
|
248
|
-
<E, R, L extends
|
|
249
|
+
<E, R, L extends ReadonlyArray<Layer.Layer.Any>>(opts: {
|
|
249
250
|
effect: Effect.Effect<
|
|
250
251
|
Options extends RpcOptionsDynamic<any, any> ? TagClass.Wrap<Options> extends true ? RpcMiddlewareDynamicWrap<
|
|
251
252
|
TagClass.FailureService<Options>,
|
|
@@ -273,7 +274,11 @@ export const Tag = <Self>() =>
|
|
|
273
274
|
>
|
|
274
275
|
dependencies?: L
|
|
275
276
|
}): TagClass<Self, Name, Options> & {
|
|
276
|
-
Default: Layer.Layer<
|
|
277
|
+
Default: Layer.Layer<
|
|
278
|
+
Self,
|
|
279
|
+
E | LayerUtils.GetLayersError<L>,
|
|
280
|
+
Exclude<R, LayerUtils.GetLayersSuccess<L>> | LayerUtils.GetLayersContext<L>
|
|
281
|
+
>
|
|
277
282
|
} =>
|
|
278
283
|
class extends RpcMiddleware.Tag<Self>()(id, options as any) {
|
|
279
284
|
static readonly dynamic = options && "dynamic" in options ? options.dynamic : undefined
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
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>
|
|
7
|
-
|
|
8
|
-
export type ContextWithLayer<
|
|
9
|
-
Config,
|
|
10
|
-
Service,
|
|
11
|
-
Error,
|
|
12
|
-
Dependencies,
|
|
13
|
-
Id,
|
|
14
|
-
LayerE,
|
|
15
|
-
LayerR
|
|
16
|
-
> =
|
|
17
|
-
& (
|
|
18
|
-
| ContextTagWithDefault<
|
|
19
|
-
Id,
|
|
20
|
-
// todo
|
|
21
|
-
RpcMiddlewareDynamic<Service, Error, any, Config>,
|
|
22
|
-
LayerE,
|
|
23
|
-
LayerR
|
|
24
|
-
>
|
|
25
|
-
| ContextTagWithDefault<
|
|
26
|
-
Id,
|
|
27
|
-
// todo
|
|
28
|
-
RpcMiddlewareDynamic<Service, Error, never, Config>,
|
|
29
|
-
LayerE,
|
|
30
|
-
LayerR
|
|
31
|
-
>
|
|
32
|
-
)
|
|
33
|
-
& {
|
|
34
|
-
dependsOn?: Dependencies
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export namespace ContextWithLayer {
|
|
38
|
-
export type Base<Config, Service, Error> = ContextWithLayer<
|
|
39
|
-
Config,
|
|
40
|
-
Service,
|
|
41
|
-
Error,
|
|
42
|
-
any,
|
|
43
|
-
any,
|
|
44
|
-
any,
|
|
45
|
-
any
|
|
46
|
-
>
|
|
47
|
-
}
|
|
@@ -1,67 +1,105 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { type
|
|
3
|
-
import { type
|
|
4
|
-
import { type
|
|
5
|
-
import { type ContextRepr } from "effect-app/client"
|
|
6
|
-
import { type HttpHeaders } from "effect-app/http"
|
|
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 } from "effect-app/client"
|
|
7
5
|
import { InfraLogger } from "../../../logger.js"
|
|
8
|
-
import { type TagClassAny } from "./RpcMiddleware.js"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// Effect rpc middleware does not support changing payload or headers, but we do..
|
|
12
|
-
readonly next: Effect.Effect<SuccessValue, E, Scope.Scope>
|
|
13
|
-
readonly payload: unknown
|
|
14
|
-
readonly headers: HttpHeaders.Headers
|
|
15
|
-
readonly clientId: number
|
|
16
|
-
readonly rpc: Rpc.AnyWithProps
|
|
17
|
-
}
|
|
6
|
+
import { type RpcMiddlewareWrap, type TagClassAny } from "./RpcMiddleware.js"
|
|
7
|
+
|
|
8
|
+
// Effect rpc middleware does not support changing payload or headers, but we do..
|
|
18
9
|
|
|
19
|
-
export type
|
|
10
|
+
export type MiddlewareMaker = TagClassAny & { Default: Layer.Layer.Any } // todo; and Layer..
|
|
20
11
|
|
|
21
|
-
export namespace
|
|
12
|
+
export namespace MiddlewareMaker {
|
|
22
13
|
export type ApplyServices<A extends TagClassAny, R> = Exclude<R, Provided<A>> | Required<A>
|
|
14
|
+
|
|
23
15
|
export type ApplyManyServices<A extends NonEmptyReadonlyArray<TagClassAny>, R> =
|
|
24
16
|
| Exclude<R, { [K in keyof A]: Provided<A[K]> }[number]>
|
|
25
17
|
| { [K in keyof A]: Required<A[K]> }[number]
|
|
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
|
+
|
|
26
29
|
export type Provided<T> = T extends TagClassAny
|
|
27
30
|
? T extends { provides: Context.Tag<any, any> } ? Context.Tag.Identifier<T["provides"]>
|
|
28
|
-
: T extends { provides:
|
|
31
|
+
: T extends { provides: ContextTagArray } ? ContextTagArray.Identifier<T["provides"]>
|
|
32
|
+
: never
|
|
33
|
+
: never
|
|
34
|
+
|
|
35
|
+
export type Errors<T> = T extends TagClassAny ? T extends { failure: S.Schema.Any } ? S.Schema.Type<T["failure"]>
|
|
29
36
|
: never
|
|
30
37
|
: never
|
|
31
38
|
|
|
32
39
|
export type Required<T> = T extends TagClassAny
|
|
33
40
|
? T extends { requires: Context.Tag<any, any> } ? Context.Tag.Identifier<T["requires"]>
|
|
34
|
-
: T extends { requires:
|
|
41
|
+
: T extends { requires: ContextTagArray } ? ContextTagArray.Identifier<T["requires"]>
|
|
35
42
|
: never
|
|
36
43
|
: never
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
export const
|
|
40
|
-
|
|
41
|
-
>(
|
|
42
|
-
dependencies: { [K in keyof
|
|
43
|
-
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
|
+
>
|
|
44
61
|
} => {
|
|
45
|
-
// we want to run them in reverse order
|
|
62
|
+
// we want to run them in reverse order because latter middlewares will provide context to former ones
|
|
46
63
|
middlewares = middlewares.toReversed() as any
|
|
64
|
+
|
|
47
65
|
return {
|
|
48
66
|
dependencies: middlewares.map((_) => _.Default),
|
|
49
67
|
effect: Effect.gen(function*() {
|
|
50
68
|
const context = yield* Effect.context()
|
|
51
|
-
|
|
52
|
-
|
|
69
|
+
|
|
70
|
+
// returns a Effect/RpcMiddlewareWrap with Scope in requirements
|
|
71
|
+
return (
|
|
72
|
+
options: Parameters<
|
|
73
|
+
RpcMiddlewareWrap<
|
|
74
|
+
MiddlewareMaker.ManyProvided<MiddlewareProviders>,
|
|
75
|
+
never,
|
|
76
|
+
Scope.Scope
|
|
77
|
+
>
|
|
78
|
+
>[0]
|
|
53
79
|
) => {
|
|
80
|
+
// we start with the actual handler
|
|
54
81
|
let handler = options.next
|
|
55
|
-
|
|
82
|
+
|
|
83
|
+
// inspired from Effect/RpcMiddleware
|
|
56
84
|
for (const tag of middlewares) {
|
|
57
85
|
if (tag.wrap) {
|
|
86
|
+
// use the tag to get the middleware from context
|
|
58
87
|
const middleware = Context.unsafeGet(context, tag)
|
|
88
|
+
|
|
89
|
+
// wrap the current handler, allowing the middleware to run before and after it
|
|
59
90
|
handler = InfraLogger.logDebug("Applying middleware wrap " + tag.key).pipe(
|
|
60
91
|
Effect.zipRight(middleware({ ...options, next: handler }))
|
|
61
92
|
) as any
|
|
62
93
|
} else if (tag.optional) {
|
|
94
|
+
// use the tag to get the middleware from context
|
|
95
|
+
// if the middleware fails to run, we will ignore the error
|
|
63
96
|
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
97
|
+
|
|
64
98
|
const previous = handler
|
|
99
|
+
|
|
100
|
+
// set the previous handler to run after the middleware
|
|
101
|
+
// if the middleware is not present, we just return the previous handler
|
|
102
|
+
// otherwise the middleware will provide some context to be provided to the previous handler
|
|
65
103
|
handler = InfraLogger.logDebug("Applying middleware optional " + tag.key).pipe(
|
|
66
104
|
Effect.zipRight(Effect.matchEffect(middleware(options), {
|
|
67
105
|
onFailure: () => previous,
|
|
@@ -74,24 +112,35 @@ export const genericMiddlewareMaker = <
|
|
|
74
112
|
}))
|
|
75
113
|
)
|
|
76
114
|
} else if (tag.dynamic) {
|
|
115
|
+
// use the tag to get the middleware from context
|
|
77
116
|
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
117
|
+
|
|
78
118
|
const previous = handler
|
|
119
|
+
|
|
120
|
+
// set the previous handler to run after the middleware
|
|
121
|
+
// we do expect the middleware to be present, but the context might not be available
|
|
122
|
+
// if it is, we provide it to the previous handler
|
|
79
123
|
handler = InfraLogger.logDebug("Applying middleware dynamic " + tag.key, tag.dynamic).pipe(
|
|
80
124
|
Effect.zipRight(
|
|
81
125
|
middleware(options).pipe(
|
|
82
|
-
Effect.flatMap((
|
|
83
|
-
Option.isSome(
|
|
84
|
-
? Context.isContext(
|
|
85
|
-
? Effect.provide(previous,
|
|
86
|
-
: Effect.provideService(previous, tag.dynamic!.settings.service!, /* TODO */
|
|
126
|
+
Effect.flatMap((o) =>
|
|
127
|
+
Option.isSome(o)
|
|
128
|
+
? Context.isContext(o.value)
|
|
129
|
+
? Effect.provide(previous, o.value)
|
|
130
|
+
: Effect.provideService(previous, tag.dynamic!.settings.service!, /* TODO */ o.value)
|
|
87
131
|
: previous
|
|
88
132
|
)
|
|
89
133
|
)
|
|
90
134
|
)
|
|
91
|
-
)
|
|
135
|
+
) as any
|
|
92
136
|
} else {
|
|
137
|
+
// use the tag to get the middleware from context
|
|
93
138
|
const middleware = Context.unsafeGet(context, tag) as RpcMiddleware.RpcMiddleware<any, any>
|
|
139
|
+
|
|
94
140
|
const previous = handler
|
|
141
|
+
|
|
142
|
+
// set the previous handler to run after the middleware
|
|
143
|
+
// we do expect both the middleware and the context to be present
|
|
95
144
|
handler = InfraLogger.logDebug("Applying middleware " + tag.key).pipe(
|
|
96
145
|
Effect.zipRight(
|
|
97
146
|
tag.provides !== undefined
|
|
@@ -104,7 +153,7 @@ export const genericMiddlewareMaker = <
|
|
|
104
153
|
)
|
|
105
154
|
: Effect.zipRight(middleware(options), previous)
|
|
106
155
|
)
|
|
107
|
-
)
|
|
156
|
+
) as any
|
|
108
157
|
}
|
|
109
158
|
}
|
|
110
159
|
return handler
|