@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.
Files changed (40) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/api/internal/auth.d.ts +2 -2
  3. package/dist/api/internal/auth.d.ts.map +1 -1
  4. package/dist/api/internal/auth.js +5 -5
  5. package/dist/api/routing/middleware/ContextProvider.d.ts +1 -3
  6. package/dist/api/routing/middleware/ContextProvider.d.ts.map +1 -1
  7. package/dist/api/routing/middleware/ContextProvider.js +1 -1
  8. package/dist/api/routing/middleware/DynamicMiddleware.d.ts +135 -12
  9. package/dist/api/routing/middleware/DynamicMiddleware.d.ts.map +1 -1
  10. package/dist/api/routing/middleware/DynamicMiddleware.js +78 -7
  11. package/dist/api/routing/middleware/dynamic-middleware.d.ts +8 -9
  12. package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
  13. package/dist/api/routing/middleware/dynamic-middleware.js +3 -3
  14. package/dist/api/routing/middleware/generic-middleware.d.ts +8 -3
  15. package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
  16. package/dist/api/routing/middleware/generic-middleware.js +1 -1
  17. package/dist/api/routing/middleware/middleware-api.d.ts +17 -0
  18. package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -0
  19. package/dist/api/routing/middleware/middleware-api.js +19 -0
  20. package/dist/api/routing/middleware/middleware.d.ts +3 -3
  21. package/dist/api/routing/middleware.d.ts +1 -0
  22. package/dist/api/routing/middleware.d.ts.map +1 -1
  23. package/dist/api/routing/middleware.js +2 -1
  24. package/dist/api/routing.d.ts +7 -7
  25. package/dist/api/routing.d.ts.map +1 -1
  26. package/dist/api/routing.js +1 -1
  27. package/package.json +5 -1
  28. package/src/api/internal/auth.ts +4 -5
  29. package/src/api/routing/middleware/ContextProvider.ts +8 -7
  30. package/src/api/routing/middleware/DynamicMiddleware.ts +309 -28
  31. package/src/api/routing/middleware/dynamic-middleware.ts +12 -23
  32. package/src/api/routing/middleware/generic-middleware.ts +8 -3
  33. package/src/api/routing/middleware/middleware-api.ts +44 -0
  34. package/src/api/routing/middleware.ts +1 -0
  35. package/src/api/routing.ts +5 -5
  36. package/test/{dynamicContext.test.ts → contextProvider.test.ts} +5 -6
  37. package/test/controller.test.ts +39 -30
  38. package/test/dist/contextProvider.test.d.ts.map +1 -0
  39. package/test/dist/controller.test.d.ts.map +1 -1
  40. 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 TagClass } from "@effect/rpc/RpcMiddleware"
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, type HttpRouter } from "effect-app/http"
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
- | HttpRouter.HttpRouter.Provided // because of the context provider and the middleware (Middleware)
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 | HttpRouter.HttpRouter.Provided because that's what, at most
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
- | HttpRouter.HttpRouter.Provided
117
+ | Scope.Scope
118
118
  >
119
119
  ) => MakeRPCHandlerFactory<
120
120
  RequestContextMap,
121
121
  | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
122
- | HttpRouter.HttpRouter.Provided
122
+ | Scope.Scope
123
123
  >
124
124
  ) => Effect<
125
125
  MakeRPCHandlerFactory<
126
126
  RequestContextMap,
127
127
  | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
128
- | HttpRouter.HttpRouter.Provided
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
- HttpRouter.HttpRouter.Provided | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
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
- HttpRouter.HttpRouter.Provided | GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
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 gen = generic({
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
- }, // todo: make moduleName part of the tag on S.Req creation.
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(schema.config ?? {}, headers).pipe(
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 as any),
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
- | HttpRouter.HttpRouter.Provided // the context provider may require HttpRouter.Provided to run
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 HttpRouter.HttpRouter.Provided
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, HttpRouter.HttpRouter.Provided>
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 | HttpRouter.HttpRouter.Provided>
339
- }): Effect.Effect<SuccessValue, E, HttpRouter.HttpRouter.Provided>
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
- }): RpcMiddleware.TagClass<Self, Name, Options> & {
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 Option, type S } from "effect-app"
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"] }, headers: Record<string, string>) {
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).handle(config, headers) as any }) 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]>["handle"]>>,
98
- Effect.Context<ReturnType<Tag.Service<TI[keyof TI]>["handle"]>>
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 HttpHeaders, type HttpRouter } from "effect-app/http"
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, HttpRouter.HttpRouter.Provided>
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