@effect-app/infra 2.85.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 +17 -0
- package/dist/api/layerUtils.d.ts +4 -8
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +3 -11
- package/dist/api/routing/middleware/ContextProvider.d.ts +2 -2
- package/dist/api/routing/middleware/ContextProvider.d.ts.map +1 -1
- 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 +3 -13
- 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 +15 -22
- 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 +55 -8
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +50 -14
- package/dist/api/routing/middleware/middleware.d.ts +8 -7
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +6 -5
- 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/dist/api/routing.d.ts +0 -1
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +2 -3
- package/package.json +9 -5
- package/src/api/layerUtils.ts +7 -21
- package/src/api/routing/middleware/ContextProvider.ts +5 -5
- 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 +9 -54
- package/src/api/routing/middleware/generic-middleware.ts +33 -33
- package/src/api/routing/middleware/middleware-api.ts +202 -32
- package/src/api/routing/middleware/middleware.ts +13 -5
- package/src/api/routing/middleware.ts +2 -1
- package/src/api/routing/tsort.ts +2 -2
- package/src/api/routing.ts +1 -9
- package/test/contextProvider.test.ts +1 -2
- package/test/controller.test.ts +35 -155
- 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 +146 -0
- package/test/dist/fixtures.d.ts.map +1 -0
- package/test/dist/fixtures.js +82 -0
- package/test/dist/layerUtils.test.d.ts.map +1 -0
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/requires.d.ts +21 -0
- package/test/dist/requires.d.ts.map +1 -0
- package/test/dist/requires.js +27 -0
- package/test/dist/requires.test.d.ts.map +1 -0
- package/test/fixtures.ts +102 -0
- package/test/layerUtils.test.ts +19 -0
- package/test/query.test.ts +2 -4
- package/test/requires.test.ts +156 -0
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +0 -215
- 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 -693
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.87.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.52.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@azure/cosmos": "^4.5.0",
|
|
@@ -306,9 +306,13 @@
|
|
|
306
306
|
"types": "./dist/api/routing/middleware/ContextProvider.d.ts",
|
|
307
307
|
"default": "./dist/api/routing/middleware/ContextProvider.js"
|
|
308
308
|
},
|
|
309
|
-
"./api/routing/middleware/
|
|
310
|
-
"types": "./dist/api/routing/middleware/
|
|
311
|
-
"default": "./dist/api/routing/middleware/
|
|
309
|
+
"./api/routing/middleware/RouterMiddleware": {
|
|
310
|
+
"types": "./dist/api/routing/middleware/RouterMiddleware.d.ts",
|
|
311
|
+
"default": "./dist/api/routing/middleware/RouterMiddleware.js"
|
|
312
|
+
},
|
|
313
|
+
"./api/routing/middleware/RpcMiddleware": {
|
|
314
|
+
"types": "./dist/api/routing/middleware/RpcMiddleware.d.ts",
|
|
315
|
+
"default": "./dist/api/routing/middleware/RpcMiddleware.js"
|
|
312
316
|
},
|
|
313
317
|
"./api/routing/middleware/dynamic-middleware": {
|
|
314
318
|
"types": "./dist/api/routing/middleware/dynamic-middleware.d.ts",
|
package/src/api/layerUtils.ts
CHANGED
|
@@ -7,19 +7,19 @@ export namespace LayerUtils {
|
|
|
7
7
|
NonEmptyReadonlyArray<Layer.Layer.Any> ? {
|
|
8
8
|
[k in keyof Layers]: Layer.Layer.Success<Layers[k]>
|
|
9
9
|
}[number]
|
|
10
|
-
:
|
|
10
|
+
: Layer.Layer.Success<Layers[number]>
|
|
11
11
|
|
|
12
12
|
export type GetLayersContext<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
|
|
13
13
|
NonEmptyReadonlyArray<Layer.Layer.Any> ? {
|
|
14
14
|
[k in keyof Layers]: Layer.Layer.Context<Layers[k]>
|
|
15
15
|
}[number]
|
|
16
|
-
:
|
|
16
|
+
: Layer.Layer.Context<Layers[number]>
|
|
17
17
|
|
|
18
18
|
export type GetLayersError<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
|
|
19
19
|
NonEmptyReadonlyArray<Layer.Layer.Any> ? {
|
|
20
20
|
[k in keyof Layers]: Layer.Layer.Error<Layers[k]>
|
|
21
21
|
}[number]
|
|
22
|
-
:
|
|
22
|
+
: Layer.Layer.Error<Layers[number]>
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export type ContextTagWithDefault<Id, A, LayerE, LayerR> =
|
|
@@ -35,25 +35,11 @@ export namespace ContextTagWithDefault {
|
|
|
35
35
|
export type GetContext<T> = T extends Context.Context<infer Y> ? Y : never
|
|
36
36
|
|
|
37
37
|
export const mergeContexts = Effect.fnUntraced(
|
|
38
|
-
function*<T extends readonly { maker: any; handle: Effect<Context<any
|
|
38
|
+
function*<T extends readonly { maker: any; handle: Effect<Context<any> | Option<Context<any>>> }[]>(makers: T) {
|
|
39
39
|
let context = Context.empty()
|
|
40
40
|
for (const mw of makers) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
"Built dynamic context for middleware" + (mw.maker.key ?? mw.maker),
|
|
44
|
-
(moreContext as any).toJSON().services
|
|
45
|
-
)
|
|
46
|
-
context = Context.merge(context, moreContext)
|
|
47
|
-
}
|
|
48
|
-
return context as Context.Context<Effect.Success<T[number]["handle"]>>
|
|
49
|
-
}
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
export const mergeOptionContexts = Effect.fnUntraced(
|
|
53
|
-
function*<T extends readonly { maker: any; handle: Effect<Option<Context<any>>> }[]>(makers: T) {
|
|
54
|
-
let context = Context.empty()
|
|
55
|
-
for (const mw of makers) {
|
|
56
|
-
const moreContext = yield* mw.handle.pipe(Effect.provide(context))
|
|
41
|
+
const ctx = yield* mw.handle.pipe(Effect.provide(context))
|
|
42
|
+
const moreContext = Context.isContext(ctx) ? Option.some(ctx) : ctx
|
|
57
43
|
yield* InfraLogger.logDebug(
|
|
58
44
|
"Built dynamic context for middleware" + (mw.maker.key ?? mw.maker),
|
|
59
45
|
Option.map(moreContext, (c) => (c as any).toJSON().services)
|
|
@@ -62,6 +48,6 @@ export const mergeOptionContexts = Effect.fnUntraced(
|
|
|
62
48
|
context = Context.merge(context, moreContext.value)
|
|
63
49
|
}
|
|
64
50
|
}
|
|
65
|
-
return context
|
|
51
|
+
return context as Context.Context<Effect.Success<T[number]["handle"]>>
|
|
66
52
|
}
|
|
67
53
|
)
|
|
@@ -87,9 +87,9 @@ export const mergeContextProviders = <
|
|
|
87
87
|
effect: Effect.Effect<
|
|
88
88
|
Effect.Effect<
|
|
89
89
|
// we need to merge all contexts into one
|
|
90
|
-
Context.Context<GetContext<EffectGenUtils.Success<Tag.
|
|
90
|
+
Context.Context<GetContext<EffectGenUtils.Success<Tag.Identifier<TDeps[number]>>>>,
|
|
91
91
|
never,
|
|
92
|
-
EffectGenUtils.Context<Tag.
|
|
92
|
+
EffectGenUtils.Context<Tag.Identifier<TDeps[number]>>
|
|
93
93
|
>,
|
|
94
94
|
LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
|
|
95
95
|
LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
@@ -174,13 +174,13 @@ export const MergedContextProvider = <
|
|
|
174
174
|
ContextProviderId,
|
|
175
175
|
Effect.Effect<
|
|
176
176
|
// we need to merge all contexts into one
|
|
177
|
-
Context.Context<GetContext<EffectGenUtils.Success<Tag.
|
|
177
|
+
Context.Context<GetContext<EffectGenUtils.Success<Tag.Identifier<TDeps[number]>>>>,
|
|
178
178
|
never,
|
|
179
|
-
EffectGenUtils.Context<Tag.
|
|
179
|
+
EffectGenUtils.Context<Tag.Identifier<TDeps[number]>>
|
|
180
180
|
>,
|
|
181
181
|
LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
|
|
182
182
|
| Exclude<
|
|
183
|
-
Tag.
|
|
183
|
+
Tag.Identifier<TDeps[number]>,
|
|
184
184
|
LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
185
185
|
>
|
|
186
186
|
| LayerUtils.GetLayersContext<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
@@ -0,0 +1,149 @@
|
|
|
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 Effect, type Request, type S, type Scope } from "effect-app"
|
|
5
|
+
import type { GetEffectContext, RPCContextMap } from "effect-app/client/req"
|
|
6
|
+
import type * as EffectRequest from "effect/Request"
|
|
7
|
+
import { type ContextTagWithDefault } from "../../layerUtils.js"
|
|
8
|
+
import { type ContextWithLayer } from "./dynamic-middleware.js"
|
|
9
|
+
|
|
10
|
+
// module:
|
|
11
|
+
//
|
|
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
|
+
|
|
93
|
+
export type RouterMiddleware<
|
|
94
|
+
RequestContextMap extends Record<string, RPCContextMap.Any>, // what services will the middlware provide dynamically to the next, or raise errors.
|
|
95
|
+
MakeMiddlewareE, // what the middleware construction can fail with
|
|
96
|
+
MakeMiddlewareR, // what the middlware requires to be constructed
|
|
97
|
+
ContextProviderA // what the context provider provides
|
|
98
|
+
> = ContextTagWithDefault<
|
|
99
|
+
MiddlewareMakerId,
|
|
100
|
+
{
|
|
101
|
+
_tag: "MiddlewareMaker"
|
|
102
|
+
effect: RPCHandlerFactory<RequestContextMap, ContextProviderA>
|
|
103
|
+
},
|
|
104
|
+
MakeMiddlewareE,
|
|
105
|
+
MakeMiddlewareR
|
|
106
|
+
>
|
|
107
|
+
|
|
108
|
+
export type RequestContextMapErrors<RequestContextMap extends Record<string, RPCContextMap.Any>> = S.Schema.Type<
|
|
109
|
+
RequestContextMap[keyof RequestContextMap]["error"]
|
|
110
|
+
>
|
|
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
|
+
}
|
|
@@ -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,
|
|
@@ -20,13 +17,15 @@ export type ContextWithLayer<
|
|
|
20
17
|
& (
|
|
21
18
|
| ContextTagWithDefault<
|
|
22
19
|
Id,
|
|
23
|
-
|
|
20
|
+
// todo
|
|
21
|
+
RpcMiddlewareDynamic<Service, Error, any, Config>,
|
|
24
22
|
LayerE,
|
|
25
23
|
LayerR
|
|
26
24
|
>
|
|
27
25
|
| ContextTagWithDefault<
|
|
28
26
|
Id,
|
|
29
|
-
|
|
27
|
+
// todo
|
|
28
|
+
RpcMiddlewareDynamic<Service, Error, never, Config>,
|
|
30
29
|
LayerE,
|
|
31
30
|
LayerR
|
|
32
31
|
>
|
|
@@ -46,47 +45,3 @@ export namespace ContextWithLayer {
|
|
|
46
45
|
any
|
|
47
46
|
>
|
|
48
47
|
}
|
|
49
|
-
|
|
50
|
-
// 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.
|
|
51
|
-
export const implementMiddleware = <T extends Record<string, RPCContextMap.Any>>() =>
|
|
52
|
-
<
|
|
53
|
-
TI extends {
|
|
54
|
-
[K in keyof T]: ContextWithLayer.Base<
|
|
55
|
-
{ [K in keyof T]?: T[K]["contextActivation"] },
|
|
56
|
-
T[K]["service"],
|
|
57
|
-
S.Schema.Type<T[K]["error"]>
|
|
58
|
-
>
|
|
59
|
-
}
|
|
60
|
-
>(implementations: TI) => ({
|
|
61
|
-
dependencies: typedValuesOf(implementations).map((_) => _.Default) as {
|
|
62
|
-
[K in keyof TI]: TI[K]["Default"]
|
|
63
|
-
}[keyof TI][],
|
|
64
|
-
effect: Effect.gen(function*() {
|
|
65
|
-
const sorted = sort(typedValuesOf(implementations))
|
|
66
|
-
|
|
67
|
-
const makers = yield* Effect.all(sorted)
|
|
68
|
-
return Effect.fnUntraced(
|
|
69
|
-
function*(options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }) {
|
|
70
|
-
const ctx = yield* mergeOptionContexts(
|
|
71
|
-
Array.map(
|
|
72
|
-
makers,
|
|
73
|
-
(_, i) => ({ maker: sorted[i], handle: (_ as any)(options) as any }) as any
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
|
-
return ctx as Context.Context<
|
|
77
|
-
GetEffectContext<T, typeof options["config"]>
|
|
78
|
-
>
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
}) as unknown as Effect<
|
|
82
|
-
(
|
|
83
|
-
options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }
|
|
84
|
-
) => Effect.Effect<
|
|
85
|
-
Context.Context<GetEffectContext<T, typeof options["config"]>>,
|
|
86
|
-
Effect.Error<ReturnType<Tag.Service<TI[keyof TI]>>>,
|
|
87
|
-
Effect.Context<ReturnType<Tag.Identifier<TI[keyof TI]>>>
|
|
88
|
-
>,
|
|
89
|
-
never,
|
|
90
|
-
Tag.Identifier<{ [K in keyof TI]: TI[K] }[keyof TI]>
|
|
91
|
-
>
|
|
92
|
-
})
|