@effect-app/infra 2.80.0 → 2.81.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 +8 -0
- package/dist/api/internal/auth.d.ts +2 -2
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +5 -5
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +129 -6
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/DynamicMiddleware.js +78 -7
- package/dist/api/routing/middleware/dynamic-middleware.d.ts +8 -9
- package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/dynamic-middleware.js +3 -3
- package/dist/api/routing/middleware/generic-middleware.d.ts +5 -0
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +1 -1
- package/dist/api/routing/middleware/middleware-api.d.ts +17 -0
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -0
- package/dist/api/routing/middleware/middleware-api.js +19 -0
- package/dist/api/routing/middleware/middleware.d.ts +3 -3
- package/dist/api/routing/middleware.d.ts +1 -0
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +2 -1
- package/package.json +5 -1
- package/src/api/internal/auth.ts +4 -5
- package/src/api/routing/middleware/DynamicMiddleware.ts +296 -15
- package/src/api/routing/middleware/dynamic-middleware.ts +12 -23
- package/src/api/routing/middleware/generic-middleware.ts +5 -0
- package/src/api/routing/middleware/middleware-api.ts +44 -0
- package/src/api/routing/middleware.ts +1 -0
- package/test/controller.test.ts +35 -25
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/middleware-api.test.d.ts.map +1 -0
|
@@ -2,21 +2,21 @@ import { Context } from "effect-app";
|
|
|
2
2
|
declare const DevMode_base: Context.ReferenceClass<DevMode, "DevMode", boolean>;
|
|
3
3
|
export declare class DevMode extends DevMode_base {
|
|
4
4
|
}
|
|
5
|
-
declare const RequestCacheMiddleware_base: import("
|
|
5
|
+
declare const RequestCacheMiddleware_base: import("./DynamicMiddleware.js").TagClass<RequestCacheMiddleware, "RequestCacheMiddleware", {
|
|
6
6
|
readonly wrap: true;
|
|
7
7
|
}> & {
|
|
8
8
|
Default: import("effect/Layer").Layer<RequestCacheMiddleware, never, never>;
|
|
9
9
|
};
|
|
10
10
|
export declare class RequestCacheMiddleware extends RequestCacheMiddleware_base {
|
|
11
11
|
}
|
|
12
|
-
declare const ConfigureInterruptibility_base: import("
|
|
12
|
+
declare const ConfigureInterruptibility_base: import("./DynamicMiddleware.js").TagClass<ConfigureInterruptibility, "ConfigureInterruptibility", {
|
|
13
13
|
readonly wrap: true;
|
|
14
14
|
}> & {
|
|
15
15
|
Default: import("effect/Layer").Layer<ConfigureInterruptibility, never, never>;
|
|
16
16
|
};
|
|
17
17
|
export declare class ConfigureInterruptibility extends ConfigureInterruptibility_base {
|
|
18
18
|
}
|
|
19
|
-
declare const MiddlewareLogger_base: import("
|
|
19
|
+
declare const MiddlewareLogger_base: import("./DynamicMiddleware.js").TagClass<MiddlewareLogger, "MiddlewareLogger", {
|
|
20
20
|
readonly wrap: true;
|
|
21
21
|
}> & {
|
|
22
22
|
Default: import("effect/Layer").Layer<MiddlewareLogger, never, never>;
|
|
@@ -2,6 +2,7 @@ export * from "./middleware/ContextProvider.js";
|
|
|
2
2
|
export * from "./middleware/dynamic-middleware.js";
|
|
3
3
|
export * from "./middleware/DynamicMiddleware.js";
|
|
4
4
|
export * from "./middleware/generic-middleware.js";
|
|
5
|
+
export * from "./middleware/middleware-api.js";
|
|
5
6
|
export * from "./middleware/middleware.js";
|
|
6
7
|
export * as Middleware from "./middleware.js";
|
|
7
8
|
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/api/routing/middleware.ts"],"names":[],"mappings":"AACA,cAAc,iCAAiC,CAAA;AAC/C,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,oCAAoC,CAAA;AAClD,cAAc,4BAA4B,CAAA;AAG1C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/api/routing/middleware.ts"],"names":[],"mappings":"AACA,cAAc,iCAAiC,CAAA;AAC/C,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,oCAAoC,CAAA;AAClD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,4BAA4B,CAAA;AAG1C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA"}
|
|
@@ -3,7 +3,8 @@ export * from "./middleware/ContextProvider.js";
|
|
|
3
3
|
export * from "./middleware/dynamic-middleware.js";
|
|
4
4
|
export * from "./middleware/DynamicMiddleware.js";
|
|
5
5
|
export * from "./middleware/generic-middleware.js";
|
|
6
|
+
export * from "./middleware/middleware-api.js";
|
|
6
7
|
export * from "./middleware/middleware.js";
|
|
7
8
|
// codegen:end
|
|
8
9
|
export * as Middleware from "./middleware.js";
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcGkvcm91dGluZy9taWRkbGV3YXJlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDRFQUE0RTtBQUM1RSxjQUFjLGlDQUFpQyxDQUFBO0FBQy9DLGNBQWMsb0NBQW9DLENBQUE7QUFDbEQsY0FBYyxtQ0FBbUMsQ0FBQTtBQUNqRCxjQUFjLG9DQUFvQyxDQUFBO0FBQ2xELGNBQWMsZ0NBQWdDLENBQUE7QUFDOUMsY0FBYyw0QkFBNEIsQ0FBQTtBQUMxQyxjQUFjO0FBRWQsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQkFBaUIsQ0FBQSJ9
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.81.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -322,6 +322,10 @@
|
|
|
322
322
|
"types": "./dist/api/routing/middleware/middleware.d.ts",
|
|
323
323
|
"default": "./dist/api/routing/middleware/middleware.js"
|
|
324
324
|
},
|
|
325
|
+
"./api/routing/middleware/middleware-api": {
|
|
326
|
+
"types": "./dist/api/routing/middleware/middleware-api.d.ts",
|
|
327
|
+
"default": "./dist/api/routing/middleware/middleware-api.js"
|
|
328
|
+
},
|
|
325
329
|
"./api/routing/schema/jwt": {
|
|
326
330
|
"types": "./dist/api/routing/schema/jwt.d.ts",
|
|
327
331
|
"default": "./dist/api/routing/schema/jwt.js"
|
package/src/api/internal/auth.ts
CHANGED
|
@@ -11,9 +11,7 @@ import { auth, InsufficientScopeError, InvalidRequestError, InvalidTokenError, U
|
|
|
11
11
|
type Config = Parameters<typeof auth>[0]
|
|
12
12
|
export const checkJWTI = (config: Config) => {
|
|
13
13
|
const mw = auth(config)
|
|
14
|
-
return Effect.
|
|
15
|
-
const req = yield* HttpServerRequest.HttpServerRequest
|
|
16
|
-
|
|
14
|
+
return Effect.fnUntraced(function*(headers: HttpHeaders.Headers) {
|
|
17
15
|
return yield* Effect.async<
|
|
18
16
|
void,
|
|
19
17
|
InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError
|
|
@@ -31,7 +29,7 @@ export const checkJWTI = (config: Config) => {
|
|
|
31
29
|
}
|
|
32
30
|
return cb(Effect.die(err))
|
|
33
31
|
}
|
|
34
|
-
const r = { headers
|
|
32
|
+
const r = { headers, query: {}, body: {}, is: () => false } // is("urlencoded")
|
|
35
33
|
try {
|
|
36
34
|
mw(r as any, {} as any, next)
|
|
37
35
|
} catch (e) {
|
|
@@ -46,7 +44,8 @@ export const checkJwt = (config: Config) => {
|
|
|
46
44
|
const check = checkJWTI(config)
|
|
47
45
|
return HttpMiddleware.make((app) =>
|
|
48
46
|
Effect.gen(function*() {
|
|
49
|
-
const
|
|
47
|
+
const req = yield* HttpServerRequest.HttpServerRequest
|
|
48
|
+
const response = yield* check(req.headers).pipe(Effect.catchAll((e) =>
|
|
50
49
|
Effect.succeed(
|
|
51
50
|
HttpServerResponse.unsafeJson({ message: e.message }, {
|
|
52
51
|
status: e.status,
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
4
|
import { Rpc, RpcMiddleware } from "@effect/rpc"
|
|
5
|
-
import { type SuccessValue, type
|
|
6
|
-
import { Console, Context, Effect, Layer, type NonEmptyReadonlyArray, type Request, type S, type Schema, type Scope, Unify } from "effect-app"
|
|
5
|
+
import { type SuccessValue, type TypeId } from "@effect/rpc/RpcMiddleware"
|
|
6
|
+
import { Console, Context, Effect, Layer, type NonEmptyReadonlyArray, type Option, type Request, type S, type Schema, type Scope, Unify } from "effect-app"
|
|
7
7
|
import type { GetEffectContext, 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"
|
|
@@ -83,7 +83,7 @@ export type RPCHandlerFactory<
|
|
|
83
83
|
>
|
|
84
84
|
>
|
|
85
85
|
|
|
86
|
-
type RequestContextMapProvider<RequestContextMap extends Record<string, RPCContextMap.Any>> = {
|
|
86
|
+
export type RequestContextMapProvider<RequestContextMap extends Record<string, RPCContextMap.Any>> = {
|
|
87
87
|
[K in keyof RequestContextMap]: ContextWithLayer.Base<
|
|
88
88
|
{ [K in keyof RequestContextMap]?: RequestContextMap[K]["contextActivation"] },
|
|
89
89
|
RequestContextMap[K]["service"],
|
|
@@ -155,6 +155,13 @@ export type RequestContextMapErrors<RequestContextMap extends Record<string, RPC
|
|
|
155
155
|
RequestContextMap[keyof RequestContextMap]["error"]
|
|
156
156
|
>
|
|
157
157
|
|
|
158
|
+
/*:
|
|
159
|
+
& Context.Tag<MiddlewareMakerId, {
|
|
160
|
+
effect: RPCHandlerFactory<RequestContextMap, GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>>
|
|
161
|
+
_tag: "MiddlewareMaker"
|
|
162
|
+
}>
|
|
163
|
+
& { Default: "abc" } */
|
|
164
|
+
|
|
158
165
|
// factory for middlewares
|
|
159
166
|
export const makeMiddleware =
|
|
160
167
|
// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
|
|
@@ -193,6 +200,131 @@ export const makeMiddleware =
|
|
|
193
200
|
const dynamicMiddlewares = implementMiddleware<RequestContextMap>()(make.dynamicMiddlewares)
|
|
194
201
|
const middlewares = genericMiddlewareMaker(...make.genericMiddlewares)
|
|
195
202
|
|
|
203
|
+
const l = Layer.scoped(
|
|
204
|
+
MiddlewareMaker,
|
|
205
|
+
Effect
|
|
206
|
+
.all({
|
|
207
|
+
dynamicMiddlewares: dynamicMiddlewares.effect,
|
|
208
|
+
generic: middlewares.effect,
|
|
209
|
+
middleware: make.execute
|
|
210
|
+
? make.execute((
|
|
211
|
+
cb: MakeRPCHandlerFactory<
|
|
212
|
+
RequestContextMap,
|
|
213
|
+
Scope.Scope | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
214
|
+
>
|
|
215
|
+
) => cb)
|
|
216
|
+
: Effect.succeed<
|
|
217
|
+
MakeRPCHandlerFactory<
|
|
218
|
+
RequestContextMap,
|
|
219
|
+
Scope.Scope | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
220
|
+
>
|
|
221
|
+
>((_schema, next) => (payload, headers) => next(payload, headers))
|
|
222
|
+
})
|
|
223
|
+
.pipe(
|
|
224
|
+
Effect.map(({ dynamicMiddlewares, generic, middleware }) => ({
|
|
225
|
+
_tag: "MiddlewareMaker" as const,
|
|
226
|
+
effect: makeRpcEffect<
|
|
227
|
+
RequestContextMap,
|
|
228
|
+
GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
229
|
+
>()(
|
|
230
|
+
(schema, next, moduleName) => {
|
|
231
|
+
const h = middleware(schema, next as any, moduleName)
|
|
232
|
+
return (payload, headers) => {
|
|
233
|
+
const basic = {
|
|
234
|
+
config: schema.config ?? {},
|
|
235
|
+
payload,
|
|
236
|
+
headers,
|
|
237
|
+
clientId: 0, // TODO: get the clientId from the request context
|
|
238
|
+
rpc: {
|
|
239
|
+
...Rpc.fromTaggedRequest(schema as any),
|
|
240
|
+
// middlewares ? // todo: get from actual middleware flow?
|
|
241
|
+
annotations: Context.empty(), // TODO //Annotations(schema as any),
|
|
242
|
+
// successSchema: schema.success ?? Schema.Void,
|
|
243
|
+
// errorSchema: schema.failure ?? Schema.Never,
|
|
244
|
+
payloadSchema: schema,
|
|
245
|
+
_tag: `${moduleName}.${payload._tag}`,
|
|
246
|
+
key: `${moduleName}.${payload._tag}` /* ? */
|
|
247
|
+
// clientId: 0 as number /* ? */
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return Effect
|
|
251
|
+
.gen(function*() {
|
|
252
|
+
const gen = generic({
|
|
253
|
+
...basic,
|
|
254
|
+
next:
|
|
255
|
+
// the contextProvider is an Effect that builds the context for the request
|
|
256
|
+
// the dynamicMiddlewares is an Effect that builds the dynamiuc context for the request
|
|
257
|
+
dynamicMiddlewares(basic).pipe(
|
|
258
|
+
Effect.flatMap((dynamicContext) => h(payload, headers).pipe(Effect.provide(dynamicContext)))
|
|
259
|
+
) as any
|
|
260
|
+
})
|
|
261
|
+
console.log({ gen })
|
|
262
|
+
|
|
263
|
+
return yield* gen
|
|
264
|
+
})
|
|
265
|
+
.pipe(Effect.onExit(Console.log)) as any // why?
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
})),
|
|
270
|
+
Effect.onExit(Console.log)
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
const dependencies = [
|
|
275
|
+
...(make.dependencies ? make.dependencies : []),
|
|
276
|
+
...(dynamicMiddlewares.dependencies as any),
|
|
277
|
+
...middlewares.dependencies
|
|
278
|
+
]
|
|
279
|
+
const middlewareLayer = l
|
|
280
|
+
.pipe(
|
|
281
|
+
Layer.provide(dependencies as any)
|
|
282
|
+
) as Layer.Layer<
|
|
283
|
+
MiddlewareMakerId,
|
|
284
|
+
| MakeMiddlewareE // what the middleware construction can fail with
|
|
285
|
+
| LayerUtils.GetLayersError<typeof dynamicMiddlewares.dependencies>
|
|
286
|
+
| LayerUtils.GetLayersError<typeof middlewares.dependencies>, // what could go wrong when building the dynamic middleware provider
|
|
287
|
+
| LayerUtils.GetLayersContext<MiddlewareDependencies> // what's needed to build layers
|
|
288
|
+
| LayerUtils.GetLayersContext<typeof middlewares.dependencies>
|
|
289
|
+
| LayerUtils.GetLayersContext<typeof dynamicMiddlewares.dependencies> // what's needed to build dynamic middleware layers
|
|
290
|
+
| Exclude<MakeMiddlewareR, LayerUtils.GetLayersSuccess<MiddlewareDependencies>> // what layers provides
|
|
291
|
+
>
|
|
292
|
+
|
|
293
|
+
return Object.assign(MiddlewareMaker, { Default: middlewareLayer })
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export const makeMiddlewareBasic =
|
|
297
|
+
// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
|
|
298
|
+
<
|
|
299
|
+
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
300
|
+
RequestContextProviders extends RequestContextMapProvider<RequestContextMap>, // how to resolve the dynamic middleware
|
|
301
|
+
GenericMiddlewareProviders extends NonEmptyReadonlyArray<GenericMiddlewareMaker>
|
|
302
|
+
>(
|
|
303
|
+
make: MiddlewareMake<
|
|
304
|
+
RequestContextMap,
|
|
305
|
+
RequestContextProviders,
|
|
306
|
+
GenericMiddlewareProviders,
|
|
307
|
+
never,
|
|
308
|
+
never,
|
|
309
|
+
never
|
|
310
|
+
>
|
|
311
|
+
) => {
|
|
312
|
+
const MiddlewareMaker = Context.GenericTag<
|
|
313
|
+
MiddlewareMakerId,
|
|
314
|
+
{
|
|
315
|
+
effect: RPCHandlerFactory<
|
|
316
|
+
RequestContextMap,
|
|
317
|
+
GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
318
|
+
>
|
|
319
|
+
_tag: "MiddlewareMaker"
|
|
320
|
+
}
|
|
321
|
+
>(
|
|
322
|
+
"MiddlewareMaker"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
const dynamicMiddlewares = implementMiddleware<RequestContextMap>()(make.dynamicMiddlewares)
|
|
326
|
+
const middlewares = genericMiddlewareMaker(...make.genericMiddlewares)
|
|
327
|
+
|
|
196
328
|
const l = Layer.scoped(
|
|
197
329
|
MiddlewareMaker,
|
|
198
330
|
Effect
|
|
@@ -225,7 +357,8 @@ export const makeMiddleware =
|
|
|
225
357
|
return (payload, headers) =>
|
|
226
358
|
Effect
|
|
227
359
|
.gen(function*() {
|
|
228
|
-
const
|
|
360
|
+
const basic = {
|
|
361
|
+
config: schema.config ?? {},
|
|
229
362
|
payload,
|
|
230
363
|
headers,
|
|
231
364
|
clientId: 0, // TODO: get the clientId from the request context
|
|
@@ -239,17 +372,17 @@ export const makeMiddleware =
|
|
|
239
372
|
_tag: `${moduleName}.${payload._tag}`,
|
|
240
373
|
key: `${moduleName}.${payload._tag}` /* ? */
|
|
241
374
|
// clientId: 0 as number /* ? */
|
|
242
|
-
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return yield* generic({
|
|
378
|
+
...basic,
|
|
243
379
|
next:
|
|
244
380
|
// the contextProvider is an Effect that builds the context for the request
|
|
245
381
|
// the dynamicMiddlewares is an Effect that builds the dynamiuc context for the request
|
|
246
|
-
dynamicMiddlewares(
|
|
382
|
+
dynamicMiddlewares(basic).pipe(
|
|
247
383
|
Effect.flatMap((dynamicContext) => h(payload, headers).pipe(Effect.provide(dynamicContext)))
|
|
248
384
|
) as any
|
|
249
385
|
})
|
|
250
|
-
console.log({ gen })
|
|
251
|
-
|
|
252
|
-
return yield* gen
|
|
253
386
|
})
|
|
254
387
|
.pipe(Effect.onExit(Console.log)) as any // why?
|
|
255
388
|
}
|
|
@@ -261,7 +394,7 @@ export const makeMiddleware =
|
|
|
261
394
|
|
|
262
395
|
const dependencies = [
|
|
263
396
|
...(make.dependencies ? make.dependencies : []),
|
|
264
|
-
...(dynamicMiddlewares.dependencies
|
|
397
|
+
...(dynamicMiddlewares.dependencies),
|
|
265
398
|
...middlewares.dependencies
|
|
266
399
|
]
|
|
267
400
|
const middlewareLayer = l
|
|
@@ -269,13 +402,10 @@ export const makeMiddleware =
|
|
|
269
402
|
Layer.provide(dependencies as any)
|
|
270
403
|
) as Layer.Layer<
|
|
271
404
|
MiddlewareMakerId,
|
|
272
|
-
| MakeMiddlewareE // what the middleware construction can fail with
|
|
273
405
|
| LayerUtils.GetLayersError<typeof dynamicMiddlewares.dependencies>
|
|
274
406
|
| LayerUtils.GetLayersError<typeof middlewares.dependencies>, // what could go wrong when building the dynamic middleware provider
|
|
275
|
-
| LayerUtils.GetLayersContext<MiddlewareDependencies> // what's needed to build layers
|
|
276
407
|
| LayerUtils.GetLayersContext<typeof middlewares.dependencies>
|
|
277
408
|
| LayerUtils.GetLayersContext<typeof dynamicMiddlewares.dependencies> // what's needed to build dynamic middleware layers
|
|
278
|
-
| Exclude<MakeMiddlewareR, LayerUtils.GetLayersSuccess<MiddlewareDependencies>> // what layers provides
|
|
279
409
|
>
|
|
280
410
|
|
|
281
411
|
return Object.assign(MiddlewareMaker, { Default: middlewareLayer })
|
|
@@ -347,10 +477,154 @@ type RpcOptionsOriginal = {
|
|
|
347
477
|
readonly requiredForClient?: boolean
|
|
348
478
|
}
|
|
349
479
|
|
|
480
|
+
type RpcDynamic<Key extends string, A extends RPCContextMap.Any> = {
|
|
481
|
+
key: Key
|
|
482
|
+
settings: A
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
type RpcOptionsDynamic<Key extends string, A extends RPCContextMap.Any> = RpcOptionsOriginal & {
|
|
486
|
+
readonly dynamic: RpcDynamic<Key, A>
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export type Dynamic<Options> = Options extends RpcOptionsDynamic<any, any> ? true : false
|
|
490
|
+
|
|
491
|
+
export interface RpcMiddlewareDynamic<A, E, Config> {
|
|
492
|
+
(options: {
|
|
493
|
+
readonly config: Config // todo
|
|
494
|
+
readonly clientId: number
|
|
495
|
+
readonly rpc: Rpc.AnyWithProps
|
|
496
|
+
readonly payload: unknown
|
|
497
|
+
readonly headers: HttpHeaders.Headers
|
|
498
|
+
}): Effect.Effect<Option.Option<Context.Context<A>>, E, Scope.Scope>
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export interface TagClassDynamicAny<RequestContext extends Record<string, RPCContextMap.Any>>
|
|
502
|
+
extends Context.Tag<any, any>
|
|
503
|
+
{
|
|
504
|
+
readonly [RpcMiddleware.TypeId]: RpcMiddleware.TypeId
|
|
505
|
+
readonly optional: boolean
|
|
506
|
+
readonly provides?: Context.Tag<any, any> | undefined
|
|
507
|
+
readonly failure: Schema.Schema.All
|
|
508
|
+
readonly requiredForClient: boolean
|
|
509
|
+
readonly dynamic: RpcDynamic<any, RequestContext[keyof RequestContext]>
|
|
510
|
+
readonly wrap: boolean
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export declare namespace TagClass {
|
|
514
|
+
/**
|
|
515
|
+
* @since 1.0.0
|
|
516
|
+
* @category models
|
|
517
|
+
*/
|
|
518
|
+
export type Provides<Options> = Options extends {
|
|
519
|
+
readonly provides: Context.Tag<any, any>
|
|
520
|
+
readonly optional?: false
|
|
521
|
+
} ? Context.Tag.Identifier<Options["provides"]>
|
|
522
|
+
: never
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* @since 1.0.0
|
|
526
|
+
* @category models
|
|
527
|
+
*/
|
|
528
|
+
export type Service<Options> = Options extends { readonly provides: Context.Tag<any, any> }
|
|
529
|
+
? Context.Tag.Service<Options["provides"]>
|
|
530
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["service"]
|
|
531
|
+
: void
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* @since 1.0.0
|
|
535
|
+
* @category models
|
|
536
|
+
*/
|
|
537
|
+
export type FailureSchema<Options> = Options extends
|
|
538
|
+
{ readonly failure: Schema.Schema.All; readonly optional?: false } ? Options["failure"]
|
|
539
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["error"]
|
|
540
|
+
: typeof Schema.Never
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* @since 1.0.0
|
|
544
|
+
* @category models
|
|
545
|
+
*/
|
|
546
|
+
export type Failure<Options> = Options extends
|
|
547
|
+
{ readonly failure: Schema.Schema<infer _A, infer _I, infer _R>; readonly optional?: false } ? _A
|
|
548
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? S.Schema.Type<A["error"]>
|
|
549
|
+
: never
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* @since 1.0.0
|
|
553
|
+
* @category models
|
|
554
|
+
*/
|
|
555
|
+
export type FailureContext<Options> = Schema.Schema.Context<FailureSchema<Options>>
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* @since 1.0.0
|
|
559
|
+
* @category models
|
|
560
|
+
*/
|
|
561
|
+
export type FailureService<Options> = Optional<Options> extends true ? unknown : Failure<Options>
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* @since 1.0.0
|
|
565
|
+
* @category models
|
|
566
|
+
*/
|
|
567
|
+
export type Optional<Options> = Options extends { readonly optional: true } ? true : false
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* @since 1.0.0
|
|
571
|
+
* @category models
|
|
572
|
+
*/
|
|
573
|
+
export type RequiredForClient<Options> = Options extends { readonly requiredForClient: true } ? true : false
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @since 1.0.0
|
|
577
|
+
* @category models
|
|
578
|
+
*/
|
|
579
|
+
export type Wrap<Options> = Options extends { readonly wrap: true } ? true : false
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* @since 1.0.0
|
|
583
|
+
* @category models
|
|
584
|
+
*/
|
|
585
|
+
export interface Base<Self, Name extends string, Options, Service> extends Context.Tag<Self, Service> {
|
|
586
|
+
new(_: never): Context.TagClassShape<Name, Service>
|
|
587
|
+
readonly [TypeId]: TypeId
|
|
588
|
+
readonly optional: Optional<Options>
|
|
589
|
+
readonly failure: FailureSchema<Options>
|
|
590
|
+
readonly provides: Options extends { readonly provides: Context.Tag<any, any> } ? Options["provides"]
|
|
591
|
+
: undefined
|
|
592
|
+
readonly dynamic: Options extends RpcOptionsDynamic<any, any> ? Options["dynamic"]
|
|
593
|
+
: undefined
|
|
594
|
+
readonly requiredForClient: RequiredForClient<Options>
|
|
595
|
+
readonly wrap: Wrap<Options>
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
export interface TagClass<
|
|
600
|
+
Self,
|
|
601
|
+
Name extends string,
|
|
602
|
+
Options
|
|
603
|
+
> extends
|
|
604
|
+
TagClass.Base<
|
|
605
|
+
Self,
|
|
606
|
+
Name,
|
|
607
|
+
Options,
|
|
608
|
+
TagClass.Wrap<Options> extends true ? RpcMiddlewareWrap<
|
|
609
|
+
TagClass.Provides<Options>,
|
|
610
|
+
TagClass.Failure<Options>
|
|
611
|
+
>
|
|
612
|
+
: Options extends RpcOptionsDynamic<any, any> ? RpcMiddlewareDynamic<
|
|
613
|
+
TagClass.Service<Options>,
|
|
614
|
+
TagClass.FailureService<Options>,
|
|
615
|
+
{ [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
|
|
616
|
+
>
|
|
617
|
+
: RpcMiddleware<
|
|
618
|
+
TagClass.Service<Options>,
|
|
619
|
+
TagClass.FailureService<Options>
|
|
620
|
+
>
|
|
621
|
+
>
|
|
622
|
+
{}
|
|
623
|
+
|
|
350
624
|
export const Tag = <Self>() =>
|
|
351
625
|
<
|
|
352
626
|
const Name extends string,
|
|
353
|
-
const Options extends RpcOptionsOriginal
|
|
627
|
+
const Options extends RpcOptionsOriginal | RpcOptionsDynamic<any, any>
|
|
354
628
|
>(
|
|
355
629
|
id: Name,
|
|
356
630
|
options?: Options | undefined
|
|
@@ -361,6 +635,11 @@ export const Tag = <Self>() =>
|
|
|
361
635
|
TagClass.Provides<Options>,
|
|
362
636
|
TagClass.Failure<Options>
|
|
363
637
|
>
|
|
638
|
+
: Options extends RpcOptionsDynamic<any, any> ? RpcMiddlewareDynamic<
|
|
639
|
+
TagClass.Service<Options>,
|
|
640
|
+
TagClass.FailureService<Options>,
|
|
641
|
+
{ [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
|
|
642
|
+
>
|
|
364
643
|
: RpcMiddleware<
|
|
365
644
|
TagClass.Service<Options>,
|
|
366
645
|
TagClass.FailureService<Options>
|
|
@@ -369,10 +648,12 @@ export const Tag = <Self>() =>
|
|
|
369
648
|
R
|
|
370
649
|
>
|
|
371
650
|
dependencies?: L
|
|
372
|
-
}):
|
|
651
|
+
}): TagClass<Self, Name, Options> & {
|
|
373
652
|
Default: Layer.Layer<Self, E | LayerUtils.GetLayersError<L>, Exclude<R, LayerUtils.GetLayersSuccess<L>>>
|
|
374
653
|
} =>
|
|
375
654
|
class extends RpcMiddleware.Tag<Self>()(id, options) {
|
|
655
|
+
// TODO: move to TagClass.
|
|
656
|
+
static readonly dynamic = options && "dynamic" in options ? options.dynamic : undefined
|
|
376
657
|
static readonly Default = Layer.scoped(this, opts.effect as any).pipe(
|
|
377
658
|
Layer.provide([Layer.empty, ...opts.dependencies ?? []])
|
|
378
659
|
)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { Array, type Context, Effect, type
|
|
2
|
+
import { Array, type Context, Effect, type S } from "effect-app"
|
|
3
3
|
import { type GetEffectContext, type RPCContextMap } from "effect-app/client"
|
|
4
4
|
import { type Tag } from "effect-app/Context"
|
|
5
|
+
import { type HttpHeaders } from "effect-app/http"
|
|
5
6
|
import { typedValuesOf } from "effect-app/utils"
|
|
6
7
|
import { type ContextTagWithDefault, mergeOptionContexts } from "../../layerUtils.js"
|
|
7
8
|
import { sort } from "../tsort.js"
|
|
9
|
+
import { type RpcMiddlewareDynamic } from "./DynamicMiddleware.js"
|
|
8
10
|
|
|
9
11
|
export type ContextWithLayer<
|
|
10
12
|
Config,
|
|
@@ -18,25 +20,13 @@ export type ContextWithLayer<
|
|
|
18
20
|
& (
|
|
19
21
|
| ContextTagWithDefault<
|
|
20
22
|
Id,
|
|
21
|
-
|
|
22
|
-
_tag: any
|
|
23
|
-
handle: (
|
|
24
|
-
config: Config,
|
|
25
|
-
headers: Record<string, string>
|
|
26
|
-
) => Effect<Option<Context<Service>>, Error, any>
|
|
27
|
-
},
|
|
23
|
+
RpcMiddlewareDynamic<Service, Error, Config>,
|
|
28
24
|
LayerE,
|
|
29
25
|
LayerR
|
|
30
26
|
>
|
|
31
27
|
| ContextTagWithDefault<
|
|
32
28
|
Id,
|
|
33
|
-
|
|
34
|
-
_tag: any
|
|
35
|
-
handle: (
|
|
36
|
-
config: Config,
|
|
37
|
-
headers: Record<string, string>
|
|
38
|
-
) => Effect<Option<Context<Service>>, Error, never>
|
|
39
|
-
},
|
|
29
|
+
RpcMiddlewareDynamic<Service, Error, Config>,
|
|
40
30
|
LayerE,
|
|
41
31
|
LayerR
|
|
42
32
|
>
|
|
@@ -76,26 +66,25 @@ export const implementMiddleware = <T extends Record<string, RPCContextMap.Any>>
|
|
|
76
66
|
|
|
77
67
|
const makers = yield* Effect.all(sorted)
|
|
78
68
|
return Effect.fnUntraced(
|
|
79
|
-
function*(config: { [K in keyof T]?: T[K]["contextActivation"] }
|
|
69
|
+
function*(options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }) {
|
|
80
70
|
const ctx = yield* mergeOptionContexts(
|
|
81
71
|
Array.map(
|
|
82
72
|
makers,
|
|
83
|
-
(_, i) => ({ maker: sorted[i], handle: (_ as any)
|
|
73
|
+
(_, i) => ({ maker: sorted[i], handle: (_ as any)(options) as any }) as any
|
|
84
74
|
)
|
|
85
75
|
)
|
|
86
76
|
return ctx as Context.Context<
|
|
87
|
-
GetEffectContext<T, typeof config>
|
|
77
|
+
GetEffectContext<T, typeof options["config"]>
|
|
88
78
|
>
|
|
89
79
|
}
|
|
90
80
|
)
|
|
91
81
|
}) as unknown as Effect<
|
|
92
82
|
(
|
|
93
|
-
config: { [K in keyof T]?: T[K]["contextActivation"] }
|
|
94
|
-
headers: Record<string, string>
|
|
83
|
+
options: { config: { [K in keyof T]?: T[K]["contextActivation"] }; headers: HttpHeaders.Headers }
|
|
95
84
|
) => Effect.Effect<
|
|
96
|
-
Context.Context<GetEffectContext<T, typeof config>>,
|
|
97
|
-
Effect.Error<ReturnType<Tag.Service<TI[keyof TI]
|
|
98
|
-
Effect.Context<ReturnType<Tag.Service<TI[keyof TI]
|
|
85
|
+
Context.Context<GetEffectContext<T, typeof options["config"]>>,
|
|
86
|
+
Effect.Error<ReturnType<Tag.Service<TI[keyof TI]>>>,
|
|
87
|
+
Effect.Context<ReturnType<Tag.Service<TI[keyof TI]>>>
|
|
99
88
|
>,
|
|
100
89
|
never,
|
|
101
90
|
Tag.Identifier<{ [K in keyof TI]: TI[K] }[keyof TI]>
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import { type Rpc, type RpcMiddleware } from "@effect/rpc"
|
|
3
3
|
import { type SuccessValue, type TagClassAny } from "@effect/rpc/RpcMiddleware"
|
|
4
4
|
import { type Array, Context, Effect, type Layer, type Scope } from "effect-app"
|
|
5
|
+
import { type RPCContextMap } from "effect-app/client"
|
|
5
6
|
import { type HttpHeaders } from "effect-app/http"
|
|
6
7
|
import { InfraLogger } from "../../../logger.js"
|
|
8
|
+
import { type TagClassDynamicAny } from "./DynamicMiddleware.js"
|
|
7
9
|
|
|
8
10
|
export interface GenericMiddlewareOptions<E> {
|
|
9
11
|
// Effect rpc middleware does not support changing payload or headers, but we do..
|
|
@@ -15,6 +17,9 @@ export interface GenericMiddlewareOptions<E> {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export type GenericMiddlewareMaker = TagClassAny & { Default: Layer.Layer.Any } // todo; and Layer..
|
|
20
|
+
export type DynamicMiddlewareMaker<RequestContext extends Record<string, RPCContextMap.Any>> =
|
|
21
|
+
& TagClassDynamicAny<RequestContext>
|
|
22
|
+
& { Default: Layer.Layer.Any } // todo; and Layer..
|
|
18
23
|
|
|
19
24
|
export namespace GenericMiddlewareMaker {
|
|
20
25
|
export type Provided<T> = T extends TagClassAny
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type NonEmptyReadonlyArray } from "effect-app"
|
|
2
|
+
import { type RPCContextMap } from "effect-app/client"
|
|
3
|
+
import { type DynamicMiddlewareMaker, type GenericMiddlewareMaker, makeMiddleware, type makeMiddlewareBasic, type RequestContextMapProvider } from "../../routing.js"
|
|
4
|
+
|
|
5
|
+
export const contextMap = <RequestContextMap>() => <K extends keyof RequestContextMap>(a: K) => ({
|
|
6
|
+
key: a,
|
|
7
|
+
settings: null as any as RequestContextMap[typeof a]
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
type DynamicMiddlewareMakerrsss<
|
|
11
|
+
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
12
|
+
Provided extends keyof RequestContext,
|
|
13
|
+
Middlewares extends NonEmptyReadonlyArray<GenericMiddlewareMaker>,
|
|
14
|
+
DynamicMiddlewareProviders extends RequestContextMapProvider<RequestContext>
|
|
15
|
+
> = keyof Omit<RequestContext, Provided> extends never
|
|
16
|
+
? { make: () => ReturnType<typeof makeMiddlewareBasic<RequestContext, DynamicMiddlewareProviders, Middlewares>> }
|
|
17
|
+
: {
|
|
18
|
+
addDynamicMiddleware: <MW extends DynamicMiddlewareMaker<RequestContext>>(
|
|
19
|
+
a: MW
|
|
20
|
+
) => DynamicMiddlewareMakerrsss<
|
|
21
|
+
RequestContext,
|
|
22
|
+
Provided | MW["dynamic"]["key"],
|
|
23
|
+
Middlewares,
|
|
24
|
+
DynamicMiddlewareProviders & { [K in MW["dynamic"]["key"]]: MW }
|
|
25
|
+
> // TODO: any of RequestContecxtMap, and track them, so remove the ones provided
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const makeNewMiddleware: <
|
|
29
|
+
RequestContextMap extends Record<string, RPCContextMap.Any>
|
|
30
|
+
>() => <Middlewares extends NonEmptyReadonlyArray<GenericMiddlewareMaker>>(
|
|
31
|
+
...genericMiddlewares: Middlewares
|
|
32
|
+
) => DynamicMiddlewareMakerrsss<RequestContextMap, never, Middlewares, never> = () => (...genericMiddlewares) => {
|
|
33
|
+
const dynamicMiddlewares: Record<keyof any, any> = {} as any
|
|
34
|
+
const make = makeMiddleware<any>()
|
|
35
|
+
const it = {
|
|
36
|
+
addDynamicMiddleware: (a: any) => {
|
|
37
|
+
console.log("Adding dynamic middleware", a, a.dynamic, Object.keys(a))
|
|
38
|
+
;(dynamicMiddlewares as any)[a.dynamic.key] = a
|
|
39
|
+
return it
|
|
40
|
+
},
|
|
41
|
+
make: () => make({ genericMiddlewares: genericMiddlewares as any, dynamicMiddlewares })
|
|
42
|
+
}
|
|
43
|
+
return it
|
|
44
|
+
}
|
|
@@ -3,6 +3,7 @@ export * from "./middleware/ContextProvider.js"
|
|
|
3
3
|
export * from "./middleware/dynamic-middleware.js"
|
|
4
4
|
export * from "./middleware/DynamicMiddleware.js"
|
|
5
5
|
export * from "./middleware/generic-middleware.js"
|
|
6
|
+
export * from "./middleware/middleware-api.js"
|
|
6
7
|
export * from "./middleware/middleware.js"
|
|
7
8
|
// codegen:end
|
|
8
9
|
|