@effect-app/infra 2.79.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 +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/ContextProvider.d.ts +1 -3
- package/dist/api/routing/middleware/ContextProvider.d.ts.map +1 -1
- package/dist/api/routing/middleware/ContextProvider.js +1 -1
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +135 -12
- 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 +8 -3
- 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/dist/api/routing.d.ts +7 -7
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +1 -1
- package/package.json +5 -1
- package/src/api/internal/auth.ts +4 -5
- package/src/api/routing/middleware/ContextProvider.ts +8 -7
- package/src/api/routing/middleware/DynamicMiddleware.ts +309 -28
- package/src/api/routing/middleware/dynamic-middleware.ts +12 -23
- package/src/api/routing/middleware/generic-middleware.ts +8 -3
- package/src/api/routing/middleware/middleware-api.ts +44 -0
- package/src/api/routing/middleware.ts +1 -0
- package/src/api/routing.ts +5 -5
- package/test/{dynamicContext.test.ts → contextProvider.test.ts} +5 -6
- package/test/controller.test.ts +39 -30
- package/test/dist/contextProvider.test.d.ts.map +1 -0
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/middleware-api.test.d.ts.map +1 -0
|
@@ -2,10 +2,10 @@
|
|
|
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
|
-
import { type HttpHeaders
|
|
8
|
+
import { type HttpHeaders } from "effect-app/http"
|
|
9
9
|
import { type TagUnify, type TagUnifyIgnore } from "effect/Context"
|
|
10
10
|
import type * as EffectRequest from "effect/Request"
|
|
11
11
|
import { type ContextTagWithDefault, type LayerUtils } from "../../layerUtils.js"
|
|
@@ -73,7 +73,7 @@ export type RPCHandlerFactory<
|
|
|
73
73
|
) => Effect.Effect<
|
|
74
74
|
Request.Request.Success<Req>,
|
|
75
75
|
Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
|
|
76
|
-
|
|
|
76
|
+
| Scope.Scope // because of the context provider and the middleware (Middleware)
|
|
77
77
|
| Exclude<
|
|
78
78
|
// the middleware will remove from HandlerR the dynamic context
|
|
79
79
|
// & S.Schema<Req, any, never> is useless here but useful when creating the middleware
|
|
@@ -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"],
|
|
@@ -109,23 +109,23 @@ export interface MiddlewareMake<
|
|
|
109
109
|
// this actually builds "the middleware", i.e. returns the augmented next factory when yielded...
|
|
110
110
|
execute?: (
|
|
111
111
|
maker: (
|
|
112
|
-
// MiddlewareR is set to GenericMiddlewareProviders |
|
|
112
|
+
// MiddlewareR is set to GenericMiddlewareProviders | Scope.Scope because that's what, at most
|
|
113
113
|
// a middleware can additionally require to get executed
|
|
114
114
|
cb: MakeRPCHandlerFactory<
|
|
115
115
|
RequestContextMap,
|
|
116
116
|
| GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
117
|
-
|
|
|
117
|
+
| Scope.Scope
|
|
118
118
|
>
|
|
119
119
|
) => MakeRPCHandlerFactory<
|
|
120
120
|
RequestContextMap,
|
|
121
121
|
| GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
122
|
-
|
|
|
122
|
+
| Scope.Scope
|
|
123
123
|
>
|
|
124
124
|
) => Effect<
|
|
125
125
|
MakeRPCHandlerFactory<
|
|
126
126
|
RequestContextMap,
|
|
127
127
|
| GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
128
|
-
|
|
|
128
|
+
| Scope.Scope
|
|
129
129
|
>,
|
|
130
130
|
MakeMiddlewareE,
|
|
131
131
|
MakeMiddlewareR | Scope // ...that's why MakeMiddlewareR is here
|
|
@@ -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
|
|
@@ -203,13 +210,138 @@ export const makeMiddleware =
|
|
|
203
210
|
? make.execute((
|
|
204
211
|
cb: MakeRPCHandlerFactory<
|
|
205
212
|
RequestContextMap,
|
|
206
|
-
|
|
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
|
+
|
|
328
|
+
const l = Layer.scoped(
|
|
329
|
+
MiddlewareMaker,
|
|
330
|
+
Effect
|
|
331
|
+
.all({
|
|
332
|
+
dynamicMiddlewares: dynamicMiddlewares.effect,
|
|
333
|
+
generic: middlewares.effect,
|
|
334
|
+
middleware: make.execute
|
|
335
|
+
? make.execute((
|
|
336
|
+
cb: MakeRPCHandlerFactory<
|
|
337
|
+
RequestContextMap,
|
|
338
|
+
Scope.Scope | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
207
339
|
>
|
|
208
340
|
) => cb)
|
|
209
341
|
: Effect.succeed<
|
|
210
342
|
MakeRPCHandlerFactory<
|
|
211
343
|
RequestContextMap,
|
|
212
|
-
|
|
344
|
+
Scope.Scope | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
213
345
|
>
|
|
214
346
|
>((_schema, next) => (payload, headers) => next(payload, headers))
|
|
215
347
|
})
|
|
@@ -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 })
|
|
@@ -310,7 +440,7 @@ function makeRpcEffect<
|
|
|
310
440
|
) => Effect.Effect<
|
|
311
441
|
Request.Request.Success<Req>,
|
|
312
442
|
Request.Request.Error<Req> | RequestContextMapErrors<RequestContextMap>,
|
|
313
|
-
|
|
|
443
|
+
| Scope.Scope // the context provider may require Scope to run
|
|
314
444
|
| Exclude<
|
|
315
445
|
// it can also be removed from HandlerR
|
|
316
446
|
Exclude<HandlerR, GetEffectContext<RequestContextMap, (T & S.Schema<Req, any, never>)["config"]>>,
|
|
@@ -320,14 +450,14 @@ function makeRpcEffect<
|
|
|
320
450
|
) => cb
|
|
321
451
|
}
|
|
322
452
|
|
|
323
|
-
// updated to support
|
|
453
|
+
// updated to support Scope.Scope
|
|
324
454
|
export interface RpcMiddleware<Provides, E> {
|
|
325
455
|
(options: {
|
|
326
456
|
readonly clientId: number
|
|
327
457
|
readonly rpc: Rpc.AnyWithProps
|
|
328
458
|
readonly payload: unknown
|
|
329
459
|
readonly headers: HttpHeaders.Headers
|
|
330
|
-
}): Effect.Effect<Provides, E,
|
|
460
|
+
}): Effect.Effect<Provides, E, Scope.Scope>
|
|
331
461
|
}
|
|
332
462
|
export interface RpcMiddlewareWrap<Provides, E> {
|
|
333
463
|
(options: {
|
|
@@ -335,8 +465,8 @@ export interface RpcMiddlewareWrap<Provides, E> {
|
|
|
335
465
|
readonly rpc: Rpc.AnyWithProps
|
|
336
466
|
readonly payload: unknown
|
|
337
467
|
readonly headers: HttpHeaders.Headers
|
|
338
|
-
readonly next: Effect.Effect<SuccessValue, E, Provides |
|
|
339
|
-
}): Effect.Effect<SuccessValue, E,
|
|
468
|
+
readonly next: Effect.Effect<SuccessValue, E, Provides | Scope.Scope>
|
|
469
|
+
}): Effect.Effect<SuccessValue, E, Scope.Scope>
|
|
340
470
|
}
|
|
341
471
|
|
|
342
472
|
type RpcOptionsOriginal = {
|
|
@@ -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]>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { type Rpc, type RpcMiddleware } from "@effect/rpc"
|
|
3
3
|
import { type SuccessValue, type TagClassAny } from "@effect/rpc/RpcMiddleware"
|
|
4
|
-
import { type Array, Context, Effect, type Layer } from "effect-app"
|
|
5
|
-
import { type
|
|
4
|
+
import { type Array, Context, Effect, type Layer, type Scope } from "effect-app"
|
|
5
|
+
import { type RPCContextMap } from "effect-app/client"
|
|
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..
|
|
10
|
-
readonly next: Effect.Effect<SuccessValue, E,
|
|
12
|
+
readonly next: Effect.Effect<SuccessValue, E, Scope.Scope>
|
|
11
13
|
readonly payload: unknown
|
|
12
14
|
readonly headers: HttpHeaders.Headers
|
|
13
15
|
readonly clientId: number
|
|
@@ -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
|
|