@effect-app/infra 1.28.3 → 1.29.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 (61) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/_cjs/api/{routing2 → routing}/DynamicMiddleware.cjs +1 -1
  3. package/_cjs/api/routing/DynamicMiddleware.cjs.map +1 -0
  4. package/_cjs/api/routing.cjs +135 -43
  5. package/_cjs/api/routing.cjs.map +1 -1
  6. package/dist/api/routing/DynamicMiddleware.d.ts.map +1 -0
  7. package/dist/api/routing/DynamicMiddleware.js +33 -0
  8. package/dist/api/routing.d.ts +100 -4
  9. package/dist/api/routing.d.ts.map +1 -1
  10. package/dist/api/routing.js +116 -9
  11. package/dist/services/Repository/ext.d.ts +4 -4
  12. package/package.json +9 -79
  13. package/src/api/{routing2 → routing}/DynamicMiddleware.ts +1 -1
  14. package/src/api/routing.ts +434 -8
  15. package/_cjs/api/routing/base.cjs +0 -135
  16. package/_cjs/api/routing/base.cjs.map +0 -1
  17. package/_cjs/api/routing/defaultErrorHandler.cjs +0 -62
  18. package/_cjs/api/routing/defaultErrorHandler.cjs.map +0 -1
  19. package/_cjs/api/routing/makeRequestHandler.cjs +0 -130
  20. package/_cjs/api/routing/makeRequestHandler.cjs.map +0 -1
  21. package/_cjs/api/routing/match.cjs +0 -40
  22. package/_cjs/api/routing/match.cjs.map +0 -1
  23. package/_cjs/api/routing/schema/routing.cjs +0 -136
  24. package/_cjs/api/routing/schema/routing.cjs.map +0 -1
  25. package/_cjs/api/routing2/DynamicMiddleware.cjs.map +0 -1
  26. package/_cjs/api/routing2.cjs +0 -142
  27. package/_cjs/api/routing2.cjs.map +0 -1
  28. package/_cjs/router.cjs +0 -170
  29. package/_cjs/router.cjs.map +0 -1
  30. package/dist/api/routing/base.d.ts +0 -97
  31. package/dist/api/routing/base.d.ts.map +0 -1
  32. package/dist/api/routing/base.js +0 -129
  33. package/dist/api/routing/defaultErrorHandler.d.ts +0 -19
  34. package/dist/api/routing/defaultErrorHandler.d.ts.map +0 -1
  35. package/dist/api/routing/defaultErrorHandler.js +0 -68
  36. package/dist/api/routing/makeRequestHandler.d.ts +0 -20
  37. package/dist/api/routing/makeRequestHandler.d.ts.map +0 -1
  38. package/dist/api/routing/makeRequestHandler.js +0 -151
  39. package/dist/api/routing/match.d.ts +0 -12
  40. package/dist/api/routing/match.d.ts.map +0 -1
  41. package/dist/api/routing/match.js +0 -27
  42. package/dist/api/routing/schema/routing.d.ts +0 -31
  43. package/dist/api/routing/schema/routing.d.ts.map +0 -1
  44. package/dist/api/routing/schema/routing.js +0 -123
  45. package/dist/api/routing2/DynamicMiddleware.d.ts.map +0 -1
  46. package/dist/api/routing2/DynamicMiddleware.js +0 -33
  47. package/dist/api/routing2.d.ts +0 -93
  48. package/dist/api/routing2.d.ts.map +0 -1
  49. package/dist/api/routing2.js +0 -117
  50. package/dist/router.d.ts +0 -91
  51. package/dist/router.d.ts.map +0 -1
  52. package/dist/router.js +0 -154
  53. package/src/api/routing/base.ts +0 -379
  54. package/src/api/routing/defaultErrorHandler.ts +0 -140
  55. package/src/api/routing/makeRequestHandler.ts +0 -343
  56. package/src/api/routing/match.ts +0 -128
  57. package/src/api/routing/schema/routing.ts +0 -237
  58. package/src/api/routing2.ts +0 -425
  59. package/src/api/writeDocs.ts.bak +0 -31
  60. package/src/router.ts +0 -619
  61. /package/dist/api/{routing2 → routing}/DynamicMiddleware.d.ts +0 -0
@@ -1,425 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
- /* eslint-disable @typescript-eslint/no-empty-object-type */
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
- /*
5
- TODO: Effect.retry(r2, optimisticConcurrencySchedule) / was for PATCH only
6
- TODO: uninteruptible commands! was for All except GET.
7
- */
8
- import { allLower, type EffectUnunified, type LowerServices } from "@effect-app/core/Effect"
9
- import { typedKeysOf } from "@effect-app/core/utils"
10
- import type { Compute } from "@effect-app/core/utils"
11
- import type { _E, _R, EffectDeps } from "@effect-app/infra/api/routing"
12
- import type * as HttpApp from "@effect/platform/HttpApp"
13
- import type { Rpc } from "@effect/rpc"
14
- import { RpcRouter } from "@effect/rpc"
15
- import type { S } from "effect-app"
16
- import { Chunk, Context, Effect, FiberRef, Predicate, Stream } from "effect-app"
17
- import type { HttpServerError } from "effect-app/http"
18
- import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
19
- import type { ContextMap, GetEffectContext, Middleware } from "./routing2/DynamicMiddleware.js"
20
- import { makeRpc } from "./routing2/DynamicMiddleware.js"
21
-
22
- /**
23
- * Plain jane JSON version
24
- */
25
- export const toHttpApp = <R extends RpcRouter.RpcRouter<any, any>>(self: R, options?: {
26
- readonly spanPrefix?: string
27
- }): HttpApp.Default<
28
- HttpServerError.RequestError,
29
- RpcRouter.RpcRouter.Context<R>
30
- > => {
31
- const handler = RpcRouter.toHandler(self, options)
32
- return Effect.withFiberRuntime((fiber) => {
33
- const context = fiber.getFiberRef(FiberRef.currentContext)
34
- const request = Context.unsafeGet(context, HttpServerRequest.HttpServerRequest)
35
- return Effect.flatMap(
36
- request.json,
37
- (_) =>
38
- handler(_).pipe(
39
- Stream.provideContext(context),
40
- Stream.runCollect,
41
- Effect.map((_) => Chunk.toReadonlyArray(_)),
42
- Effect.andThen((_) => HttpServerResponse.json(_)),
43
- Effect.orDie
44
- )
45
- )
46
- })
47
- }
48
-
49
- type GetRouteContext<CTXMap extends Record<string, ContextMap.Any>, T> =
50
- // & CTX
51
- // inverted
52
- & {
53
- [
54
- key in keyof CTXMap as CTXMap[key][3] extends true ? never
55
- : key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
56
- : never
57
- ]?: CTXMap[key][1]
58
- }
59
- & {
60
- [
61
- key in keyof CTXMap as CTXMap[key][3] extends true ? never
62
- : key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never
63
- : CTXMap[key][0]
64
- ]: CTXMap[key][1]
65
- }
66
- // normal
67
- & {
68
- [
69
- key in keyof CTXMap as CTXMap[key][3] extends false ? never
70
- : key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
71
- : never
72
- ]: CTXMap[key][1]
73
- }
74
- & {
75
- [
76
- key in keyof CTXMap as CTXMap[key][3] extends false ? never
77
- : key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never
78
- : CTXMap[key][0]
79
- ]?: CTXMap[key][1]
80
- }
81
-
82
- export interface Hint<Err extends string> {
83
- Err: Err
84
- }
85
-
86
- type HandleVoid<Expected, Actual, Result> = [Expected] extends [void]
87
- ? [Actual] extends [void] ? Result : Hint<"You're returning non void for a void Response, please fix">
88
- : Result
89
-
90
- type AnyRequestModule = S.Schema.Any & { success?: S.Schema.Any; failure?: S.Schema.Any }
91
-
92
- type GetSuccess<T> = T extends { success: S.Schema.Any } ? T["success"] : typeof S.Void
93
-
94
- type GetSuccessShape<Action extends { success?: S.Schema.Any }, RT extends "d" | "raw"> = RT extends "raw"
95
- ? S.Schema.Encoded<GetSuccess<Action>>
96
- : S.Schema.Type<GetSuccess<Action>>
97
- type GetFailure<T extends { failure?: S.Schema.Any }> = T["failure"] extends never ? typeof S.Never : T["failure"]
98
-
99
- export interface Handler<Action extends AnyRequestModule, RT extends "raw" | "d", A, E, R, Context> {
100
- new(): {}
101
- _tag: RT
102
- handler: (
103
- req: S.Schema.Type<Action>,
104
- ctx: Context
105
- ) => Effect<
106
- A,
107
- E,
108
- R
109
- >
110
- }
111
-
112
- // Separate "raw" vs "d" to verify A (Encoded for "raw" vs Type for "d")
113
- type AHandler<Action extends AnyRequestModule> =
114
- | Handler<
115
- Action,
116
- "raw",
117
- S.Schema.Encoded<GetSuccess<Action>>,
118
- S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
119
- any,
120
- { Response: any }
121
- >
122
- | Handler<
123
- Action,
124
- "d",
125
- S.Schema.Type<GetSuccess<Action>>,
126
- S.Schema.Type<GetFailure<Action>> | S.ParseResult.ParseError,
127
- any,
128
- { Response: any }
129
- >
130
-
131
- type Filter<T> = {
132
- [K in keyof T as T[K] extends S.Schema.All & { success: S.Schema.Any; failure: S.Schema.Any } ? K : never]: T[K]
133
- }
134
-
135
- interface ExtendedMiddleware<Context, CTXMap extends Record<string, ContextMap.Any>>
136
- extends Middleware<Context, CTXMap>
137
- {
138
- // TODO
139
- makeContext: Effect<
140
- { [K in keyof CTXMap as CTXMap[K][1] extends never ? never : CTXMap[K][0]]: CTXMap[K][1] },
141
- never,
142
- never
143
- >
144
- }
145
-
146
- export const makeRouter2 = <Context, CTXMap extends Record<string, ContextMap.Any>>(
147
- middleware: ExtendedMiddleware<Context, CTXMap>
148
- ) => {
149
- const rpc = makeRpc(middleware)
150
- function matchFor<Rsc extends Record<string, any> & { meta: { moduleName: string } }>(
151
- rsc: Rsc
152
- ) {
153
- const meta = (rsc as any).meta as { moduleName: string }
154
- if (!meta) throw new Error("Resource has no meta specified") // TODO: do something with moduleName+cur etc.
155
-
156
- type Filtered = Filter<Rsc>
157
- const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
158
- if (Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
159
- acc[cur as keyof Filtered] = rsc[cur]
160
- }
161
- return acc
162
- }, {} as Filtered)
163
-
164
- const matchWithServices = <Key extends keyof Filtered>(action: Key) => {
165
- return <
166
- SVC extends Record<
167
- string,
168
- Effect<any, any, any>
169
- >,
170
- R2,
171
- E,
172
- A
173
- >(
174
- services: SVC,
175
- f: (
176
- req: S.Schema.Type<Rsc[Key]>,
177
- ctx: Compute<
178
- LowerServices<EffectDeps<SVC>> & GetRouteContext<CTXMap, Rsc[Key]["config"]> & {
179
- Response: Rsc[Key]["success"]
180
- },
181
- "flat"
182
- >
183
- ) => Effect<A, E, R2>
184
- ) =>
185
- (req: any) =>
186
- Effect.andThen(
187
- Effect.all({ svc: allLower(services), ctx: middleware.makeContext }),
188
- ({ ctx, svc }) => f(req, { ...svc, ...ctx, Response: rsc[action].success } as any)
189
- )
190
- }
191
-
192
- type MatchWithServicesNew<RT extends "raw" | "d", Key extends keyof Rsc> = {
193
- <R2, E, A>(
194
- f: Effect<A, E, R2>
195
- ): HandleVoid<
196
- GetSuccessShape<Rsc[Key], RT>,
197
- A,
198
- Handler<
199
- Rsc[Key],
200
- RT,
201
- A,
202
- E,
203
- Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>,
204
- { Response: Rsc[Key]["success"] } //
205
- >
206
- >
207
-
208
- <R2, E, A>(
209
- f: (
210
- req: S.Schema.Type<Rsc[Key]>,
211
- ctx: GetRouteContext<CTXMap, Rsc[Key]["config"]> & { Response: Rsc[Key]["success"] }
212
- ) => Effect<A, E, R2>
213
- ): HandleVoid<
214
- GetSuccessShape<Rsc[Key], RT>,
215
- A,
216
- Handler<
217
- Rsc[Key],
218
- RT,
219
- A,
220
- E,
221
- Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>,
222
- { Response: Rsc[Key]["success"] } //
223
- >
224
- >
225
-
226
- <
227
- SVC extends Record<
228
- string,
229
- EffectUnunified<any, any, any>
230
- >,
231
- R2,
232
- E,
233
- A
234
- >(
235
- services: SVC,
236
- f: (
237
- req: S.Schema.Type<Rsc[Key]>,
238
- ctx: Compute<
239
- LowerServices<EffectDeps<SVC>> & GetRouteContext<CTXMap, Rsc[Key]["config"]> & {
240
- Response: Rsc[Key]["success"]
241
- },
242
- "flat"
243
- >
244
- ) => Effect<A, E, R2>
245
- ): HandleVoid<
246
- GetSuccessShape<Rsc[Key], RT>,
247
- A,
248
- Handler<
249
- Rsc[Key],
250
- RT,
251
- A,
252
- E,
253
- Exclude<R2, GetEffectContext<CTXMap, Rsc[Key]["config"]>>,
254
- { Response: Rsc[Key]["success"] } //
255
- >
256
- >
257
- }
258
-
259
- type Keys = keyof Filtered
260
-
261
- const controllers = <
262
- THandlers extends {
263
- // import to keep them separate via | for type checking!!
264
- [K in Keys]: AHandler<Rsc[K]>
265
- }
266
- >(
267
- controllers: THandlers
268
- ) => {
269
- const handlers = typedKeysOf(filtered).reduce(
270
- (acc, cur) => {
271
- ;(acc as any)[cur] = {
272
- h: controllers[cur as keyof typeof controllers].handler,
273
- Request: rsc[cur]
274
- }
275
-
276
- return acc
277
- },
278
- {} as {
279
- [K in Keys]: {
280
- h: (
281
- r: S.Schema.Type<Rsc[K]>
282
- ) => Effect<
283
- S.Schema.Type<GetSuccess<Rsc[K]>>,
284
- _E<ReturnType<THandlers[K]["handler"]>>,
285
- _R<ReturnType<THandlers[K]["handler"]>>
286
- >
287
- Request: Rsc[K]
288
- }
289
- }
290
- )
291
-
292
- const mapped = typedKeysOf(handlers).reduce((acc, cur) => {
293
- const handler = handlers[cur]
294
- const req = handler.Request
295
-
296
- acc[cur] = rpc.effect(req, handler.h as any, meta.moduleName) // TODO
297
- return acc
298
- }, {} as any) as {
299
- [K in Keys]: Rpc.Rpc<
300
- Rsc[K],
301
- _R<ReturnType<THandlers[K]["handler"]>>
302
- >
303
- }
304
-
305
- type RPCRouteR<T extends Rpc.Rpc<any, any>> = [T] extends [
306
- Rpc.Rpc<any, infer R>
307
- ] ? R
308
- : never
309
-
310
- type RPCRouteReq<T extends Rpc.Rpc<any, any>> = [T] extends [
311
- Rpc.Rpc<infer Req, any>
312
- ] ? Req
313
- : never
314
-
315
- const router = RpcRouter.make(...Object.values(mapped) as any) as RpcRouter.RpcRouter<
316
- RPCRouteReq<typeof mapped[keyof typeof mapped]>,
317
- RPCRouteR<typeof mapped[keyof typeof mapped]>
318
- >
319
-
320
- return HttpRouter.empty.pipe(
321
- HttpRouter.all(
322
- ("/rpc/" + rsc.meta.moduleName) as any,
323
- toHttpApp(router),
324
- // TODO: not queries.
325
- { uninterruptible: true }
326
- )
327
- )
328
- }
329
-
330
- const r = {
331
- controllers,
332
- ...typedKeysOf(filtered).reduce(
333
- (prev, cur) => {
334
- ;(prev as any)[cur] = (svcOrFnOrEffect: any, fnOrNone: any) => {
335
- const stack = new Error().stack?.split("\n").slice(2).join("\n")
336
- return Effect.isEffect(svcOrFnOrEffect)
337
- ? class {
338
- static stack = stack
339
- static _tag = "d"
340
- static handler = () => svcOrFnOrEffect
341
- }
342
- : typeof svcOrFnOrEffect === "function"
343
- ? class {
344
- static stack = stack
345
- static _tag = "d"
346
- static handler = (req: any) =>
347
- Effect.andThen(
348
- Effect.all({ ctx: middleware.makeContext }),
349
- ({ ctx }) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].success })
350
- )
351
- }
352
- : class {
353
- static stack = stack
354
- static _tag = "d"
355
- static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
356
- }
357
- }
358
- ;(prev as any)[(cur as any) + "Raw"] = (svcOrFnOrEffect: any, fnOrNone: any) => {
359
- const stack = new Error().stack?.split("\n").slice(2).join("\n")
360
- return Effect.isEffect(svcOrFnOrEffect)
361
- ? class {
362
- static stack = stack
363
- static _tag = "raw"
364
- static handler = () => svcOrFnOrEffect
365
- }
366
- : typeof svcOrFnOrEffect === "function"
367
- ? class {
368
- static stack = stack
369
- static _tag = "raw"
370
- static handler = (req: any, ctx: any) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].success })
371
- }
372
- : class {
373
- static stack = stack
374
- static _tag = "raw"
375
- static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
376
- }
377
- }
378
- return prev
379
- },
380
- {} as
381
- & {
382
- // use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
383
- /**
384
- * Requires the Type shape
385
- */
386
- [Key in keyof Filtered]: MatchWithServicesNew<"d", Key>
387
- }
388
- & {
389
- // use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
390
- /**
391
- * Requires the Encoded shape (e.g directly undecoded from DB, so that we don't do multiple Decode/Encode)
392
- */
393
- [Key in keyof Filtered as Key extends string ? `${Key}Raw` : never]: MatchWithServicesNew<"raw", Key>
394
- }
395
- )
396
- }
397
- return r
398
- }
399
-
400
- type RequestHandlersTest = {
401
- [key: string]: HttpRouter.HttpRouter<any, any>
402
- }
403
- function matchAll<T extends RequestHandlersTest>(handlers: T) {
404
- const r = typedKeysOf(handlers).reduce((acc, cur) => {
405
- return HttpRouter.concat(acc, handlers[cur] as any)
406
- }, HttpRouter.empty)
407
-
408
- type _RRouter<T extends HttpRouter.HttpRouter<any, any>> = [T] extends [
409
- HttpRouter.HttpRouter<any, infer R>
410
- ] ? R
411
- : never
412
-
413
- type _ERouter<T extends HttpRouter.HttpRouter<any, any>> = [T] extends [
414
- HttpRouter.HttpRouter<infer E, any>
415
- ] ? E
416
- : never
417
-
418
- return r as HttpRouter.HttpRouter<
419
- _ERouter<typeof handlers[keyof typeof handlers]>,
420
- _RRouter<typeof handlers[keyof typeof handlers]>
421
- >
422
- }
423
-
424
- return { matchAll, matchFor }
425
- }
@@ -1,31 +0,0 @@
1
- import { typedValuesOf } from "@effect-app/core/utils"
2
- import { writeTextFile } from "@effect-app/infra-adapters/fileUtil"
3
- import * as Plutus from "@effect-app/infra-adapters/Openapi/atlas-plutus"
4
- import { makeOpenApiSpecs } from "./express/makeOpenApiSpecs.js"
5
- import type { RouteDescriptorAny } from "./express/schema/routing.js"
6
-
7
- export function writeOpenapiDocs(rdescs: Record<string, Record<string, RouteDescriptorAny>>) {
8
- return writeOpenapiDocsI(
9
- typedValuesOf(rdescs)
10
- .reduce((prev, cur) => prev.concat(typedValuesOf(cur)), [] as readonly RouteDescriptorAny[])
11
- )
12
- }
13
-
14
- export function writeOpenapiDocsI(rdescs: readonly RouteDescriptorAny[]) {
15
- return makeOpenApiSpecs(
16
- rdescs.sortBy(Order.string.mapInput((a: RouteDescriptorAny) => a.path)),
17
- Plutus.info({
18
- title: "api",
19
- version: "X",
20
- pageTitle: "api"
21
- })
22
- )
23
- .map((_) => ({
24
- ..._,
25
- tags: [
26
- // add the tags here
27
- ]
28
- }))
29
- .flatMap((_) => writeTextFile("./openapi.json", JSON.stringify(_, undefined, 2)).orDie)
30
- .flatMap(() => InfraLogger.logDebug("OpenAPI spec written to './openapi.json'"))
31
- }