@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.
- package/CHANGELOG.md +19 -0
- package/_cjs/api/{routing2 → routing}/DynamicMiddleware.cjs +1 -1
- package/_cjs/api/routing/DynamicMiddleware.cjs.map +1 -0
- package/_cjs/api/routing.cjs +135 -43
- package/_cjs/api/routing.cjs.map +1 -1
- package/dist/api/routing/DynamicMiddleware.d.ts.map +1 -0
- package/dist/api/routing/DynamicMiddleware.js +33 -0
- package/dist/api/routing.d.ts +100 -4
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +116 -9
- package/dist/services/Repository/ext.d.ts +4 -4
- package/package.json +9 -79
- package/src/api/{routing2 → routing}/DynamicMiddleware.ts +1 -1
- package/src/api/routing.ts +434 -8
- package/_cjs/api/routing/base.cjs +0 -135
- package/_cjs/api/routing/base.cjs.map +0 -1
- package/_cjs/api/routing/defaultErrorHandler.cjs +0 -62
- package/_cjs/api/routing/defaultErrorHandler.cjs.map +0 -1
- package/_cjs/api/routing/makeRequestHandler.cjs +0 -130
- package/_cjs/api/routing/makeRequestHandler.cjs.map +0 -1
- package/_cjs/api/routing/match.cjs +0 -40
- package/_cjs/api/routing/match.cjs.map +0 -1
- package/_cjs/api/routing/schema/routing.cjs +0 -136
- package/_cjs/api/routing/schema/routing.cjs.map +0 -1
- package/_cjs/api/routing2/DynamicMiddleware.cjs.map +0 -1
- package/_cjs/api/routing2.cjs +0 -142
- package/_cjs/api/routing2.cjs.map +0 -1
- package/_cjs/router.cjs +0 -170
- package/_cjs/router.cjs.map +0 -1
- package/dist/api/routing/base.d.ts +0 -97
- package/dist/api/routing/base.d.ts.map +0 -1
- package/dist/api/routing/base.js +0 -129
- package/dist/api/routing/defaultErrorHandler.d.ts +0 -19
- package/dist/api/routing/defaultErrorHandler.d.ts.map +0 -1
- package/dist/api/routing/defaultErrorHandler.js +0 -68
- package/dist/api/routing/makeRequestHandler.d.ts +0 -20
- package/dist/api/routing/makeRequestHandler.d.ts.map +0 -1
- package/dist/api/routing/makeRequestHandler.js +0 -151
- package/dist/api/routing/match.d.ts +0 -12
- package/dist/api/routing/match.d.ts.map +0 -1
- package/dist/api/routing/match.js +0 -27
- package/dist/api/routing/schema/routing.d.ts +0 -31
- package/dist/api/routing/schema/routing.d.ts.map +0 -1
- package/dist/api/routing/schema/routing.js +0 -123
- package/dist/api/routing2/DynamicMiddleware.d.ts.map +0 -1
- package/dist/api/routing2/DynamicMiddleware.js +0 -33
- package/dist/api/routing2.d.ts +0 -93
- package/dist/api/routing2.d.ts.map +0 -1
- package/dist/api/routing2.js +0 -117
- package/dist/router.d.ts +0 -91
- package/dist/router.d.ts.map +0 -1
- package/dist/router.js +0 -154
- package/src/api/routing/base.ts +0 -379
- package/src/api/routing/defaultErrorHandler.ts +0 -140
- package/src/api/routing/makeRequestHandler.ts +0 -343
- package/src/api/routing/match.ts +0 -128
- package/src/api/routing/schema/routing.ts +0 -237
- package/src/api/routing2.ts +0 -425
- package/src/api/writeDocs.ts.bak +0 -31
- package/src/router.ts +0 -619
- /package/dist/api/{routing2 → routing}/DynamicMiddleware.d.ts +0 -0
package/src/router.ts
DELETED
|
@@ -1,619 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
-
import type { EffectUnunified, LowerServices } from "@effect-app/core/Effect"
|
|
5
|
-
import { allLower } from "@effect-app/core/Effect"
|
|
6
|
-
import { typedKeysOf } from "@effect-app/core/utils"
|
|
7
|
-
import type { Compute, EnforceNonEmptyRecord } from "@effect-app/core/utils"
|
|
8
|
-
import type {
|
|
9
|
-
_E,
|
|
10
|
-
_R,
|
|
11
|
-
EffectDeps,
|
|
12
|
-
JWTError,
|
|
13
|
-
Middleware,
|
|
14
|
-
ReqHandler,
|
|
15
|
-
RequestHandler
|
|
16
|
-
} from "@effect-app/infra/api/routing"
|
|
17
|
-
import { defaultErrorHandler, makeRequestHandler } from "@effect-app/infra/api/routing"
|
|
18
|
-
import type { Layer, Scope } from "effect-app"
|
|
19
|
-
import { Effect, Predicate, S } from "effect-app"
|
|
20
|
-
import type { SupportedErrors, ValidationError } from "effect-app/client/errors"
|
|
21
|
-
import { HttpRouter } from "effect-app/http"
|
|
22
|
-
import type { HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
23
|
-
import type { Struct } from "effect-app/schema"
|
|
24
|
-
import { REST } from "effect-app/schema"
|
|
25
|
-
import type {} from "@effect/schema/ParseResult"
|
|
26
|
-
|
|
27
|
-
export type RouteMatch<
|
|
28
|
-
R,
|
|
29
|
-
M,
|
|
30
|
-
// TODO: specific errors
|
|
31
|
-
// Err extends SupportedErrors | S.ParseResult.ParseError,
|
|
32
|
-
PR = never
|
|
33
|
-
> // RErr = never,
|
|
34
|
-
= HttpRouter.Route<never, Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>>
|
|
35
|
-
|
|
36
|
-
export interface Hint<Err extends string> {
|
|
37
|
-
Err: Err
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
type HandleVoid<Expected, Actual, Result> = [Expected] extends [void]
|
|
41
|
-
? [Actual] extends [void] ? Result : Hint<"You're returning non void for a void Response, please fix">
|
|
42
|
-
: Result
|
|
43
|
-
|
|
44
|
-
type AnyRequestModule = S.Schema.Any & { success?: S.Schema.Any; failure?: S.Schema.Any }
|
|
45
|
-
|
|
46
|
-
type GetSuccess<T> = T extends { success: S.Schema.Any } ? T["success"] : typeof S.Void
|
|
47
|
-
|
|
48
|
-
type GetSuccessShape<Action extends { success?: S.Schema.Any }, RT extends "d" | "raw"> = RT extends "raw"
|
|
49
|
-
? S.Schema.Encoded<GetSuccess<Action>>
|
|
50
|
-
: S.Schema.Type<GetSuccess<Action>>
|
|
51
|
-
type GetFailure<T extends { failure?: S.Schema.Any }> = T["failure"] extends never ? typeof S.Never : T["failure"]
|
|
52
|
-
|
|
53
|
-
export interface Handler<Action extends AnyRequestModule, RT extends "raw" | "d", A, E, R, Context> {
|
|
54
|
-
new(): {}
|
|
55
|
-
_tag: RT
|
|
56
|
-
handler: (
|
|
57
|
-
req: S.Schema.Type<Action>,
|
|
58
|
-
ctx: Context
|
|
59
|
-
) => Effect<
|
|
60
|
-
A,
|
|
61
|
-
E,
|
|
62
|
-
R
|
|
63
|
-
>
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Separate "raw" vs "d" to verify A (Encoded for "raw" vs Type for "d")
|
|
67
|
-
type AHandler<Action extends AnyRequestModule> =
|
|
68
|
-
| Handler<
|
|
69
|
-
Action,
|
|
70
|
-
"raw",
|
|
71
|
-
S.Schema.Encoded<GetSuccess<Action>>,
|
|
72
|
-
SupportedErrors | S.ParseResult.ParseError | S.Schema.Type<GetFailure<Action>>,
|
|
73
|
-
any,
|
|
74
|
-
any
|
|
75
|
-
>
|
|
76
|
-
| Handler<
|
|
77
|
-
Action,
|
|
78
|
-
"d",
|
|
79
|
-
S.Schema.Type<GetSuccess<Action>>,
|
|
80
|
-
SupportedErrors | S.ParseResult.ParseError | S.Schema.Type<GetFailure<Action>>,
|
|
81
|
-
any,
|
|
82
|
-
any
|
|
83
|
-
>
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Middleware is inactivate by default, the Key is optional in route context, and the service is optionally provided as Effect Context.
|
|
87
|
-
* Unless configured as `true`
|
|
88
|
-
*/
|
|
89
|
-
export type ContextMap<Key, Service> = [Key, Service, true]
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Middleware is active by default, and provides the Service at Key in route context, and the Service is provided as Effect Context.
|
|
93
|
-
* Unless omitted
|
|
94
|
-
*/
|
|
95
|
-
export type ContextMapInverted<Key, Service> = [Key, Service, false]
|
|
96
|
-
|
|
97
|
-
// For CTXMap, handled by `handleRequestEnv` middleware:
|
|
98
|
-
// ["configurationKey", ["contextKey", ServiceShape, defaultOffBoolean]]
|
|
99
|
-
// defaultOffBoolean:
|
|
100
|
-
// false means: if not configured, or set to false, the item is considered active.
|
|
101
|
-
// true means: if configured as true, the item is considered active.
|
|
102
|
-
// not active means the service is not in the context, and in route context is marked as optional.
|
|
103
|
-
export const makeRouter = <CTX, CTXMap extends Record<string, [string, any, boolean]>>(
|
|
104
|
-
handleRequestEnv: any /* Middleware */
|
|
105
|
-
) => {
|
|
106
|
-
type GetRouteContext<T> =
|
|
107
|
-
& CTX
|
|
108
|
-
// inverted
|
|
109
|
-
& {
|
|
110
|
-
[
|
|
111
|
-
key in keyof CTXMap as CTXMap[key][2] extends true ? never
|
|
112
|
-
: key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
|
|
113
|
-
: never
|
|
114
|
-
]?: CTXMap[key][1]
|
|
115
|
-
}
|
|
116
|
-
& {
|
|
117
|
-
[
|
|
118
|
-
key in keyof CTXMap as CTXMap[key][2] extends true ? never
|
|
119
|
-
: key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never
|
|
120
|
-
: CTXMap[key][0]
|
|
121
|
-
]: CTXMap[key][1]
|
|
122
|
-
}
|
|
123
|
-
// normal
|
|
124
|
-
& {
|
|
125
|
-
[
|
|
126
|
-
key in keyof CTXMap as CTXMap[key][2] extends false ? never
|
|
127
|
-
: key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
|
|
128
|
-
: never
|
|
129
|
-
]: CTXMap[key][1]
|
|
130
|
-
}
|
|
131
|
-
& {
|
|
132
|
-
[
|
|
133
|
-
key in keyof CTXMap as CTXMap[key][2] extends false ? never
|
|
134
|
-
: key extends keyof T ? T[key] extends false ? CTXMap[key][0] : never
|
|
135
|
-
: CTXMap[key][0]
|
|
136
|
-
]?: CTXMap[key][1]
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
type Values<T extends Record<any, any>> = T[keyof T]
|
|
140
|
-
|
|
141
|
-
type GetEffectContext<T> = Values<
|
|
142
|
-
// inverted
|
|
143
|
-
& {
|
|
144
|
-
[
|
|
145
|
-
key in keyof CTXMap as CTXMap[key][2] extends true ? never
|
|
146
|
-
: key extends keyof T ? T[key] extends true ? never : CTXMap[key][0]
|
|
147
|
-
: CTXMap[key][0]
|
|
148
|
-
]: // TODO: or as an Optional available?
|
|
149
|
-
CTXMap[key][1]
|
|
150
|
-
}
|
|
151
|
-
// normal
|
|
152
|
-
& {
|
|
153
|
-
[
|
|
154
|
-
key in keyof CTXMap as CTXMap[key][2] extends false ? never
|
|
155
|
-
: key extends keyof T ? T[key] extends true ? CTXMap[key][0] : never
|
|
156
|
-
: never
|
|
157
|
-
]: // TODO: or as an Optional available?
|
|
158
|
-
CTXMap[key][1]
|
|
159
|
-
}
|
|
160
|
-
>
|
|
161
|
-
|
|
162
|
-
function match<
|
|
163
|
-
R,
|
|
164
|
-
M,
|
|
165
|
-
PathA extends Struct.Fields,
|
|
166
|
-
CookieA extends Struct.Fields,
|
|
167
|
-
QueryA extends Struct.Fields,
|
|
168
|
-
BodyA extends Struct.Fields,
|
|
169
|
-
HeaderA extends Struct.Fields,
|
|
170
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
171
|
-
ResA extends Struct.Fields,
|
|
172
|
-
ResE,
|
|
173
|
-
MiddlewareE,
|
|
174
|
-
PPath extends `/${string}`,
|
|
175
|
-
R2,
|
|
176
|
-
PR,
|
|
177
|
-
RErr,
|
|
178
|
-
CTX,
|
|
179
|
-
Context,
|
|
180
|
-
Config
|
|
181
|
-
>(
|
|
182
|
-
requestHandler: RequestHandler<
|
|
183
|
-
R,
|
|
184
|
-
M,
|
|
185
|
-
PathA,
|
|
186
|
-
CookieA,
|
|
187
|
-
QueryA,
|
|
188
|
-
BodyA,
|
|
189
|
-
HeaderA,
|
|
190
|
-
ReqA,
|
|
191
|
-
ResA,
|
|
192
|
-
ResE,
|
|
193
|
-
PPath,
|
|
194
|
-
CTX,
|
|
195
|
-
Context,
|
|
196
|
-
Config
|
|
197
|
-
>,
|
|
198
|
-
errorHandler: <R>(
|
|
199
|
-
req: HttpServerRequest.HttpServerRequest,
|
|
200
|
-
res: HttpServerResponse.HttpServerResponse,
|
|
201
|
-
r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | MiddlewareE | ResE, R>
|
|
202
|
-
) => Effect<
|
|
203
|
-
HttpServerResponse.HttpServerResponse,
|
|
204
|
-
never,
|
|
205
|
-
Exclude<RErr | R, HttpServerRequest.HttpServerRequest | HttpRouter.RouteContext | Scope>
|
|
206
|
-
>,
|
|
207
|
-
middleware?: Middleware<
|
|
208
|
-
R,
|
|
209
|
-
M,
|
|
210
|
-
PathA,
|
|
211
|
-
CookieA,
|
|
212
|
-
QueryA,
|
|
213
|
-
BodyA,
|
|
214
|
-
HeaderA,
|
|
215
|
-
ReqA,
|
|
216
|
-
ResA,
|
|
217
|
-
ResE,
|
|
218
|
-
MiddlewareE,
|
|
219
|
-
PPath,
|
|
220
|
-
R2,
|
|
221
|
-
PR,
|
|
222
|
-
CTX,
|
|
223
|
-
Context,
|
|
224
|
-
Config
|
|
225
|
-
>
|
|
226
|
-
) {
|
|
227
|
-
let middlewareLayer: Layer<PR, MiddlewareE, R2> | undefined = undefined
|
|
228
|
-
if (middleware) {
|
|
229
|
-
const { handler, makeRequestLayer } = middleware(requestHandler)
|
|
230
|
-
requestHandler = handler as any // todo
|
|
231
|
-
middlewareLayer = makeRequestLayer
|
|
232
|
-
}
|
|
233
|
-
// const rdesc = yield* RouteDescriptors.flatMap((_) => _.get)
|
|
234
|
-
|
|
235
|
-
const handler = makeRequestHandler<
|
|
236
|
-
R,
|
|
237
|
-
M,
|
|
238
|
-
PathA,
|
|
239
|
-
CookieA,
|
|
240
|
-
QueryA,
|
|
241
|
-
BodyA,
|
|
242
|
-
HeaderA,
|
|
243
|
-
ReqA,
|
|
244
|
-
ResA,
|
|
245
|
-
ResE,
|
|
246
|
-
MiddlewareE,
|
|
247
|
-
R2,
|
|
248
|
-
PR,
|
|
249
|
-
RErr,
|
|
250
|
-
PPath,
|
|
251
|
-
Config
|
|
252
|
-
>(
|
|
253
|
-
requestHandler as any, // one argument if no middleware, 2 if has middleware. TODO: clean this shit up
|
|
254
|
-
errorHandler,
|
|
255
|
-
middlewareLayer
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
const route = HttpRouter.makeRoute(
|
|
259
|
-
requestHandler.Request.method,
|
|
260
|
-
requestHandler.Request.path,
|
|
261
|
-
handler.pipe(
|
|
262
|
-
Effect.withSpan("Request." + requestHandler.name, { captureStackTrace: () => (requestHandler as any).stack })
|
|
263
|
-
)
|
|
264
|
-
)
|
|
265
|
-
// TODO
|
|
266
|
-
// rdesc.push(makeRouteDescriptor(
|
|
267
|
-
// requestHandler.Request.path,
|
|
268
|
-
// requestHandler.Request.method,
|
|
269
|
-
// requestHandler
|
|
270
|
-
// ))
|
|
271
|
-
return route
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function handle<
|
|
275
|
-
ReqSchema extends AnyRequestModule
|
|
276
|
-
>(
|
|
277
|
-
_: ReqSchema & { ResponseOpenApi?: any },
|
|
278
|
-
name: string,
|
|
279
|
-
adaptResponse?: any
|
|
280
|
-
) {
|
|
281
|
-
const Request = S.REST.extractRequest(_)
|
|
282
|
-
const Response = S.REST.extractResponse(_)
|
|
283
|
-
type ResSchema = GetSuccess<ReqSchema>
|
|
284
|
-
type Req = S.Schema.Type<ReqSchema>
|
|
285
|
-
type Res = S.Schema.Type<ResSchema> // TODO: depends on raw
|
|
286
|
-
|
|
287
|
-
return <R, E>(
|
|
288
|
-
h: { _tag: "raw" | "d"; handler: (r: Req) => Effect<Res, E, R>; stack?: string }
|
|
289
|
-
) => ({
|
|
290
|
-
adaptResponse,
|
|
291
|
-
stack: h.stack,
|
|
292
|
-
h: h.handler,
|
|
293
|
-
name,
|
|
294
|
-
Request,
|
|
295
|
-
Response,
|
|
296
|
-
ResponseOpenApi: _.ResponseOpenApi ?? Response,
|
|
297
|
-
Context: null as any,
|
|
298
|
-
CTX: null as any,
|
|
299
|
-
rt: h._tag
|
|
300
|
-
} as ReqHandler<
|
|
301
|
-
Req,
|
|
302
|
-
R,
|
|
303
|
-
E,
|
|
304
|
-
Res,
|
|
305
|
-
ReqSchema,
|
|
306
|
-
ResSchema,
|
|
307
|
-
GetRouteContext<Req>,
|
|
308
|
-
GetEffectContext<Req>
|
|
309
|
-
>)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function matchFor<Rsc extends Record<string, any>>(
|
|
313
|
-
rsc: Rsc
|
|
314
|
-
) {
|
|
315
|
-
type Filtered = {
|
|
316
|
-
[K in keyof Rsc as Rsc[K] extends { Response: any } ? K : never]: Rsc[K] extends { Response: any } ? Rsc[K]
|
|
317
|
-
: never
|
|
318
|
-
}
|
|
319
|
-
const filtered = typedKeysOf(rsc).reduce((acc, cur) => {
|
|
320
|
-
if (Predicate.isObject(rsc[cur]) && rsc[cur].Request) {
|
|
321
|
-
acc[cur as keyof Filtered] = rsc[cur]
|
|
322
|
-
}
|
|
323
|
-
return acc
|
|
324
|
-
}, {} as Filtered)
|
|
325
|
-
|
|
326
|
-
const matchWithServices = <Key extends keyof Filtered>(action: Key) => {
|
|
327
|
-
return <
|
|
328
|
-
SVC extends Record<
|
|
329
|
-
string,
|
|
330
|
-
Effect<any, any, any>
|
|
331
|
-
>,
|
|
332
|
-
R2,
|
|
333
|
-
E,
|
|
334
|
-
A
|
|
335
|
-
>(
|
|
336
|
-
services: SVC,
|
|
337
|
-
f: (
|
|
338
|
-
req: S.Schema.Type<Rsc[Key]>,
|
|
339
|
-
ctx: Compute<
|
|
340
|
-
LowerServices<EffectDeps<SVC>> & GetRouteContext<Rsc[Key]>,
|
|
341
|
-
"flat"
|
|
342
|
-
>
|
|
343
|
-
) => Effect<A, E, R2>
|
|
344
|
-
) =>
|
|
345
|
-
(req: any, ctx: any) =>
|
|
346
|
-
Effect.andThen(allLower(services), (svc2) => f(req, { ...ctx, ...svc2, Response: rsc[action].Response }))
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
type MatchWithServicesNew<RT extends "raw" | "d", Key extends keyof Rsc> = {
|
|
350
|
-
<R2, E, A>(
|
|
351
|
-
f: Effect<A, E, R2>
|
|
352
|
-
): HandleVoid<
|
|
353
|
-
GetSuccessShape<Rsc[Key], RT>,
|
|
354
|
-
A,
|
|
355
|
-
Handler<
|
|
356
|
-
Rsc[Key],
|
|
357
|
-
RT,
|
|
358
|
-
A,
|
|
359
|
-
E,
|
|
360
|
-
R2,
|
|
361
|
-
GetRouteContext<Rsc[Key]>
|
|
362
|
-
>
|
|
363
|
-
>
|
|
364
|
-
|
|
365
|
-
<R2, E, A>(
|
|
366
|
-
f: (
|
|
367
|
-
req: S.Schema.Type<Rsc[Key]>,
|
|
368
|
-
ctx: GetRouteContext<Rsc[Key]> & Pick<Rsc[Key], "Response">
|
|
369
|
-
) => Effect<A, E, R2>
|
|
370
|
-
): HandleVoid<
|
|
371
|
-
GetSuccessShape<Rsc[Key], RT>,
|
|
372
|
-
A,
|
|
373
|
-
Handler<
|
|
374
|
-
Rsc[Key],
|
|
375
|
-
RT,
|
|
376
|
-
A,
|
|
377
|
-
E,
|
|
378
|
-
R2,
|
|
379
|
-
GetRouteContext<Rsc[Key]>
|
|
380
|
-
>
|
|
381
|
-
>
|
|
382
|
-
|
|
383
|
-
<
|
|
384
|
-
SVC extends Record<
|
|
385
|
-
string,
|
|
386
|
-
EffectUnunified<any, any, any>
|
|
387
|
-
>,
|
|
388
|
-
R2,
|
|
389
|
-
E,
|
|
390
|
-
A
|
|
391
|
-
>(
|
|
392
|
-
services: SVC,
|
|
393
|
-
f: (
|
|
394
|
-
req: S.Schema.Type<Rsc[Key]>,
|
|
395
|
-
ctx: Compute<
|
|
396
|
-
LowerServices<EffectDeps<SVC>> & GetRouteContext<Rsc[Key]> & Pick<Rsc[Key], "Response">,
|
|
397
|
-
"flat"
|
|
398
|
-
>
|
|
399
|
-
) => Effect<A, E, R2>
|
|
400
|
-
): HandleVoid<
|
|
401
|
-
GetSuccessShape<Rsc[Key], RT>,
|
|
402
|
-
A,
|
|
403
|
-
Handler<
|
|
404
|
-
Rsc[Key],
|
|
405
|
-
RT,
|
|
406
|
-
A,
|
|
407
|
-
E,
|
|
408
|
-
R2,
|
|
409
|
-
GetRouteContext<Rsc[Key]>
|
|
410
|
-
>
|
|
411
|
-
>
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
type Keys = keyof Filtered
|
|
415
|
-
|
|
416
|
-
const controllers = <
|
|
417
|
-
THandlers extends {
|
|
418
|
-
// import to keep them separate via | for type checking!!
|
|
419
|
-
[K in Keys]: AHandler<Rsc[K]>
|
|
420
|
-
}
|
|
421
|
-
>(
|
|
422
|
-
controllers: THandlers
|
|
423
|
-
) => {
|
|
424
|
-
const handlers = typedKeysOf(filtered).reduce(
|
|
425
|
-
(acc, cur) => {
|
|
426
|
-
if (cur === "meta") return acc
|
|
427
|
-
const m = (rsc as any).meta as { moduleName: string }
|
|
428
|
-
if (!m) throw new Error("Resource has no meta specified")
|
|
429
|
-
;(acc as any)[cur] = handle(
|
|
430
|
-
rsc[cur],
|
|
431
|
-
m.moduleName + "." + (cur as string)
|
|
432
|
-
)(controllers[cur as keyof typeof controllers] as any)
|
|
433
|
-
return acc
|
|
434
|
-
},
|
|
435
|
-
{} as {
|
|
436
|
-
[K in Keys]: ReqHandler<
|
|
437
|
-
S.Schema.Type<Rsc[K]>,
|
|
438
|
-
_R<ReturnType<THandlers[K]["handler"]>>,
|
|
439
|
-
_E<ReturnType<THandlers[K]["handler"]>>,
|
|
440
|
-
S.Schema.Type<GetSuccess<Rsc[K]>>, // TODO: GetSuccessShape, but requires RT
|
|
441
|
-
Rsc[K],
|
|
442
|
-
GetSuccess<Rsc[K]>,
|
|
443
|
-
GetRouteContext<Rsc[K]>,
|
|
444
|
-
GetEffectContext<Rsc[K]>
|
|
445
|
-
>
|
|
446
|
-
}
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
const mapped = typedKeysOf(handlers).reduce((acc, cur) => {
|
|
450
|
-
const handler = handlers[cur]
|
|
451
|
-
const req = handler.Request
|
|
452
|
-
|
|
453
|
-
class Request extends (req as any) {
|
|
454
|
-
static path = "/" + handler.name + (req.path === "/" ? "" : req.path)
|
|
455
|
-
static method = req.method === "AUTO"
|
|
456
|
-
? REST.determineMethod(handler.name.split(".")[1]!, req)
|
|
457
|
-
: req.method
|
|
458
|
-
}
|
|
459
|
-
if (req.method === "AUTO") {
|
|
460
|
-
Object.assign(Request, {
|
|
461
|
-
[Request.method === "GET" || Request.method === "DELETE" ? "Query" : "Body"]: req.Auto
|
|
462
|
-
})
|
|
463
|
-
}
|
|
464
|
-
Object.assign(handler, { Request })
|
|
465
|
-
acc[cur] = match(
|
|
466
|
-
handler as any,
|
|
467
|
-
errorHandler(req),
|
|
468
|
-
handleRequestEnv // TODO
|
|
469
|
-
)
|
|
470
|
-
return acc
|
|
471
|
-
}, {} as any) as {
|
|
472
|
-
[K in Keys]: RouteMatch<
|
|
473
|
-
_R<ReturnType<THandlers[K]["handler"]>>,
|
|
474
|
-
Rsc[K],
|
|
475
|
-
// _E<ReturnType<THandlers[K]["handler"]>>,
|
|
476
|
-
GetEffectContext<Rsc[K]>
|
|
477
|
-
>
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
type _RRoute<T extends HttpRouter.Route<any, any>> = [T] extends [
|
|
481
|
-
HttpRouter.Route<any, infer R>
|
|
482
|
-
] ? R
|
|
483
|
-
: never
|
|
484
|
-
|
|
485
|
-
type _ERoute<T extends HttpRouter.Route<any, any>> = [T] extends [
|
|
486
|
-
HttpRouter.Route<infer E, any>
|
|
487
|
-
] ? E
|
|
488
|
-
: never
|
|
489
|
-
|
|
490
|
-
return HttpRouter.fromIterable(Object.values(mapped)) as HttpRouter.HttpRouter<
|
|
491
|
-
_ERoute<typeof mapped[keyof typeof mapped]>,
|
|
492
|
-
_RRoute<typeof mapped[keyof typeof mapped]>
|
|
493
|
-
>
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const r = {
|
|
497
|
-
controllers,
|
|
498
|
-
...typedKeysOf(filtered).reduce(
|
|
499
|
-
(prev, cur) => {
|
|
500
|
-
;(prev as any)[cur] = (svcOrFnOrEffect: any, fnOrNone: any) => {
|
|
501
|
-
const stack = new Error().stack?.split("\n").slice(2).join("\n")
|
|
502
|
-
return Effect.isEffect(svcOrFnOrEffect)
|
|
503
|
-
? class {
|
|
504
|
-
static stack = stack
|
|
505
|
-
static _tag = "d"
|
|
506
|
-
static handler = () => svcOrFnOrEffect
|
|
507
|
-
}
|
|
508
|
-
: typeof svcOrFnOrEffect === "function"
|
|
509
|
-
? class {
|
|
510
|
-
static stack = stack
|
|
511
|
-
static _tag = "d"
|
|
512
|
-
static handler = (req: any, ctx: any) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].Response })
|
|
513
|
-
}
|
|
514
|
-
: class {
|
|
515
|
-
static stack = stack
|
|
516
|
-
static _tag = "d"
|
|
517
|
-
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
;(prev as any)[(cur as any) + "Raw"] = (svcOrFnOrEffect: any, fnOrNone: any) => {
|
|
521
|
-
const stack = new Error().stack?.split("\n").slice(2).join("\n")
|
|
522
|
-
return Effect.isEffect(svcOrFnOrEffect)
|
|
523
|
-
? class {
|
|
524
|
-
static stack = stack
|
|
525
|
-
static _tag = "raw"
|
|
526
|
-
static handler = () => svcOrFnOrEffect
|
|
527
|
-
}
|
|
528
|
-
: typeof svcOrFnOrEffect === "function"
|
|
529
|
-
? class {
|
|
530
|
-
static stack = stack
|
|
531
|
-
static _tag = "raw"
|
|
532
|
-
static handler = (req: any, ctx: any) => svcOrFnOrEffect(req, { ...ctx, Response: rsc[cur].Response })
|
|
533
|
-
}
|
|
534
|
-
: class {
|
|
535
|
-
static stack = stack
|
|
536
|
-
static _tag = "raw"
|
|
537
|
-
static handler = matchWithServices(cur)(svcOrFnOrEffect, fnOrNone)
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
return prev
|
|
541
|
-
},
|
|
542
|
-
{} as
|
|
543
|
-
& {
|
|
544
|
-
// use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
|
|
545
|
-
/**
|
|
546
|
-
* Requires the Type shape
|
|
547
|
-
*/
|
|
548
|
-
[Key in keyof Filtered]: MatchWithServicesNew<"d", Key>
|
|
549
|
-
}
|
|
550
|
-
& {
|
|
551
|
-
// use Rsc as Key over using Keys, so that the Go To on X.Action remain in tact in Controllers files
|
|
552
|
-
/**
|
|
553
|
-
* Requires the Encoded shape (e.g directly undecoded from DB, so that we don't do multiple Decode/Encode)
|
|
554
|
-
*/
|
|
555
|
-
[Key in keyof Filtered as Key extends string ? `${Key}Raw` : never]: MatchWithServicesNew<"raw", Key>
|
|
556
|
-
}
|
|
557
|
-
)
|
|
558
|
-
}
|
|
559
|
-
return r
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const errorHandler = (resourceRequest: { failure?: S.Schema.AnyNoContext }) => {
|
|
563
|
-
return <R>(
|
|
564
|
-
req: HttpServerRequest.HttpServerRequest,
|
|
565
|
-
res: HttpServerResponse.HttpServerResponse,
|
|
566
|
-
r2: Effect<HttpServerResponse.HttpServerResponse, SupportedErrors | JWTError | S.ParseResult.ParseError, R>
|
|
567
|
-
) => defaultErrorHandler(req, res, Effect.catchTag(r2, "ParseError", (_) => Effect.die(_)), resourceRequest.failure)
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Gather all handlers of a module and attach them to the Server.
|
|
572
|
-
* If no `allowAnonymous` flag is on the Request, will require a valid authenticated user.
|
|
573
|
-
*/
|
|
574
|
-
|
|
575
|
-
function matchAll<T extends RequestHandlersTest>(handlers: T) {
|
|
576
|
-
const r = typedKeysOf(handlers).reduce((acc, cur) => {
|
|
577
|
-
return HttpRouter.concat(acc, handlers[cur] as any)
|
|
578
|
-
}, HttpRouter.empty)
|
|
579
|
-
|
|
580
|
-
type _RRouter<T extends HttpRouter.HttpRouter<any, any>> = [T] extends [
|
|
581
|
-
HttpRouter.HttpRouter<any, infer R>
|
|
582
|
-
] ? R
|
|
583
|
-
: never
|
|
584
|
-
|
|
585
|
-
type _ERouter<T extends HttpRouter.HttpRouter<any, any>> = [T] extends [
|
|
586
|
-
HttpRouter.HttpRouter<infer E, any>
|
|
587
|
-
] ? E
|
|
588
|
-
: never
|
|
589
|
-
|
|
590
|
-
return r as HttpRouter.HttpRouter<
|
|
591
|
-
_ERouter<typeof handlers[keyof typeof handlers]>,
|
|
592
|
-
_RRouter<typeof handlers[keyof typeof handlers]>
|
|
593
|
-
>
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// type SupportedRequestHandler = RequestHandler<
|
|
597
|
-
// any,
|
|
598
|
-
// any,
|
|
599
|
-
// any,
|
|
600
|
-
// any,
|
|
601
|
-
// any,
|
|
602
|
-
// any,
|
|
603
|
-
// any,
|
|
604
|
-
// any,
|
|
605
|
-
// any,
|
|
606
|
-
// SupportedErrors | S.ParseResult.ParseError,
|
|
607
|
-
// any,
|
|
608
|
-
// any,
|
|
609
|
-
// any,
|
|
610
|
-
// any
|
|
611
|
-
// >
|
|
612
|
-
|
|
613
|
-
// type RequestHandlers = { [key: string]: SupportedRequestHandler }
|
|
614
|
-
type RequestHandlersTest = {
|
|
615
|
-
[key: string]: HttpRouter.HttpRouter<any, any>
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
return { matchFor, matchAll }
|
|
619
|
-
}
|
|
File without changes
|