@effect-app/infra 2.93.0 → 3.0.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 (63) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/Emailer/service.d.ts +1 -1
  3. package/dist/MainFiberSet.d.ts +1 -1
  4. package/dist/Operations.d.ts +1 -1
  5. package/dist/RequestFiberSet.d.ts +1 -1
  6. package/dist/Store/service.d.ts +2 -2
  7. package/dist/adapters/SQL/Model.d.ts +6 -6
  8. package/dist/adapters/ServiceBus.d.ts +2 -2
  9. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  10. package/dist/adapters/ServiceBus.js +13 -10
  11. package/dist/adapters/memQueue.d.ts +1 -1
  12. package/dist/api/ContextProvider.d.ts +3 -3
  13. package/dist/api/ContextProvider.d.ts.map +1 -1
  14. package/dist/api/ContextProvider.js +1 -1
  15. package/dist/api/routing/middleware/RouterMiddleware.d.ts +6 -6
  16. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  17. package/dist/api/routing/middleware/RpcMiddleware.d.ts +4 -15
  18. package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -1
  19. package/dist/api/routing/middleware/RpcMiddleware.js +3 -4
  20. package/dist/api/routing/middleware/RpcMiddlewareX.d.ts +18 -0
  21. package/dist/api/routing/middleware/RpcMiddlewareX.d.ts.map +1 -0
  22. package/dist/api/routing/middleware/RpcMiddlewareX.js +16 -0
  23. package/dist/api/routing/middleware/generic-middleware.d.ts +22 -8
  24. package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
  25. package/dist/api/routing/middleware/generic-middleware.js +59 -62
  26. package/dist/api/routing/middleware/middleware-api.d.ts +51 -32
  27. package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
  28. package/dist/api/routing/middleware/middleware-api.js +54 -24
  29. package/dist/api/routing/middleware/middleware-native.d.ts +23 -0
  30. package/dist/api/routing/middleware/middleware-native.d.ts.map +1 -0
  31. package/dist/api/routing/middleware/middleware-native.js +19 -0
  32. package/dist/api/routing/middleware/middleware.d.ts +7 -27
  33. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  34. package/dist/api/routing/middleware/middleware.js +73 -88
  35. package/dist/api/routing/middleware.d.ts +1 -0
  36. package/dist/api/routing/middleware.d.ts.map +1 -1
  37. package/dist/api/routing/middleware.js +2 -1
  38. package/dist/api/routing.d.ts +1 -4
  39. package/dist/api/routing.d.ts.map +1 -1
  40. package/dist/api/routing.js +8 -8
  41. package/package.json +11 -3
  42. package/src/adapters/ServiceBus.ts +7 -5
  43. package/src/api/ContextProvider.ts +9 -7
  44. package/src/api/routing/middleware/RouterMiddleware.ts +9 -8
  45. package/src/api/routing/middleware/RpcMiddleware.ts +4 -51
  46. package/src/api/routing/middleware/RpcMiddlewareX.ts +70 -0
  47. package/src/api/routing/middleware/generic-middleware.ts +142 -107
  48. package/src/api/routing/middleware/middleware-api.ts +239 -61
  49. package/src/api/routing/middleware/middleware-native.ts +23 -0
  50. package/src/api/routing/middleware/middleware.ts +37 -40
  51. package/src/api/routing/middleware.ts +1 -0
  52. package/src/api/routing.ts +7 -13
  53. package/test/contextProvider.test.ts +4 -4
  54. package/test/controller.test.ts +41 -16
  55. package/test/dist/controller.test.d.ts.map +1 -1
  56. package/test/dist/fixtures.d.ts +48 -32
  57. package/test/dist/fixtures.d.ts.map +1 -1
  58. package/test/dist/fixtures.js +76 -47
  59. package/test/dist/requires.test.d.ts.map +1 -1
  60. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -0
  61. package/test/fixtures.ts +71 -17
  62. package/test/requires.test.ts +15 -50
  63. package/test/rpc-multi-middleware.test.ts +134 -0
@@ -1,10 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Rpc, type RpcGroup, type RpcMiddleware, type RpcSchema } from "@effect/rpc"
2
3
  import { type AnyWithProps } from "@effect/rpc/Rpc"
3
- import { Context, type Effect, type NonEmptyArray, type NonEmptyReadonlyArray, S } from "effect-app"
4
- import { type GetContextConfig, type RPCContextMap } from "effect-app/client"
4
+ import { type HandlersFrom } from "@effect/rpc/RpcGroup"
5
+ import { Tag } from "@effect/rpc/RpcMiddleware"
6
+ import { Context, type Effect, Layer, type NonEmptyArray, type NonEmptyReadonlyArray, S, type Schema, type Scope, type Stream } from "effect-app"
7
+ import { type GetContextConfig, type GetEffectContext, type RPCContextMap } from "effect-app/client"
8
+ import { typedValuesOf } from "effect-app/utils"
9
+ import { type ReadonlyMailbox } from "effect/Mailbox"
5
10
  import { type TypeTestId } from "../../routing.js"
6
- import { type MiddlewareMaker, middlewareMaker } from "./generic-middleware.js"
7
- import { type AnyDynamic, type RpcDynamic, Tag, type TagClassAny } from "./RpcMiddleware.js"
11
+ import { type MiddlewareMaker, middlewareMaker, type RequestContextTag } from "./generic-middleware.js"
12
+ import { type AnyDynamic, type RpcDynamic, type TagClassAny } from "./RpcMiddleware.js"
8
13
 
9
14
  /** Adapter used when setting the dynamic prop on a middleware implementation */
10
15
  export const contextMap = <
@@ -15,26 +20,27 @@ export const contextMap = <
15
20
  settings: { service: rcm[key]!["service"] } as RequestContextMap[Key]
16
21
  })
17
22
 
23
+ const tag = Context.GenericTag("RequestContextConfig")
18
24
  /** Retrieves RequestContextConfig out of the RPC annotations */
19
25
  export const getConfig = <
20
26
  RequestContextMap extends Record<string, RPCContextMap.Any>
21
27
  >() =>
22
28
  (rpc: AnyWithProps): GetContextConfig<RequestContextMap> => {
23
- return Context.unsafeGet(rpc.annotations, Context.GenericTag("RequestContextConfig"))
29
+ return Context.getOrElse(rpc.annotations, tag as any, () => ({}))
24
30
  }
25
31
 
26
32
  // the following implements sort of builder pattern
27
33
  // we support both sideways and upwards elimination of dependencies
28
34
 
29
35
  // it's for dynamic middlewares
30
- type GetDependsOnKeys<MW extends MiddlewareMaker> = MW extends { dependsOn: NonEmptyReadonlyArray<TagClassAny> } ? {
36
+ type GetDependsOnKeys<MW extends MiddlewareMaker.Any> = MW extends { dependsOn: NonEmptyReadonlyArray<TagClassAny> } ? {
31
37
  [K in keyof MW["dependsOn"]]: MW["dependsOn"][K] extends AnyDynamic ? MW["dependsOn"][K]["dynamic"]["key"]
32
38
  : never
33
39
  }[keyof MW["dependsOn"]]
34
40
  : never
35
41
 
36
42
  type FilterInDynamicMiddlewares<
37
- MWs extends ReadonlyArray<MiddlewareMaker>,
43
+ MWs extends ReadonlyArray<MiddlewareMaker.Any>,
38
44
  RequestContextMap extends Record<string, RPCContextMap.Any>
39
45
  > = {
40
46
  [K in keyof MWs]: MWs[K] extends { dynamic: RpcDynamic<any, RequestContextMap[keyof RequestContextMap]> } ? MWs[K]
@@ -46,13 +52,13 @@ type RecursiveHandleMWsSideways<
46
52
  R extends {
47
53
  rcm: Record<string, RPCContextMap.Any>
48
54
  provided: keyof R["rcm"] // that's fine
49
- middlewares: ReadonlyArray<MiddlewareMaker>
55
+ middlewares: ReadonlyArray<MiddlewareMaker.Any>
50
56
  dmp: any
51
57
  middlewareR: any
52
58
  }
53
59
  > = MWs extends [
54
- infer F extends MiddlewareMaker,
55
- ...infer Rest extends ReadonlyArray<MiddlewareMaker>
60
+ infer F extends MiddlewareMaker.Any,
61
+ ...infer Rest extends ReadonlyArray<MiddlewareMaker.Any>
56
62
  ] ? RecursiveHandleMWsSideways<Rest, {
57
63
  rcm: R["rcm"]
58
64
  // when one dynamic middleware depends on another, subtract the key to enforce the dependency to be provided after
@@ -76,11 +82,36 @@ type RecursiveHandleMWsSideways<
76
82
  export interface BuildingMiddleware<
77
83
  RequestContextMap extends Record<string, RPCContextMap.Any>,
78
84
  Provided extends keyof RequestContextMap,
79
- Middlewares extends ReadonlyArray<MiddlewareMaker>,
85
+ Middlewares extends ReadonlyArray<MiddlewareMaker.Any>,
80
86
  DynamicMiddlewareProviders,
81
87
  out MiddlewareR extends { _tag: string } = never
82
88
  > {
83
- middleware<MWs extends NonEmptyArray<MiddlewareMaker>>(
89
+ rpc: <
90
+ const Tag extends string,
91
+ Payload extends Schema.Schema.Any | Schema.Struct.Fields = typeof Schema.Void,
92
+ Success extends Schema.Schema.Any = typeof Schema.Void,
93
+ Error extends Schema.Schema.All = typeof Schema.Never,
94
+ const Stream extends boolean = false,
95
+ Config extends GetContextConfig<RequestContextMap> = {}
96
+ >(tag: Tag, options?: {
97
+ readonly payload?: Payload
98
+ readonly success?: Success
99
+ readonly error?: Error
100
+ readonly stream?: Stream
101
+ readonly config?: Config
102
+ readonly primaryKey?: [Payload] extends [Schema.Struct.Fields]
103
+ ? ((payload: Schema.Simplify<Schema.Struct.Type<NoInfer<Payload>>>) => string)
104
+ : never
105
+ }) =>
106
+ & Rpc.Rpc<
107
+ Tag,
108
+ Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
109
+ Stream extends true ? RpcSchema.Stream<Success, Error> : Success,
110
+ Stream extends true ? typeof Schema.Never : Error
111
+ >
112
+ & { readonly config: Config }
113
+
114
+ middleware<MWs extends NonEmptyArray<MiddlewareMaker.Any>>(
84
115
  ...mw: MWs
85
116
  ): RecursiveHandleMWsSideways<MWs, {
86
117
  rcm: RequestContextMap
@@ -91,7 +122,7 @@ export interface BuildingMiddleware<
91
122
  }> extends infer Res extends {
92
123
  rcm: RequestContextMap
93
124
  provided: keyof RequestContextMap
94
- middlewares: ReadonlyArray<MiddlewareMaker>
125
+ middlewares: ReadonlyArray<MiddlewareMaker.Any>
95
126
  dmp: any
96
127
  middlewareR: any
97
128
  } ? MiddlewaresBuilder<
@@ -113,7 +144,7 @@ export interface BuildingMiddleware<
113
144
  export type MiddlewaresBuilder<
114
145
  RequestContextMap extends Record<string, RPCContextMap.Any>,
115
146
  Provided extends keyof RequestContextMap = never,
116
- Middlewares extends ReadonlyArray<MiddlewareMaker> = [],
147
+ Middlewares extends ReadonlyArray<MiddlewareMaker.Any> = [],
117
148
  DynamicMiddlewareProviders = unknown,
118
149
  MiddlewareR extends { _tag: string } = never
119
150
  > =
@@ -126,50 +157,20 @@ export type MiddlewaresBuilder<
126
157
  >
127
158
  & // keyof Omit<RequestContextMap, Provided> extends never is true when all the dynamic middlewares are provided
128
159
  // MiddlewareR is never when all the required services from generic & dynamic middlewares are provided
129
- (keyof Omit<RequestContextMap, Provided> extends never ? [MiddlewareR] extends [never] ? ReturnType<
130
- typeof makeMiddlewareBasic<
131
- RequestContextMap,
132
- Middlewares
133
- >
160
+ (keyof Omit<RequestContextMap, Provided> extends never ? [MiddlewareR] extends [never] ? MiddlewareMaker<
161
+ RequestContextMap,
162
+ Middlewares
134
163
  >
135
164
  : {}
136
165
  : {})
137
166
 
138
- export const makeMiddleware: <
139
- RequestContextMap extends Record<string, RPCContextMap.Any>
140
- >(rcm: RequestContextMap) => MiddlewaresBuilder<RequestContextMap> = (rcm) => {
141
- let allMiddleware: MiddlewareMaker[] = []
142
- const it = {
143
- middleware: (...middlewares: any[]) => {
144
- for (const mw of middlewares) {
145
- // recall that we run middlewares in reverse order
146
- allMiddleware = [mw, ...allMiddleware]
147
- }
148
- return allMiddleware.filter((m) => !!m.dynamic).length !== Object.keys(rcm).length
149
- // for sure, until all the dynamic middlewares are provided it's non sensical to call makeMiddlewareBasic
150
- ? it
151
- // actually, we don't know yet if MiddlewareR is never, but we can't easily check it at runtime
152
- : Object.assign(makeMiddlewareBasic<any, any>(rcm, ...allMiddleware), it)
153
- }
154
- }
155
- return it as any
156
- }
157
-
158
- //
159
- export interface MiddlewareMakerId {
160
- readonly _id: unique symbol
161
- }
162
-
163
- // TODO: actually end up with [Tag<A, A>, Tag<B, B>, ...]
164
- type MakeTags<A> = Context.Tag<A, A>
165
-
166
167
  const makeMiddlewareBasic =
167
168
  // by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
168
169
  <
169
170
  RequestContextMap extends Record<string, RPCContextMap.Any>,
170
- MiddlewareProviders extends ReadonlyArray<MiddlewareMaker>
171
+ MiddlewareProviders extends ReadonlyArray<MiddlewareMaker.Any>
171
172
  >(
172
- _rcm: RequestContextMap,
173
+ rcm: RequestContextMap,
173
174
  ...make: MiddlewareProviders
174
175
  ) => {
175
176
  // reverse middlewares and wrap one after the other
@@ -201,26 +202,203 @@ const makeMiddlewareBasic =
201
202
  ],
202
203
  provides: (provides.length > 0
203
204
  ? provides
204
- : undefined) as unknown as MiddlewareMaker.ManyProvided<MiddlewareProviders> extends never ? never : [
205
- MakeTags<MiddlewareMaker.ManyProvided<MiddlewareProviders>>
206
- ],
205
+ : undefined) as unknown as MiddlewareMaker.ManyProvided<MiddlewareProviders> extends never ? never
206
+ : MakeTags<MiddlewareMaker.ManyProvided<MiddlewareProviders>>,
207
207
  wrap: true
208
- })(
209
- middleware as {
210
- dependencies: typeof middleware["dependencies"]
211
- effect: Effect<
208
+ })
209
+
210
+ const layer = Layer
211
+ .scoped(
212
+ MiddlewareMaker,
213
+ middleware as Effect<
212
214
  any, // TODO: why ?
213
- Effect.Error<typeof middleware["effect"]>,
214
- Effect.Context<typeof middleware["effect"]>
215
+ Effect.Error<typeof middleware>,
216
+ Effect.Context<typeof middleware>
215
217
  >
216
- }
217
- )
218
+ )
218
219
 
219
220
  // add to the tag a default implementation
220
221
  return Object.assign(MiddlewareMaker, {
222
+ layer,
221
223
  // tag to be used to retrieve the RequestContextConfig from RPC annotations
222
224
  requestContext: Context.GenericTag<"RequestContextConfig", GetContextConfig<RequestContextMap>>(
223
225
  "RequestContextConfig"
224
- )
226
+ ),
227
+ requestContextMap: rcm
225
228
  })
226
229
  }
230
+
231
+ export const makeMiddleware = <
232
+ RequestContextMap extends Record<string, RPCContextMap.Any>
233
+ >(rcm: RequestContextMap): MiddlewaresBuilder<RequestContextMap> => {
234
+ let allMiddleware: MiddlewareMaker.Any[] = []
235
+ const requestContext = Context.GenericTag<"RequestContextConfig", GetContextConfig<RequestContextMap>>(
236
+ "RequestContextConfig"
237
+ )
238
+ const it = {
239
+ // rpc with config
240
+ rpc: <
241
+ const Tag extends string,
242
+ Payload extends Schema.Schema.Any | Schema.Struct.Fields = typeof Schema.Void,
243
+ Success extends Schema.Schema.Any = typeof Schema.Void,
244
+ Error extends Schema.Schema.All = typeof Schema.Never,
245
+ const Stream extends boolean = false,
246
+ Config extends GetContextConfig<RequestContextMap> = {}
247
+ >(tag: Tag, options?: {
248
+ readonly payload?: Payload
249
+ readonly success?: Success
250
+ readonly error?: Error
251
+ readonly stream?: Stream
252
+ readonly config?: Config
253
+ readonly primaryKey?: [Payload] extends [Schema.Struct.Fields]
254
+ ? ((payload: Schema.Simplify<Schema.Struct.Type<NoInfer<Payload>>>) => string)
255
+ : never
256
+ }):
257
+ & Rpc.Rpc<
258
+ Tag,
259
+ Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
260
+ // TODO: enhance `Error`. type based on middleware config.
261
+ Stream extends true ? RpcSchema.Stream<Success, Error> : Success,
262
+ Stream extends true ? typeof Schema.Never : Error
263
+ >
264
+ & { config: Config } =>
265
+ {
266
+ const config = options?.config ?? {} as Config
267
+
268
+ // based on the config, we must enhance (union) or set failures.
269
+ // TODO: we should only include errors that are relevant based on the middleware config.ks
270
+ const error = options?.error
271
+ const errors = typedValuesOf(rcm).map((_) => _.error).filter((_) => _ && _ !== S.Never) // TODO: only the errors relevant based on config
272
+ const newError = error ? S.Union(error, ...errors) : S.Union(...errors)
273
+
274
+ const rpc = Rpc.make(tag, { ...options, error: newError }) as any
275
+
276
+ return Object.assign(rpc.annotate(requestContext, config), { config })
277
+ },
278
+ middleware: (...middlewares: any[]) => {
279
+ for (const mw of middlewares) {
280
+ // recall that we run middlewares in reverse order
281
+ allMiddleware = [mw, ...allMiddleware]
282
+ }
283
+ return allMiddleware.filter((m) => !!m.dynamic).length !== Object.keys(rcm).length
284
+ // for sure, until all the dynamic middlewares are provided it's non sensical to call makeMiddlewareBasic
285
+ ? it
286
+ // actually, we don't know yet if MiddlewareR is never, but we can't easily check it at runtime
287
+ : Object.assign(makeMiddlewareBasic<any, any>(rcm, ...allMiddleware), it)
288
+ }
289
+ }
290
+ return it as any
291
+ }
292
+
293
+ // customised version of Rpc.AddMiddleware, so that we don't loose the `config`...
294
+ // not needed if there's official support in Rpc.Rpc.
295
+ export type AddMiddleware<R extends Rpc.Any, Middleware extends RpcMiddleware.TagClassAny> = R extends Rpc.Rpc<
296
+ infer _Tag,
297
+ infer _Payload,
298
+ infer _Success,
299
+ infer _Error,
300
+ infer _Middleware
301
+ > ?
302
+ & Rpc.Rpc<
303
+ _Tag,
304
+ _Payload,
305
+ _Success,
306
+ _Error,
307
+ _Middleware | Middleware
308
+ >
309
+ & { readonly config: R extends { readonly config: infer _C } ? _C : never }
310
+ : never
311
+
312
+ // alternatively consider group.serverMiddleware? hmmm
313
+ export const middlewareGroup = <
314
+ RequestContextMap extends Record<string, RPCContextMap.Any>,
315
+ Middleware extends Context.Tag<MiddlewareMakerId, any> & RpcMiddleware.TagClassAny & {
316
+ readonly requestContext: RequestContextTag<RequestContextMap>
317
+ readonly requestContextMap: RequestContextMap
318
+ }
319
+ >(
320
+ middleware: Middleware
321
+ ) =>
322
+ <R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>) => {
323
+ type RN = AddMiddleware<R, typeof middleware>
324
+ const middlewaredGroup = group.middleware(middleware) as unknown as RpcGroup.RpcGroup<RN>
325
+ const toLayerOriginal = middlewaredGroup.toLayer.bind(middlewaredGroup)
326
+ return Object.assign(middlewaredGroup, {
327
+ toLayerDynamic: <
328
+ Handlers extends HandlersFrom<RN>,
329
+ EX = never,
330
+ RX = never
331
+ >(
332
+ build:
333
+ | Handlers
334
+ | Effect.Effect<Handlers, EX, RX>
335
+ ): Layer.Layer<
336
+ Rpc.ToHandler<RN>,
337
+ EX,
338
+ | Exclude<RX, Scope>
339
+ | HandlersContext<RN, Handlers>
340
+ > => {
341
+ return toLayerOriginal(build as any) as any // ??
342
+ }
343
+ })
344
+ }
345
+
346
+ // customized versions to handle dynamically eliminated context.
347
+ export type HandlersContext<Rpcs extends Rpc.Any, Handlers> = keyof Handlers extends infer K
348
+ ? K extends keyof Handlers & string ? HandlerContext<Rpcs, K, Handlers[K]> : never
349
+ : never
350
+
351
+ export type HandlerContext<Rpcs extends Rpc.Any, K extends Rpcs["_tag"], Handler> = [Rpc.IsStream<Rpcs, K>] extends
352
+ [true] ? Handler extends (...args: any) =>
353
+ | Stream.Stream<infer _A, infer _E, infer _R>
354
+ | Rpc.Fork<Stream.Stream<infer _A, infer _E, infer _R>>
355
+ | Effect.Effect<
356
+ ReadonlyMailbox<infer _A, infer _E>,
357
+ infer _EX,
358
+ infer _R
359
+ >
360
+ | Rpc.Fork<
361
+ Effect.Effect<
362
+ ReadonlyMailbox<infer _A, infer _E>,
363
+ infer _EX,
364
+ infer _R
365
+ >
366
+ > ? Exclude<ExcludeProvides<_R, Rpcs, K>, Scope>
367
+ : never
368
+ : Handler extends (
369
+ ...args: any
370
+ ) => Effect.Effect<infer _A, infer _E, infer _R> | Rpc.Fork<Effect.Effect<infer _A, infer _E, infer _R>>
371
+ ? ExcludeProvides<_R, Rpcs, K>
372
+ : never
373
+
374
+ // new
375
+ export type ExtractDynamicallyProvides<R extends Rpc.Any, Tag extends string> = R extends
376
+ Rpc.Rpc<Tag, infer _Payload, infer _Success, infer _Error, infer _Middleware> ? _Middleware extends {
377
+ readonly requestContextMap: infer _RC
378
+ } ? _RC extends Record<string, RPCContextMap.Any> // ? GetEffectContext<_RC, { allowAnonymous: false }>
379
+ ? R extends { readonly config: infer _C } ? GetEffectContext<_RC, _C>
380
+ : GetEffectContext<_RC, {}>
381
+ : never
382
+ : never
383
+ : never
384
+
385
+ export type ExtractProvides<R extends Rpc.Any, Tag extends string> = R extends
386
+ Rpc.Rpc<Tag, infer _Payload, infer _Success, infer _Error, infer _Middleware> ? _Middleware extends {
387
+ readonly provides: Context.Tag<infer _I, infer _S>
388
+ } ? _I
389
+ : never
390
+ : never
391
+
392
+ export type ExcludeProvides<Env, R extends Rpc.Any, Tag extends string> = Exclude<
393
+ Env,
394
+ // customisation is down here.
395
+ ExtractProvides<R, Tag> | ExtractDynamicallyProvides<R, Tag>
396
+ >
397
+
398
+ //
399
+ export interface MiddlewareMakerId {
400
+ readonly _id: unique symbol
401
+ }
402
+
403
+ // TODO: actually end up with [Tag<A, A>, Tag<B, B>, ...] once `provides: []` is implemented
404
+ export type MakeTags<A> = Context.Tag<A, A>
@@ -0,0 +1,23 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { RpcMiddleware } from "@effect/rpc"
3
+ import { Context } from "effect-app"
4
+
5
+ export class DevMode extends Context.Reference<DevMode>()("DevMode", { defaultValue: () => false }) {}
6
+
7
+ export class RequestCacheMiddleware
8
+ extends RpcMiddleware.Tag<RequestCacheMiddleware>()("RequestCacheMiddleware", { wrap: true })
9
+ {}
10
+
11
+ export class ConfigureInterruptibilityMiddleware
12
+ extends RpcMiddleware.Tag<ConfigureInterruptibilityMiddleware>()("ConfigureInterruptibilityMiddleware", {
13
+ wrap: true
14
+ })
15
+ {}
16
+
17
+ export class LoggerMiddleware extends RpcMiddleware.Tag<LoggerMiddleware>()("LoggerMiddleware", { wrap: true }) {}
18
+
19
+ export const DefaultGenericMiddlewares = [
20
+ RequestCacheMiddleware,
21
+ ConfigureInterruptibilityMiddleware,
22
+ LoggerMiddleware
23
+ ] as const
@@ -1,14 +1,15 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Cause, Context, Duration, Effect, Layer, ParseResult, Request, Schedule, type Schema } from "effect-app"
1
+ import { Cause, Duration, Effect, Layer, ParseResult, Request, Schedule, type Schema } from "effect"
3
2
  import { pretty } from "effect-app/utils"
4
3
  import { logError, reportError } from "../../../errorReporter.js"
5
4
  import { InfraLogger } from "../../../logger.js"
6
5
  import { determineMethod, isCommand } from "../utils.js"
7
- import { Tag } from "./RpcMiddleware.js"
6
+ import * as MiddlewareNative from "./middleware-native.js"
8
7
 
9
8
  const logRequestError = logError("Request")
10
9
  const reportRequestError = reportError("Request")
11
10
 
11
+ export { DevMode } from "./middleware-native.js"
12
+
12
13
  export const RequestCacheLayers = Layer.mergeAll(
13
14
  Layer.setRequestCache(
14
15
  Request.makeCache({ capacity: 500, timeToLive: Duration.hours(8) })
@@ -17,46 +18,43 @@ export const RequestCacheLayers = Layer.mergeAll(
17
18
  Layer.setRequestBatching(true)
18
19
  )
19
20
 
20
- export class DevMode extends Context.Reference<DevMode>()("DevMode", { defaultValue: () => false }) {}
21
-
22
- export class RequestCacheMiddleware extends Tag<RequestCacheMiddleware>()("RequestCacheMiddleware", { wrap: true })({
23
- effect: Effect.succeed(({ next }) => next.pipe(Effect.provide(RequestCacheLayers)))
24
- }) {
25
- }
21
+ export const RequestCacheMiddlewareLive = Layer.succeed(
22
+ MiddlewareNative.RequestCacheMiddleware,
23
+ ({ next }) => next.pipe(Effect.provide(RequestCacheLayers))
24
+ )
26
25
 
27
26
  // retry just once on optimistic concurrency exceptions
28
27
  const optimisticConcurrencySchedule = Schedule.once.pipe(
29
28
  Schedule.intersect(Schedule.recurWhile<any>((a) => a?._tag === "OptimisticConcurrencyException"))
30
29
  )
31
30
 
32
- export class ConfigureInterruptibilityMiddleware
33
- extends Tag<ConfigureInterruptibilityMiddleware>()("ConfigureInterruptibilityMiddleware", { wrap: true })({
34
- effect: Effect.gen(function*() {
35
- const cache = new Map()
36
- const getCached = (key: string, schema: Schema.Schema.Any) => {
37
- const existing = cache.get(key)
38
- if (existing) return existing
39
- const n = determineMethod(key, schema)
40
- cache.set(key, n)
41
- return n
42
- }
43
- return ({ next, rpc }) => {
44
- const method = getCached(rpc._tag, rpc.payloadSchema)
31
+ export const ConfigureInterruptibilityMiddlewareLive = Layer.effect(
32
+ MiddlewareNative.ConfigureInterruptibilityMiddleware,
33
+ Effect.gen(function*() {
34
+ const cache = new Map()
35
+ const getCached = (key: string, schema: Schema.Schema.Any) => {
36
+ const existing = cache.get(key)
37
+ if (existing) return existing
38
+ const n = determineMethod(key, schema)
39
+ cache.set(key, n)
40
+ return n
41
+ }
42
+ return ({ next, rpc }) => {
43
+ const method = getCached(rpc._tag, rpc.payloadSchema)
45
44
 
46
- next = isCommand(method)
47
- ? Effect.retry(Effect.uninterruptible(next), optimisticConcurrencySchedule)
48
- : Effect.interruptible(next)
45
+ next = isCommand(method)
46
+ ? Effect.retry(Effect.uninterruptible(next), optimisticConcurrencySchedule)
47
+ : Effect.interruptible(next)
49
48
 
50
- return next
51
- }
52
- })
49
+ return next
50
+ }
53
51
  })
54
- {
55
- }
52
+ )
56
53
 
57
- export class LoggerMiddleware extends Tag<LoggerMiddleware>()("LoggerMiddleware", { wrap: true })({
58
- effect: Effect.gen(function*() {
59
- const devMode = yield* DevMode
54
+ export const LoggerMiddlewareLive = Layer.effect(
55
+ MiddlewareNative.LoggerMiddleware,
56
+ Effect.gen(function*() {
57
+ const devMode = yield* MiddlewareNative.DevMode
60
58
  return ({ headers, next, payload, rpc }) =>
61
59
  Effect
62
60
  .annotateCurrentSpan({
@@ -112,11 +110,10 @@ export class LoggerMiddleware extends Tag<LoggerMiddleware>()("LoggerMiddleware"
112
110
  devMode ? (_) => _ : Effect.catchAllDefect(() => Effect.die("Internal Server Error"))
113
111
  )
114
112
  })
115
- }) {
116
- }
113
+ )
117
114
 
118
- export const DefaultGenericMiddlewares = [
119
- RequestCacheMiddleware,
120
- ConfigureInterruptibilityMiddleware,
121
- LoggerMiddleware
122
- ] as const
115
+ export const DefaultGenericMiddlewaresLive = Layer.mergeAll(
116
+ RequestCacheMiddlewareLive,
117
+ ConfigureInterruptibilityMiddlewareLive,
118
+ LoggerMiddlewareLive
119
+ )
@@ -4,6 +4,7 @@ export * from "./middleware/middleware-api.js"
4
4
  export * from "./middleware/middleware.js"
5
5
  export * from "./middleware/RouterMiddleware.js"
6
6
  export * from "./middleware/RpcMiddleware.js"
7
+ export * from "./middleware/RpcMiddlewareX.js"
7
8
  // codegen:end
8
9
 
9
10
  export * as Middleware from "./middleware.js"
@@ -5,7 +5,7 @@
5
5
  import { Rpc, RpcGroup, type RpcSerialization, RpcServer } from "@effect/rpc"
6
6
  import { type Array, Effect, Layer, type NonEmptyReadonlyArray, Predicate, S, Schema, type Scope } from "effect-app"
7
7
  import type { GetEffectContext, GetEffectError, RPCContextMap } from "effect-app/client/req"
8
- import { type HttpHeaders, HttpRouter } from "effect-app/http"
8
+ import { type HttpHeaders } from "effect-app/http"
9
9
  import { typedKeysOf, typedValuesOf } from "effect-app/utils"
10
10
  import { type Service } from "effect/Effect"
11
11
  import type { Contravariant } from "effect/Types"
@@ -158,8 +158,6 @@ export type RouteMatcher<
158
158
  }
159
159
  }
160
160
 
161
- export class Router extends HttpRouter.Tag("@effect-app/Rpc")<Router>() {}
162
-
163
161
  export const makeRouter = <
164
162
  RequestContextMap extends Record<string, RPCContextMap.Any>,
165
163
  MakeMiddlewareE,
@@ -439,15 +437,13 @@ export const makeRouter = <
439
437
  >
440
438
 
441
439
  return RpcServer
442
- .layer(rpcs, { spanPrefix: "RpcServer." + meta.moduleName })
440
+ .layerHttpRouter({
441
+ spanPrefix: "RpcServer." + meta.moduleName,
442
+ group: rpcs,
443
+ path: ("/rpc/" + meta.moduleName) as `/${typeof meta.moduleName}`,
444
+ protocol: "http"
445
+ })
443
446
  .pipe(Layer.provide(rpc))
444
- .pipe(
445
- Layer.provideMerge(
446
- RpcServer.layerProtocolHttp(
447
- { path: ("/" + meta.moduleName) as `/${typeof meta.moduleName}`, routerTag: Router }
448
- )
449
- )
450
- )
451
447
  })
452
448
  .pipe(Layer.unwrapEffect)
453
449
 
@@ -459,8 +455,6 @@ export const makeRouter = <
459
455
  Layer.provide(Layer.succeed(DevMode, devMode))
460
456
  )
461
457
 
462
- // Effect.Effect<HttpRouter.HttpRouter<unknown, HttpRouter.HttpRouter.DefaultServices>, never, UserRouter>
463
-
464
458
  return {
465
459
  moduleName: meta.moduleName,
466
460
  routes
@@ -12,7 +12,7 @@ class MyContextProvider extends Effect.Service<MyContextProvider>()("MyContextPr
12
12
  if (Math.random() > 0.5) return yield* new CustomError1()
13
13
 
14
14
  return Effect.gen(function*() {
15
- // the only requirements you can have are the one provided by HttpRouter.HttpRouter.Provided
15
+ // the only requirements you can have are the one provided by HttpLayerRouter.Provided
16
16
  yield* Scope.Scope
17
17
 
18
18
  yield* Effect.logInfo("MyContextProviderGen", "this is a generator")
@@ -63,7 +63,7 @@ class MyContextProviderGen extends Effect.Service<MyContextProviderGen>()("MyCon
63
63
  if (Math.random() > 0.5) return yield* new CustomError1()
64
64
 
65
65
  return function*() {
66
- // the only requirements you can have are the one provided by HttpRouter.HttpRouter.Provided
66
+ // the only requirements you can have are the one provided by HttpLayerRouter.Provided
67
67
  yield* Scope.Scope
68
68
 
69
69
  yield* Effect.logInfo("MyContextProviderGen", "this is a generator")
@@ -87,7 +87,7 @@ export const someContextProvider = ContextProvider({
87
87
  if (Math.random() > 0.5) return yield* new CustomError1()
88
88
 
89
89
  return Effect.gen(function*() {
90
- // the only requirements you can have are the one provided by HttpRouter.HttpRouter.Provided
90
+ // the only requirements you can have are the one provided by HttpLayerRouter.Provided
91
91
  yield* Scope.Scope
92
92
 
93
93
  // not allowed
@@ -106,7 +106,7 @@ export const someContextProviderGen = ContextProvider({
106
106
  if (Math.random() > 0.5) return yield* new CustomError1()
107
107
 
108
108
  return function*() {
109
- // the only requirements you can have are the one provided by HttpRouter.HttpRouter.Provided
109
+ // the only requirements you can have are the one provided by HttpLayerRouter.Provided
110
110
  yield* Scope.Scope
111
111
 
112
112
  // not allowed