@effect-app/infra 2.35.3 → 2.36.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.
@@ -1,989 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
3
- /* eslint-disable @typescript-eslint/no-empty-object-type */
4
- /* eslint-disable @typescript-eslint/no-explicit-any */
5
- /*
6
- TODO: Effect.retry(r2, optimisticConcurrencySchedule) / was for PATCH only
7
- TODO: uninteruptible commands! was for All except GET.
8
- */
9
- import type * as HttpApp from "@effect/platform/HttpApp"
10
- import { Rpc, RpcRouter } from "@effect/rpc"
11
- import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect-app"
12
- import { Array, Cause, Chunk, Context, Effect, FiberRef, flow, Layer, Predicate, S, Schema, Stream } from "effect-app"
13
- import type { GetEffectContext, RPCContextMap } from "effect-app/client/req"
14
- import type { HttpServerError } from "effect-app/http"
15
- import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
16
- import { pretty, typedKeysOf, typedValuesOf } from "effect-app/utils"
17
- import type { Contravariant } from "effect/Types"
18
- import { logError, reportError } from "../errorReporter.js"
19
- import { InfraLogger } from "../logger.js"
20
- import type { Middleware } from "./routing/DynamicMiddleware.js"
21
- import { makeRpc } from "./routing/DynamicMiddleware.js"
22
-
23
- const logRequestError = logError("Request")
24
- const reportRequestError = reportError("Request")
25
-
26
- export type _R<T extends Effect<any, any, any>> = [T] extends [
27
- Effect<any, any, infer R>
28
- ] ? R
29
- : never
30
-
31
- export type _E<T extends Effect<any, any, any>> = [T] extends [
32
- Effect<any, infer E, any>
33
- ] ? E
34
- : never
35
-
36
- export type EffectDeps<A> = {
37
- [K in keyof A as A[K] extends Effect<any, any, any> ? K : never]: A[K] extends Effect<any, any, any> ? A[K] : never
38
- }
39
- /**
40
- * Plain jane JSON version
41
- * @deprecated use HttpRpcRouterNoStream.toHttpApp once support options
42
- */
43
- export const toHttpApp = <R extends RpcRouter.RpcRouter<any, any>>(self: R, options?: {
44
- readonly spanPrefix?: string
45
- }): HttpApp.Default<
46
- HttpServerError.RequestError,
47
- RpcRouter.RpcRouter.Context<R>
48
- > => {
49
- const handler = RpcRouter.toHandler(self, options)
50
- return Effect.withFiberRuntime((fiber) => {
51
- const context = fiber.getFiberRef(FiberRef.currentContext)
52
- const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest)
53
- return Effect.flatMap(
54
- request.json,
55
- (_) =>
56
- handler(_).pipe(
57
- Stream.provideContext(context),
58
- Stream.runCollect,
59
- Effect.map((_) => Chunk.toReadonlyArray(_)),
60
- Effect.andThen((_) => {
61
- let status = 200
62
- for (const r of _.flat()) {
63
- if (typeof r === "number") continue
64
- const results = Array.isArray(r) ? r : [r]
65
- if (results.some((_: S.ExitEncoded<any, any, any>) => _._tag === "Failure" && _.cause._tag === "Die")) {
66
- status = 500
67
- break
68
- }
69
- if (results.some((_: S.ExitEncoded<any, any, any>) => _._tag === "Failure" && _.cause._tag === "Fail")) {
70
- status = 422 // 418
71
- break
72
- }
73
- }
74
- return HttpServerResponse.json(_, { status })
75
- }),
76
- Effect.orDie,
77
- Effect.tapDefect(reportError("RPCHttpApp"))
78
- )
79
- )
80
- })
81
- }
82
-
83
- export interface Hint<Err extends string> {
84
- Err: Err
85
- }
86
-
87
- type HandleVoid<Expected, Actual, Result> = [Expected] extends [void]
88
- ? [Actual] extends [void] ? Result : Hint<"You're returning non void for a void Response, please fix">
89
- : Result
90
-
91
- export type AnyRequestModule = S.Schema.Any & {
92
- _tag: string
93
- config: any
94
- success: S.Schema.Any
95
- failure: S.Schema.Any
96
- }
97
-
98
- // we have to separate the HandleVoid case, so that we can have the normal case have A extend the success shape and error early
99
- export type Method<
100
- Rsc extends Record<string, AnyRequestModule>,
101
- K extends keyof Rsc,
102
- RT extends "d" | "raw",
103
- CTXMap extends Record<string, any>,
104
- Context,
105
- Accum
106
- > = [GetSuccessShape<Rsc[K], RT>] extends [void] ? VoidMethod<Rsc, K, RT, CTXMap, Context, Accum>
107
- : NormalMethod<Rsc, K, RT, CTXMap, Context, Accum>
108
-
109
- export interface NormalMethod<
110
- Rsc extends Record<string, AnyRequestModule>,
111
- K extends keyof Rsc,
112
- RT extends "d" | "raw",
113
- CTXMap extends Record<string, any>,
114
- Context,
115
- Accum
116
- > {
117
- // note: the defaults of = never prevent the whole router to error
118
- <A extends GetSuccessShape<Rsc[K], RT>, R2 = never, E = never>(
119
- f: Effect<A, E, R2>
120
- ): keyof { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] } extends never ? {
121
- /** @deprecated these are the finalized routes, nothing to see here */
122
- ಠ_ಠ:
123
- & {
124
- [k in K]: Handler<
125
- Rsc[K],
126
- RT,
127
- Exclude<
128
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
129
- HttpRouter.HttpRouter.Provided
130
- >
131
- >
132
- }
133
- & Accum
134
- }
135
- : RRouter<
136
- { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] },
137
- CTXMap,
138
- Context,
139
- {
140
- [k in K]: Handler<
141
- Rsc[K],
142
- RT,
143
- Exclude<
144
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
145
- HttpRouter.HttpRouter.Provided
146
- >
147
- >
148
- } & Accum
149
- >
150
-
151
- <A extends GetSuccessShape<Rsc[K], RT>, R2 = never, E = never>(
152
- f: (req: S.Schema.Type<Rsc[K]>) => Effect<A, E, R2>
153
- ): keyof { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] } extends never ? {
154
- /** @deprecated these are the finalized routes, nothing to see here */
155
- ಠ_ಠ:
156
- & {
157
- [k in K]: Handler<
158
- Rsc[K],
159
- RT,
160
- Exclude<
161
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
162
- HttpRouter.HttpRouter.Provided
163
- >
164
- >
165
- }
166
- & Accum
167
- }
168
- : RRouter<
169
- { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] },
170
- CTXMap,
171
- Context,
172
- {
173
- [k in K]: Handler<
174
- Rsc[K],
175
- RT,
176
- Exclude<
177
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
178
- HttpRouter.HttpRouter.Provided
179
- >
180
- >
181
- } & Accum
182
- >
183
- }
184
-
185
- export interface VoidMethod<
186
- Rsc extends Record<string, AnyRequestModule>,
187
- K extends keyof Rsc,
188
- RT extends "d" | "raw",
189
- CTXMap extends Record<string, any>,
190
- Context,
191
- Accum
192
- > {
193
- // note: the defaults of = never prevent the whole router to error
194
- <A, R2 = never, E = never>(
195
- f: Effect<A, E, R2>
196
- ): HandleVoid<
197
- GetSuccessShape<Rsc[K], RT>,
198
- A,
199
- keyof { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] } extends never ? {
200
- /** @deprecated these are the finalized routes, nothing to see here */
201
- ಠ_ಠ:
202
- & {
203
- [k in K]: Handler<
204
- Rsc[K],
205
- RT,
206
- Exclude<
207
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
208
- HttpRouter.HttpRouter.Provided
209
- >
210
- >
211
- }
212
- & Accum
213
- }
214
- : RRouter<
215
- { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] },
216
- CTXMap,
217
- Context,
218
- {
219
- [k in K]: Handler<
220
- Rsc[K],
221
- RT,
222
- Exclude<
223
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
224
- HttpRouter.HttpRouter.Provided
225
- >
226
- >
227
- } & Accum
228
- >
229
- >
230
-
231
- <A, R2 = never, E = never>(
232
- f: (req: S.Schema.Type<Rsc[K]>) => Effect<A, E, R2>
233
- ): HandleVoid<
234
- GetSuccessShape<Rsc[K], RT>,
235
- A,
236
- keyof { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] } extends never ? {
237
- /** @deprecated these are the finalized routes, nothing to see here */
238
- ಠ_ಠ:
239
- & {
240
- [k in K]: Handler<
241
- Rsc[K],
242
- RT,
243
- Exclude<
244
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
245
- HttpRouter.HttpRouter.Provided
246
- >
247
- >
248
- }
249
- & Accum
250
- }
251
- : RRouter<
252
- { [k in keyof Rsc as k extends K | keyof Accum ? never : k]: Rsc[k] },
253
- CTXMap,
254
- Context,
255
- {
256
- [k in K]: Handler<
257
- Rsc[K],
258
- RT,
259
- Exclude<
260
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[K]["config"]>>,
261
- HttpRouter.HttpRouter.Provided
262
- >
263
- >
264
- } & Accum
265
- >
266
- >
267
- }
268
-
269
- type RRouter<Rsc extends Record<string, AnyRequestModule>, CTXMap extends Record<string, any>, Context, Accum = {}> =
270
- & {
271
- [K in keyof Rsc]:
272
- & (Method<Rsc, K, "d", CTXMap, Context, Accum>)
273
- & {
274
- raw: Method<Rsc, K, "raw", CTXMap, Context, Accum>
275
- }
276
- }
277
- & {
278
- /** @deprecated these are the finalized routes, nothing to see here */
279
- ಠ_ಠ: Accum
280
- }
281
-
282
- type GetSuccess<T> = T extends { success: S.Schema.Any } ? T["success"] : typeof S.Void
283
-
284
- type GetSuccessShape<Action extends { success?: S.Schema.Any }, RT extends "d" | "raw"> = RT extends "raw"
285
- ? S.Schema.Encoded<GetSuccess<Action>>
286
- : S.Schema.Type<GetSuccess<Action>>
287
- type GetFailure<T extends { failure?: S.Schema.Any }> = T["failure"] extends never ? typeof S.Never : T["failure"]
288
-
289
- type HandlerFull<Action extends AnyRequestModule, RT extends "raw" | "d", A, E, R> = {
290
- new(): {}
291
- _tag: RT
292
- stack: string
293
- handler: (
294
- req: S.Schema.Type<Action>
295
- ) => Effect<
296
- A,
297
- E,
298
- R
299
- >
300
- }
301
-
302
- export interface Handler<Action extends AnyRequestModule, RT extends "raw" | "d", R> extends
303
- HandlerFull<
304
- Action,
305
- RT,
306
- GetSuccessShape<Action, RT>,
307
- S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
308
- R
309
- >
310
- {
311
- }
312
-
313
- type AHandler<Action extends AnyRequestModule> = Handler<
314
- Action,
315
- any,
316
- any
317
- >
318
-
319
- type Filter<T> = {
320
- [K in keyof T as T[K] extends AnyRequestModule ? K : never]: T[K]
321
- }
322
-
323
- export const RouterSymbol = Symbol()
324
- export interface RouterShape<Rsc> {
325
- [RouterSymbol]: Rsc
326
- }
327
-
328
- type RPCRouteR<T extends Rpc.Rpc<any, any>> = [T] extends [
329
- Rpc.Rpc<any, infer R>
330
- ] ? R
331
- : never
332
-
333
- type RPCRouteReq<T extends Rpc.Rpc<any, any>> = [T] extends [
334
- Rpc.Rpc<infer Req, any>
335
- ] ? Req
336
- : never
337
-
338
- type Match<
339
- Rsc extends Record<string, any>,
340
- CTXMap extends Record<string, any>,
341
- RT extends "raw" | "d",
342
- Key extends keyof Rsc,
343
- Context
344
- > = {
345
- // TODO: deal with HandleVoid and ability to extends from GetSuccessShape...
346
- // aka we want to make sure that the return type is void if the success is void,
347
- // and make sure A is the actual expected type
348
-
349
- // note: the defaults of = never prevent the whole router to error
350
- <A extends GetSuccessShape<Rsc[Key], RT>, R2 = never, E = never>(
351
- f: Effect<A, E, R2>
352
- ): HandleVoid<
353
- GetSuccessShape<Rsc[Key], RT>,
354
- A,
355
- Handler<
356
- Rsc[Key],
357
- RT,
358
- Exclude<
359
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>,
360
- HttpRouter.HttpRouter.Provided
361
- >
362
- >
363
- >
364
-
365
- <A extends GetSuccessShape<Rsc[Key], RT>, R2 = never, E = never>(
366
- f: (req: S.Schema.Type<Rsc[Key]>) => Effect<A, E, R2>
367
- ): HandleVoid<
368
- GetSuccessShape<Rsc[Key], RT>,
369
- A,
370
- Handler<
371
- Rsc[Key],
372
- RT,
373
- Exclude<
374
- Context | Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>,
375
- HttpRouter.HttpRouter.Provided
376
- >
377
- >
378
- >
379
- }
380
-
381
- export type RouteMatcher<
382
- CTXMap extends Record<string, any>,
383
- Rsc extends Record<string, any>,
384
- Context
385
- > = {
386
- // use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
387
- /**
388
- * Requires the Type shape
389
- */
390
- [Key in keyof Filter<Rsc>]: Match<Rsc, CTXMap, "d", Key, Context> & {
391
- success: Rsc[Key]["success"]
392
- successRaw: S.SchemaClass<S.Schema.Encoded<Rsc[Key]["success"]>>
393
- failure: Rsc[Key]["failure"]
394
- /**
395
- * Requires the Encoded shape (e.g directly undecoded from DB, so that we don't do multiple Decode/Encode)
396
- */
397
- raw: Match<Rsc, CTXMap, "raw", Key, Context>
398
- }
399
- }
400
- // export interface RouteMatcher<
401
- // Filtered extends Record<string, any>,
402
- // CTXMap extends Record<string, any>,
403
- // Rsc extends Filtered
404
- // > extends RouteMatcherInt<Filtered, CTXMap, Rsc> {}
405
-
406
- export const makeMiddleware = <
407
- Context,
408
- CTXMap extends Record<string, RPCContextMap.Any>,
409
- RMW,
410
- Layers extends NonEmptyReadonlyArray<Layer.Layer.Any> | never[]
411
- >(content: Middleware<Context, CTXMap, RMW, Layers>): Middleware<Context, CTXMap, RMW, Layers> => content
412
-
413
- export const makeRouter = <
414
- Context,
415
- CTXMap extends Record<string, RPCContextMap.Any>,
416
- RMW,
417
- Layers extends NonEmptyReadonlyArray<Layer.Layer.Any> | never[]
418
- >(
419
- middleware: Middleware<Context, CTXMap, RMW, Layers>,
420
- devMode: boolean
421
- ) => {
422
- function matchFor<
423
- const ModuleName extends string,
424
- const Rsc extends Record<string, any>
425
- >(
426
- rsc: Rsc & { meta: { moduleName: ModuleName } }
427
- ) {
428
- const meta = rsc.meta
429
- type Filtered = Filter<Rsc>
430
- const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
431
- if (Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
432
- acc[cur as keyof Filtered] = rsc[cur]
433
- }
434
- return acc
435
- }, {} as Filtered)
436
-
437
- const items = typedKeysOf(filtered).reduce(
438
- (prev, cur) => {
439
- ;(prev as any)[cur] = Object.assign((fnOrEffect: any) => {
440
- const stack = new Error().stack?.split("\n").slice(2).join("\n")
441
- return Effect.isEffect(fnOrEffect)
442
- ? class {
443
- static request = rsc[cur]
444
- static stack = stack
445
- static _tag = "d"
446
- static handler = () => fnOrEffect
447
- }
448
- : class {
449
- static request = rsc[cur]
450
- static stack = stack
451
- static _tag = "d"
452
- static handler = fnOrEffect
453
- }
454
- }, {
455
- success: rsc[cur].success,
456
- successRaw: S.encodedSchema(rsc[cur].success),
457
- failure: rsc[cur].failure,
458
- raw: // "Raw" variations are for when you don't want to decode just to encode it again on the response
459
- // e.g for direct projection from DB
460
- // but more importantly, to skip Effectful decoders, like to resolve relationships from the database or remote client.
461
- (fnOrEffect: any) => {
462
- const stack = new Error().stack?.split("\n").slice(2).join("\n")
463
- return Effect.isEffect(fnOrEffect)
464
- ? class {
465
- static request = rsc[cur]
466
- static stack = stack
467
- static _tag = "raw"
468
- static handler = () => fnOrEffect
469
- }
470
- : class {
471
- static request = rsc[cur]
472
- static stack = stack
473
- static _tag = "raw"
474
- static handler = (req: any, ctx: any) => fnOrEffect(req, { ...ctx, Response: rsc[cur].success })
475
- }
476
- }
477
- })
478
- return prev
479
- },
480
- {} as RouteMatcher<CTXMap, Rsc, Context>
481
- )
482
-
483
- type Keys = keyof Filtered
484
-
485
- type GetSuccess<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
486
- NonEmptyReadonlyArray<Layer.Layer.Any> ? {
487
- [k in keyof Layers]: Layer.Layer.Success<Layers[k]>
488
- }[number]
489
- : never
490
-
491
- type GetContext<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
492
- NonEmptyReadonlyArray<Layer.Layer.Any> ? {
493
- [k in keyof Layers]: Layer.Layer.Context<Layers[k]>
494
- }[number]
495
- : never
496
-
497
- type GetError<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends NonEmptyReadonlyArray<Layer.Layer.Any>
498
- ? { [k in keyof Layers]: Layer.Layer.Error<Layers[k]> }[number]
499
- : never
500
-
501
- const f = <
502
- E,
503
- R,
504
- THandlers extends {
505
- // import to keep them separate via | for type checking!!
506
- [K in Keys]: AHandler<Rsc[K]>
507
- },
508
- TLayers extends NonEmptyReadonlyArray<Layer.Layer.Any> | never[]
509
- >(
510
- layers: TLayers,
511
- make: Effect<THandlers, E, R>
512
- ) => {
513
- type ProvidedLayers =
514
- | { [k in keyof Layers]: Layer.Layer.Success<Layers[k]> }[number]
515
- | { [k in keyof TLayers]: Layer.Layer.Success<TLayers[k]> }[number]
516
- type Router = RouterShape<Rsc>
517
- const r: HttpRouter.HttpRouter.TagClass<
518
- Router,
519
- `${typeof meta.moduleName}Router`,
520
- never,
521
- Exclude<
522
- | Context
523
- | RPCRouteR<
524
- { [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<THandlers[K]["handler"]>>> }[keyof Filter<Rsc>]
525
- >,
526
- HttpRouter.HttpRouter.Provided
527
- >
528
- > = (class Router extends HttpRouter.Tag(`${meta.moduleName}Router`)<Router>() {}) as any
529
-
530
- const layer = r.use((router) =>
531
- Effect.gen(function*() {
532
- const controllers = yield* make
533
- const rpc = yield* makeRpc(middleware)
534
-
535
- // return make.pipe(Effect.map((c) => controllers(c, layers)))
536
- const mapped = typedKeysOf(filtered).reduce((acc, cur) => {
537
- const handler = controllers[cur as keyof typeof controllers]
538
- const req = rsc[cur]
539
-
540
- acc[cur] = rpc.effect(
541
- handler._tag === "raw"
542
- ? class extends (req as any) {
543
- static success = S.encodedSchema(req.success)
544
- get [Schema.symbolSerializable]() {
545
- return this.constructor
546
- }
547
- get [Schema.symbolWithResult]() {
548
- return {
549
- failure: req.failure,
550
- success: S.encodedSchema(req.success)
551
- }
552
- }
553
- } as any
554
- : req,
555
- (req) =>
556
- // TODO: render more data... similar to console?
557
- Effect
558
- .annotateCurrentSpan(
559
- "requestInput",
560
- Object.entries(req).reduce((prev, [key, value]: [string, unknown]) => {
561
- prev[key] = key === "password"
562
- ? "<redacted>"
563
- : typeof value === "string" || typeof value === "number" || typeof value === "boolean"
564
- ? typeof value === "string" && value.length > 256
565
- ? (value.substring(0, 253) + "...")
566
- : value
567
- : Array.isArray(value)
568
- ? `Array[${value.length}]`
569
- : value === null || value === undefined
570
- ? `${value}`
571
- : typeof value === "object" && value
572
- ? `Object[${Object.keys(value).length}]`
573
- : typeof value
574
- return prev
575
- }, {} as Record<string, string | number | boolean>)
576
- )
577
- .pipe(
578
- // can't use andThen due to some being a function and effect
579
- Effect.zipRight(handler.handler(req as any) as any),
580
- Effect.tapErrorCause((cause) => Cause.isFailure(cause) ? logRequestError(cause) : Effect.void),
581
- Effect.tapDefect((cause) =>
582
- Effect
583
- .all([
584
- reportRequestError(cause, {
585
- action: `${meta.moduleName}.${req._tag}`
586
- }),
587
- Rpc.currentHeaders.pipe(Effect.andThen((headers) => {
588
- return InfraLogger
589
- .logError("Finished request", cause)
590
- .pipe(Effect.annotateLogs({
591
- action: `${meta.moduleName}.${req._tag}`,
592
- req: pretty(req),
593
- headers: pretty(headers)
594
- // resHeaders: pretty(
595
- // Object
596
- // .entries(headers)
597
- // .reduce((prev, [key, value]) => {
598
- // prev[key] = value && typeof value === "string" ? snipString(value) : value
599
- // return prev
600
- // }, {} as Record<string, any>)
601
- // )
602
- }))
603
- }))
604
- ])
605
- ),
606
- devMode ? (_) => _ : Effect.catchAllDefect(() => Effect.die("Internal Server Error")),
607
- Effect.withSpan("Request." + meta.moduleName + "." + req._tag, {
608
- captureStackTrace: () => handler.stack
609
- })
610
- ),
611
- meta.moduleName
612
- ) // TODO
613
- return acc
614
- }, {} as any) as {
615
- [K in Keys]: Rpc.Rpc<
616
- Rsc[K],
617
- Context | _R<ReturnType<THandlers[K]["handler"]>>
618
- >
619
- }
620
-
621
- const rpcRouter = RpcRouter.make(...Object.values(mapped) as any) as RpcRouter.RpcRouter<
622
- RPCRouteReq<typeof mapped[keyof typeof mapped]>,
623
- RPCRouteR<typeof mapped[keyof typeof mapped]>
624
- >
625
- const httpApp = toHttpApp(rpcRouter, {
626
- spanPrefix: rsc
627
- .meta
628
- .moduleName + "."
629
- })
630
- yield* router
631
- .post(
632
- "/",
633
- httpApp as any,
634
- // TODO: not queries.
635
- { uninterruptible: true }
636
- )
637
- })
638
- )
639
-
640
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
641
- const routes = layer.pipe(
642
- Layer.provideMerge(r.Live),
643
- layers && Array.isNonEmptyReadonlyArray(layers) ? Layer.provide(layers as any) as any : (_) => _,
644
- // TODO: only provide to the middleware?
645
- middleware.dependencies ? Layer.provide(middleware.dependencies as any) : (_) => _
646
- ) as Layer.Layer<
647
- Router,
648
- GetError<TLayers> | E,
649
- | GetContext<TLayers>
650
- | Exclude<
651
- RMW | R,
652
- ProvidedLayers
653
- >
654
- >
655
-
656
- // Effect.Effect<HttpRouter.HttpRouter<unknown, HttpRouter.HttpRouter.DefaultServices>, never, UserRouter>
657
-
658
- return {
659
- moduleName: meta.moduleName,
660
- Router: r,
661
- routes
662
- }
663
- }
664
-
665
- const effect: {
666
- // Multiple times duplicated the "good" overload, so that errors will only mention the last overload when failing
667
- <
668
- const Make extends {
669
- dependencies: Array<Layer.Layer.Any>
670
- effect: Effect<
671
- { ಠ_ಠ: { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]> } },
672
- any,
673
- Make["strict"] extends false ? any : GetSuccess<Make["dependencies"]>
674
- >
675
- strict?: boolean
676
- /** @deprecated */
677
- readonly ಠ_ಠ: never
678
- }
679
- >(
680
- make: Make
681
- ): {
682
- moduleName: ModuleName
683
- Router: HttpRouter.HttpRouter.TagClass<
684
- RouterShape<Rsc>,
685
- `${ModuleName}Router`,
686
- never,
687
- | Exclude<Context, HttpRouter.HttpRouter.Provided>
688
- | Exclude<
689
- RPCRouteR<
690
- {
691
- [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<MakeHandlers<Make, Filter<Rsc>>[K]["handler"]>>>
692
- }[keyof Filter<Rsc>]
693
- >,
694
- HttpRouter.HttpRouter.Provided
695
- >
696
- >
697
- routes: Layer.Layer<
698
- RouterShape<Rsc>,
699
- MakeErrors<Make> | GetError<Make["dependencies"]>,
700
- | GetContext<Make["dependencies"]>
701
- // | GetContext<Layers> // elsewhere provided
702
- | Exclude<MakeContext<Make> | RMW, GetSuccess<Make["dependencies"]> | GetSuccess<Layers>>
703
- >
704
- }
705
- <
706
- const Make extends {
707
- dependencies: Array<Layer.Layer.Any>
708
- effect: Effect<
709
- { ಠ_ಠ: { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]> } },
710
- any,
711
- Make["strict"] extends false ? any : GetSuccess<Make["dependencies"]>
712
- >
713
- strict?: boolean
714
- /** @deprecated */
715
- readonly ಠ_ಠ: never
716
- }
717
- >(
718
- make: Make
719
- ): {
720
- moduleName: ModuleName
721
- Router: HttpRouter.HttpRouter.TagClass<
722
- RouterShape<Rsc>,
723
- `${ModuleName}Router`,
724
- never,
725
- | Exclude<Context, HttpRouter.HttpRouter.Provided>
726
- | Exclude<
727
- RPCRouteR<
728
- {
729
- [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<MakeHandlers<Make, Filter<Rsc>>[K]["handler"]>>>
730
- }[keyof Filter<Rsc>]
731
- >,
732
- HttpRouter.HttpRouter.Provided
733
- >
734
- >
735
- routes: Layer.Layer<
736
- RouterShape<Rsc>,
737
- MakeErrors<Make> | GetError<Make["dependencies"]>,
738
- | GetContext<Make["dependencies"]>
739
- // | GetContext<Layers> // elsewhere provided
740
- | Exclude<MakeContext<Make> | RMW, GetSuccess<Make["dependencies"]> | GetSuccess<Layers>>
741
- >
742
- }
743
- <
744
- const Make extends {
745
- dependencies: Array<Layer.Layer.Any>
746
- effect: Effect<
747
- { ಠ_ಠ: { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]> } },
748
- any,
749
- Make["strict"] extends false ? any : GetSuccess<Make["dependencies"]>
750
- >
751
- strict?: boolean
752
- /** @deprecated */
753
- readonly ಠ_ಠ: never
754
- }
755
- >(
756
- make: Make
757
- ): {
758
- moduleName: ModuleName
759
- Router: HttpRouter.HttpRouter.TagClass<
760
- RouterShape<Rsc>,
761
- `${ModuleName}Router`,
762
- never,
763
- | Exclude<Context, HttpRouter.HttpRouter.Provided>
764
- | Exclude<
765
- RPCRouteR<
766
- {
767
- [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<MakeHandlers<Make, Filter<Rsc>>[K]["handler"]>>>
768
- }[keyof Filter<Rsc>]
769
- >,
770
- HttpRouter.HttpRouter.Provided
771
- >
772
- >
773
- routes: Layer.Layer<
774
- RouterShape<Rsc>,
775
- MakeErrors<Make> | GetError<Make["dependencies"]>,
776
- | GetContext<Make["dependencies"]>
777
- // | GetContext<Layers> // elsewhere provided
778
- | Exclude<MakeContext<Make> | RMW, GetSuccess<Make["dependencies"]> | GetSuccess<Layers>>
779
- >
780
- }
781
- <
782
- const Make extends {
783
- dependencies: Array<Layer.Layer.Any>
784
- effect: Effect<
785
- { ಠ_ಠ: { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]> } },
786
- any,
787
- GetSuccess<Make["dependencies"]>
788
- >
789
- strict?: boolean
790
- /** @deprecated */
791
- readonly ಠ_ಠ: never
792
- }
793
- >(
794
- make: Make
795
- ): {
796
- moduleName: ModuleName
797
- Router: HttpRouter.HttpRouter.TagClass<
798
- RouterShape<Rsc>,
799
- `${ModuleName}Router`,
800
- never,
801
- | Exclude<Context, HttpRouter.HttpRouter.Provided>
802
- | Exclude<
803
- RPCRouteR<
804
- {
805
- [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<MakeHandlers<Make, Filter<Rsc>>[K]["handler"]>>>
806
- }[keyof Filter<Rsc>]
807
- >,
808
- HttpRouter.HttpRouter.Provided
809
- >
810
- >
811
- routes: Layer.Layer<
812
- RouterShape<Rsc>,
813
- MakeErrors<Make> | GetError<Make["dependencies"]>,
814
- | GetContext<Make["dependencies"]>
815
- // | GetContext<Layers> // elsewhere provided
816
- | Exclude<MakeContext<Make> | RMW, GetSuccess<Make["dependencies"]> | GetSuccess<Layers>>
817
- >
818
- }
819
- <
820
- const Make extends {
821
- dependencies: Array<Layer.Layer.Any>
822
- effect: Effect<
823
- { ಠ_ಠ: { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]> } },
824
- any,
825
- GetSuccess<Make["dependencies"]>
826
- >
827
- strict?: boolean
828
- }
829
- >(
830
- make: Make
831
- ): {
832
- moduleName: ModuleName
833
- Router: HttpRouter.HttpRouter.TagClass<
834
- RouterShape<Rsc>,
835
- `${ModuleName}Router`,
836
- never,
837
- | Exclude<Context, HttpRouter.HttpRouter.Provided>
838
- | Exclude<
839
- RPCRouteR<
840
- {
841
- [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<MakeHandlers<Make, Filter<Rsc>>[K]["handler"]>>>
842
- }[keyof Filter<Rsc>]
843
- >,
844
- HttpRouter.HttpRouter.Provided
845
- >
846
- >
847
- routes: Layer.Layer<
848
- RouterShape<Rsc>,
849
- MakeErrors<Make> | GetError<Make["dependencies"]>,
850
- | GetContext<Make["dependencies"]>
851
- // | GetContext<Layers> // elsewhere provided
852
- | Exclude<MakeContext<Make> | RMW, GetSuccess<Make["dependencies"]> | GetSuccess<Layers>>
853
- >
854
- }
855
- <
856
- const Make extends {
857
- dependencies: [
858
- ...Make["dependencies"],
859
- ...Exclude<Effect.Context<Make["effect"]>, MakeDepsOut<Make>> extends never ? []
860
- : [Layer.Layer<Exclude<Effect.Context<Make["effect"]>, MakeDepsOut<Make>>, never, never>]
861
- ]
862
- effect: Effect<
863
- { ಠ_ಠ: { [K in keyof Filter<Rsc>]: AHandler<Rsc[K]> } },
864
- any,
865
- any
866
- >
867
- strict?: boolean
868
- }
869
- >(
870
- make: Make
871
- ): {
872
- moduleName: ModuleName
873
- Router: HttpRouter.HttpRouter.TagClass<
874
- RouterShape<Rsc>,
875
- `${ModuleName}Router`,
876
- never,
877
- Exclude<Context, HttpRouter.HttpRouter.Provided>
878
- > // | Exclude<
879
- // RPCRouteR<
880
- // { [K in keyof Filter<Rsc>]: Rpc.Rpc<Rsc[K], _R<ReturnType<THandlers[K]["handler"]>>> }[keyof Filter<Rsc>]
881
- // >,
882
- // HttpRouter.HttpRouter.Provided
883
- // >
884
- routes: any
885
- }
886
- } = ((m: { dependencies: any; effect: any; strict?: any }) => f(m.dependencies, m.effect)) as any
887
-
888
- const total = Object.keys(filtered).length
889
-
890
- // TODO
891
- const accum: Record<string, any> = {}
892
-
893
- const router2: RRouter<
894
- Filtered,
895
- CTXMap,
896
- Context
897
- > = typedKeysOf(filtered).reduce((prev, cur) => {
898
- prev[cur] = Object.assign((it: any) => {
899
- accum[cur] = items[cur](it)
900
- if (Object.keys(accum).length === total) return accum
901
- return router2
902
- }, {
903
- raw: (it: any) => {
904
- accum[cur] = items[cur](it)
905
- if (Object.keys(accum).length === total) return accum
906
- return router2
907
- }
908
- })
909
- return prev
910
- }, {} as any)
911
-
912
- return Object.assign(effect, router2)
913
- }
914
-
915
- type HR<T> = T extends HttpRouter.HttpRouter<any, infer R> ? R : never
916
- type HE<T> = T extends HttpRouter.HttpRouter<infer E, any> ? E : never
917
-
918
- type RequestHandlersTest = {
919
- [key: string]: {
920
- Router: { router: Effect<HttpRouter.HttpRouter<any, any>, any, any> }
921
- routes: Layer.Layer<any, any, any>
922
- moduleName: string
923
- }
924
- }
925
- function matchAll<T extends RequestHandlersTest, A, E, R>(
926
- handlers: T,
927
- requestLayer: Layer.Layer<A, E, R>
928
- ) {
929
- const routers = typedValuesOf(handlers)
930
-
931
- const rootRouter = class extends HttpRouter.Tag("RootRouter")<
932
- "RootRouter",
933
- HR<Effect.Success<typeof handlers[keyof typeof handlers]["Router"]["router"]>>,
934
- HE<Effect.Success<typeof handlers[keyof typeof handlers]["Router"]["router"]>>
935
- >() {}
936
-
937
- const r = rootRouter
938
- .use((router) =>
939
- Effect.gen(function*() {
940
- for (const route of routers) {
941
- yield* router.mount(
942
- ("/rpc/" + route.moduleName) as any,
943
- yield* route
944
- .Router
945
- .router
946
- .pipe(Effect.map(HttpRouter.use(flow(Effect.provide(requestLayer))))) as any
947
- )
948
- }
949
- })
950
- )
951
- .pipe(Layer.provide(routers.map((r) => r.routes).flat() as unknown as NonEmptyArray<Layer.Layer.Any>))
952
-
953
- return {
954
- layer: r as Layer.Layer<
955
- never,
956
- Layer.Layer.Error<typeof handlers[keyof typeof handlers]["routes"]>,
957
- Layer.Layer.Context<typeof handlers[keyof typeof handlers]["routes"]>
958
- >,
959
- Router: rootRouter as any as HttpRouter.HttpRouter.TagClass<
960
- "RootRouter",
961
- "RootRouter",
962
- HE<Effect.Success<typeof handlers[keyof typeof handlers]["Router"]["router"]>>,
963
- R | Exclude<HR<Effect.Success<typeof handlers[keyof typeof handlers]["Router"]["router"]>>, A>
964
- >
965
- }
966
- }
967
-
968
- return { matchAll, matchFor }
969
- }
970
-
971
- export type MakeDeps<Make> = Make extends { readonly dependencies: ReadonlyArray<Layer.Layer.Any> }
972
- ? Make["dependencies"][number]
973
- : never
974
-
975
- export type MakeErrors<Make> = Make extends { readonly effect: Effect<any, infer E, any> } ? E
976
- : never
977
-
978
- export type MakeContext<Make> = Make extends { readonly effect: Effect<any, any, infer R> } ? R
979
- : never
980
-
981
- export type MakeHandlers<Make, Handlers extends Record<string, any>> = Make extends
982
- { readonly effect: Effect<{ ಠ_ಠ: { [K in keyof Handlers]: AHandler<Handlers[K]> } }, any, any> }
983
- ? Effect.Success<Make["effect"]> extends { ಠ_ಠ: any } ? Effect.Success<Make["effect"]>["ಠ_ಠ"] : never
984
- : never
985
-
986
- /**
987
- * @since 3.9.0
988
- */
989
- export type MakeDepsOut<Make> = Contravariant.Type<MakeDeps<Make>[Layer.LayerTypeId]["_ROut"]>