@effect-app/infra 2.80.0 → 2.81.1
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 +14 -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 +79 -11
- 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 +295 -19
- 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.1",
|
|
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 {
|
|
5
|
+
import { type SuccessValue, type TypeId } from "@effect/rpc/RpcMiddleware"
|
|
6
|
+
import { 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,128 @@ 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
|
+
|
|
262
|
+
return yield* gen
|
|
263
|
+
}) as any // why?
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
}))
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
const dependencies = [
|
|
272
|
+
...(make.dependencies ? make.dependencies : []),
|
|
273
|
+
...(dynamicMiddlewares.dependencies as any),
|
|
274
|
+
...middlewares.dependencies
|
|
275
|
+
]
|
|
276
|
+
const middlewareLayer = l
|
|
277
|
+
.pipe(
|
|
278
|
+
Layer.provide(dependencies as any)
|
|
279
|
+
) as Layer.Layer<
|
|
280
|
+
MiddlewareMakerId,
|
|
281
|
+
| MakeMiddlewareE // what the middleware construction can fail with
|
|
282
|
+
| LayerUtils.GetLayersError<typeof dynamicMiddlewares.dependencies>
|
|
283
|
+
| LayerUtils.GetLayersError<typeof middlewares.dependencies>, // what could go wrong when building the dynamic middleware provider
|
|
284
|
+
| LayerUtils.GetLayersContext<MiddlewareDependencies> // what's needed to build layers
|
|
285
|
+
| LayerUtils.GetLayersContext<typeof middlewares.dependencies>
|
|
286
|
+
| LayerUtils.GetLayersContext<typeof dynamicMiddlewares.dependencies> // what's needed to build dynamic middleware layers
|
|
287
|
+
| Exclude<MakeMiddlewareR, LayerUtils.GetLayersSuccess<MiddlewareDependencies>> // what layers provides
|
|
288
|
+
>
|
|
289
|
+
|
|
290
|
+
return Object.assign(MiddlewareMaker, { Default: middlewareLayer })
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export const makeMiddlewareBasic =
|
|
294
|
+
// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
|
|
295
|
+
<
|
|
296
|
+
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
297
|
+
RequestContextProviders extends RequestContextMapProvider<RequestContextMap>, // how to resolve the dynamic middleware
|
|
298
|
+
GenericMiddlewareProviders extends NonEmptyReadonlyArray<GenericMiddlewareMaker>
|
|
299
|
+
>(
|
|
300
|
+
make: MiddlewareMake<
|
|
301
|
+
RequestContextMap,
|
|
302
|
+
RequestContextProviders,
|
|
303
|
+
GenericMiddlewareProviders,
|
|
304
|
+
never,
|
|
305
|
+
never,
|
|
306
|
+
never
|
|
307
|
+
>
|
|
308
|
+
) => {
|
|
309
|
+
const MiddlewareMaker = Context.GenericTag<
|
|
310
|
+
MiddlewareMakerId,
|
|
311
|
+
{
|
|
312
|
+
effect: RPCHandlerFactory<
|
|
313
|
+
RequestContextMap,
|
|
314
|
+
GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
315
|
+
>
|
|
316
|
+
_tag: "MiddlewareMaker"
|
|
317
|
+
}
|
|
318
|
+
>(
|
|
319
|
+
"MiddlewareMaker"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
const dynamicMiddlewares = implementMiddleware<RequestContextMap>()(make.dynamicMiddlewares)
|
|
323
|
+
const middlewares = genericMiddlewareMaker(...make.genericMiddlewares)
|
|
324
|
+
|
|
196
325
|
const l = Layer.scoped(
|
|
197
326
|
MiddlewareMaker,
|
|
198
327
|
Effect
|
|
@@ -225,7 +354,8 @@ export const makeMiddleware =
|
|
|
225
354
|
return (payload, headers) =>
|
|
226
355
|
Effect
|
|
227
356
|
.gen(function*() {
|
|
228
|
-
const
|
|
357
|
+
const basic = {
|
|
358
|
+
config: schema.config ?? {},
|
|
229
359
|
payload,
|
|
230
360
|
headers,
|
|
231
361
|
clientId: 0, // TODO: get the clientId from the request context
|
|
@@ -239,29 +369,27 @@ export const makeMiddleware =
|
|
|
239
369
|
_tag: `${moduleName}.${payload._tag}`,
|
|
240
370
|
key: `${moduleName}.${payload._tag}` /* ? */
|
|
241
371
|
// clientId: 0 as number /* ? */
|
|
242
|
-
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return yield* generic({
|
|
375
|
+
...basic,
|
|
243
376
|
next:
|
|
244
377
|
// the contextProvider is an Effect that builds the context for the request
|
|
245
378
|
// the dynamicMiddlewares is an Effect that builds the dynamiuc context for the request
|
|
246
|
-
dynamicMiddlewares(
|
|
379
|
+
dynamicMiddlewares(basic).pipe(
|
|
247
380
|
Effect.flatMap((dynamicContext) => h(payload, headers).pipe(Effect.provide(dynamicContext)))
|
|
248
381
|
) as any
|
|
249
382
|
})
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return yield* gen
|
|
253
|
-
})
|
|
254
|
-
.pipe(Effect.onExit(Console.log)) as any // why?
|
|
383
|
+
}) as any // why?
|
|
255
384
|
}
|
|
256
385
|
)
|
|
257
|
-
}))
|
|
258
|
-
Effect.onExit(Console.log)
|
|
386
|
+
}))
|
|
259
387
|
)
|
|
260
388
|
)
|
|
261
389
|
|
|
262
390
|
const dependencies = [
|
|
263
391
|
...(make.dependencies ? make.dependencies : []),
|
|
264
|
-
...(dynamicMiddlewares.dependencies
|
|
392
|
+
...(dynamicMiddlewares.dependencies),
|
|
265
393
|
...middlewares.dependencies
|
|
266
394
|
]
|
|
267
395
|
const middlewareLayer = l
|
|
@@ -269,13 +397,10 @@ export const makeMiddleware =
|
|
|
269
397
|
Layer.provide(dependencies as any)
|
|
270
398
|
) as Layer.Layer<
|
|
271
399
|
MiddlewareMakerId,
|
|
272
|
-
| MakeMiddlewareE // what the middleware construction can fail with
|
|
273
400
|
| LayerUtils.GetLayersError<typeof dynamicMiddlewares.dependencies>
|
|
274
401
|
| 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
402
|
| LayerUtils.GetLayersContext<typeof middlewares.dependencies>
|
|
277
403
|
| LayerUtils.GetLayersContext<typeof dynamicMiddlewares.dependencies> // what's needed to build dynamic middleware layers
|
|
278
|
-
| Exclude<MakeMiddlewareR, LayerUtils.GetLayersSuccess<MiddlewareDependencies>> // what layers provides
|
|
279
404
|
>
|
|
280
405
|
|
|
281
406
|
return Object.assign(MiddlewareMaker, { Default: middlewareLayer })
|
|
@@ -347,10 +472,154 @@ type RpcOptionsOriginal = {
|
|
|
347
472
|
readonly requiredForClient?: boolean
|
|
348
473
|
}
|
|
349
474
|
|
|
475
|
+
type RpcDynamic<Key extends string, A extends RPCContextMap.Any> = {
|
|
476
|
+
key: Key
|
|
477
|
+
settings: A
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
type RpcOptionsDynamic<Key extends string, A extends RPCContextMap.Any> = RpcOptionsOriginal & {
|
|
481
|
+
readonly dynamic: RpcDynamic<Key, A>
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export type Dynamic<Options> = Options extends RpcOptionsDynamic<any, any> ? true : false
|
|
485
|
+
|
|
486
|
+
export interface RpcMiddlewareDynamic<A, E, Config> {
|
|
487
|
+
(options: {
|
|
488
|
+
readonly config: Config // todo
|
|
489
|
+
readonly clientId: number
|
|
490
|
+
readonly rpc: Rpc.AnyWithProps
|
|
491
|
+
readonly payload: unknown
|
|
492
|
+
readonly headers: HttpHeaders.Headers
|
|
493
|
+
}): Effect.Effect<Option.Option<Context.Context<A>>, E, Scope.Scope>
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export interface TagClassDynamicAny<RequestContext extends Record<string, RPCContextMap.Any>>
|
|
497
|
+
extends Context.Tag<any, any>
|
|
498
|
+
{
|
|
499
|
+
readonly [RpcMiddleware.TypeId]: RpcMiddleware.TypeId
|
|
500
|
+
readonly optional: boolean
|
|
501
|
+
readonly provides?: Context.Tag<any, any> | undefined
|
|
502
|
+
readonly failure: Schema.Schema.All
|
|
503
|
+
readonly requiredForClient: boolean
|
|
504
|
+
readonly dynamic: RpcDynamic<any, RequestContext[keyof RequestContext]>
|
|
505
|
+
readonly wrap: boolean
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export declare namespace TagClass {
|
|
509
|
+
/**
|
|
510
|
+
* @since 1.0.0
|
|
511
|
+
* @category models
|
|
512
|
+
*/
|
|
513
|
+
export type Provides<Options> = Options extends {
|
|
514
|
+
readonly provides: Context.Tag<any, any>
|
|
515
|
+
readonly optional?: false
|
|
516
|
+
} ? Context.Tag.Identifier<Options["provides"]>
|
|
517
|
+
: never
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @since 1.0.0
|
|
521
|
+
* @category models
|
|
522
|
+
*/
|
|
523
|
+
export type Service<Options> = Options extends { readonly provides: Context.Tag<any, any> }
|
|
524
|
+
? Context.Tag.Service<Options["provides"]>
|
|
525
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["service"]
|
|
526
|
+
: void
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* @since 1.0.0
|
|
530
|
+
* @category models
|
|
531
|
+
*/
|
|
532
|
+
export type FailureSchema<Options> = Options extends
|
|
533
|
+
{ readonly failure: Schema.Schema.All; readonly optional?: false } ? Options["failure"]
|
|
534
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? A["error"]
|
|
535
|
+
: typeof Schema.Never
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* @since 1.0.0
|
|
539
|
+
* @category models
|
|
540
|
+
*/
|
|
541
|
+
export type Failure<Options> = Options extends
|
|
542
|
+
{ readonly failure: Schema.Schema<infer _A, infer _I, infer _R>; readonly optional?: false } ? _A
|
|
543
|
+
: Options extends { readonly dynamic: RpcDynamic<any, infer A> } ? S.Schema.Type<A["error"]>
|
|
544
|
+
: never
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* @since 1.0.0
|
|
548
|
+
* @category models
|
|
549
|
+
*/
|
|
550
|
+
export type FailureContext<Options> = Schema.Schema.Context<FailureSchema<Options>>
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* @since 1.0.0
|
|
554
|
+
* @category models
|
|
555
|
+
*/
|
|
556
|
+
export type FailureService<Options> = Optional<Options> extends true ? unknown : Failure<Options>
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* @since 1.0.0
|
|
560
|
+
* @category models
|
|
561
|
+
*/
|
|
562
|
+
export type Optional<Options> = Options extends { readonly optional: true } ? true : false
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* @since 1.0.0
|
|
566
|
+
* @category models
|
|
567
|
+
*/
|
|
568
|
+
export type RequiredForClient<Options> = Options extends { readonly requiredForClient: true } ? true : false
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* @since 1.0.0
|
|
572
|
+
* @category models
|
|
573
|
+
*/
|
|
574
|
+
export type Wrap<Options> = Options extends { readonly wrap: true } ? true : false
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* @since 1.0.0
|
|
578
|
+
* @category models
|
|
579
|
+
*/
|
|
580
|
+
export interface Base<Self, Name extends string, Options, Service> extends Context.Tag<Self, Service> {
|
|
581
|
+
new(_: never): Context.TagClassShape<Name, Service>
|
|
582
|
+
readonly [TypeId]: TypeId
|
|
583
|
+
readonly optional: Optional<Options>
|
|
584
|
+
readonly failure: FailureSchema<Options>
|
|
585
|
+
readonly provides: Options extends { readonly provides: Context.Tag<any, any> } ? Options["provides"]
|
|
586
|
+
: undefined
|
|
587
|
+
readonly dynamic: Options extends RpcOptionsDynamic<any, any> ? Options["dynamic"]
|
|
588
|
+
: undefined
|
|
589
|
+
readonly requiredForClient: RequiredForClient<Options>
|
|
590
|
+
readonly wrap: Wrap<Options>
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export interface TagClass<
|
|
595
|
+
Self,
|
|
596
|
+
Name extends string,
|
|
597
|
+
Options
|
|
598
|
+
> extends
|
|
599
|
+
TagClass.Base<
|
|
600
|
+
Self,
|
|
601
|
+
Name,
|
|
602
|
+
Options,
|
|
603
|
+
TagClass.Wrap<Options> extends true ? RpcMiddlewareWrap<
|
|
604
|
+
TagClass.Provides<Options>,
|
|
605
|
+
TagClass.Failure<Options>
|
|
606
|
+
>
|
|
607
|
+
: Options extends RpcOptionsDynamic<any, any> ? RpcMiddlewareDynamic<
|
|
608
|
+
TagClass.Service<Options>,
|
|
609
|
+
TagClass.FailureService<Options>,
|
|
610
|
+
{ [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
|
|
611
|
+
>
|
|
612
|
+
: RpcMiddleware<
|
|
613
|
+
TagClass.Service<Options>,
|
|
614
|
+
TagClass.FailureService<Options>
|
|
615
|
+
>
|
|
616
|
+
>
|
|
617
|
+
{}
|
|
618
|
+
|
|
350
619
|
export const Tag = <Self>() =>
|
|
351
620
|
<
|
|
352
621
|
const Name extends string,
|
|
353
|
-
const Options extends RpcOptionsOriginal
|
|
622
|
+
const Options extends RpcOptionsOriginal | RpcOptionsDynamic<any, any>
|
|
354
623
|
>(
|
|
355
624
|
id: Name,
|
|
356
625
|
options?: Options | undefined
|
|
@@ -361,6 +630,11 @@ export const Tag = <Self>() =>
|
|
|
361
630
|
TagClass.Provides<Options>,
|
|
362
631
|
TagClass.Failure<Options>
|
|
363
632
|
>
|
|
633
|
+
: Options extends RpcOptionsDynamic<any, any> ? RpcMiddlewareDynamic<
|
|
634
|
+
TagClass.Service<Options>,
|
|
635
|
+
TagClass.FailureService<Options>,
|
|
636
|
+
{ [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] }
|
|
637
|
+
>
|
|
364
638
|
: RpcMiddleware<
|
|
365
639
|
TagClass.Service<Options>,
|
|
366
640
|
TagClass.FailureService<Options>
|
|
@@ -369,10 +643,12 @@ export const Tag = <Self>() =>
|
|
|
369
643
|
R
|
|
370
644
|
>
|
|
371
645
|
dependencies?: L
|
|
372
|
-
}):
|
|
646
|
+
}): TagClass<Self, Name, Options> & {
|
|
373
647
|
Default: Layer.Layer<Self, E | LayerUtils.GetLayersError<L>, Exclude<R, LayerUtils.GetLayersSuccess<L>>>
|
|
374
648
|
} =>
|
|
375
649
|
class extends RpcMiddleware.Tag<Self>()(id, options) {
|
|
650
|
+
// TODO: move to TagClass.
|
|
651
|
+
static readonly dynamic = options && "dynamic" in options ? options.dynamic : undefined
|
|
376
652
|
static readonly Default = Layer.scoped(this, opts.effect as any).pipe(
|
|
377
653
|
Layer.provide([Layer.empty, ...opts.dependencies ?? []])
|
|
378
654
|
)
|
|
@@ -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
|
|