@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
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/* eslint-disable @typescript-eslint/ban-types */
|
|
3
|
-
import type { EnforceNonEmptyRecord } from "@effect-app/core/utils"
|
|
4
|
-
import { copy, pretty } from "@effect-app/core/utils"
|
|
5
|
-
import { RequestFiberSet } from "@effect-app/infra-adapters/RequestFiberSet"
|
|
6
|
-
import { snipString } from "@effect-app/infra/api/util"
|
|
7
|
-
import { reportError } from "@effect-app/infra/errorReporter"
|
|
8
|
-
import type { ValidationError } from "@effect-app/infra/errors"
|
|
9
|
-
import type { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer"
|
|
10
|
-
import type { ContextMapContainer } from "@effect-app/infra/services/Store/ContextMapContainer"
|
|
11
|
-
import type { Struct } from "@effect/schema/Schema"
|
|
12
|
-
import type { Layer } from "effect-app"
|
|
13
|
-
import { Console, Effect, FiberRef, Option, S } from "effect-app"
|
|
14
|
-
import type { HttpServerError } from "effect-app/http"
|
|
15
|
-
import { HttpBody, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
16
|
-
import { NonEmptyString255 } from "effect-app/schema"
|
|
17
|
-
import type { REST } from "effect-app/schema"
|
|
18
|
-
import { InfraLogger } from "../../logger.js"
|
|
19
|
-
import { updateRequestContext } from "../setupRequest.js"
|
|
20
|
-
import { makeRequestParsers, parseRequestParams } from "./base.js"
|
|
21
|
-
import type { RequestHandler, RequestHandlerBase } from "./base.js"
|
|
22
|
-
|
|
23
|
-
export const RequestSettings = FiberRef.unsafeMake({
|
|
24
|
-
verbose: false
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
export type Middleware<
|
|
28
|
-
R,
|
|
29
|
-
M,
|
|
30
|
-
PathA extends Struct.Fields,
|
|
31
|
-
CookieA extends Struct.Fields,
|
|
32
|
-
QueryA extends Struct.Fields,
|
|
33
|
-
BodyA extends Struct.Fields,
|
|
34
|
-
HeaderA extends Struct.Fields,
|
|
35
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
36
|
-
ResA extends Struct.Fields,
|
|
37
|
-
ResE,
|
|
38
|
-
MiddlewareE,
|
|
39
|
-
PPath extends `/${string}`,
|
|
40
|
-
R2,
|
|
41
|
-
PR,
|
|
42
|
-
CTX,
|
|
43
|
-
Context,
|
|
44
|
-
Config
|
|
45
|
-
> = (
|
|
46
|
-
handler: RequestHandler<
|
|
47
|
-
R,
|
|
48
|
-
M,
|
|
49
|
-
PathA,
|
|
50
|
-
CookieA,
|
|
51
|
-
QueryA,
|
|
52
|
-
BodyA,
|
|
53
|
-
HeaderA,
|
|
54
|
-
ReqA,
|
|
55
|
-
ResA,
|
|
56
|
-
ResE,
|
|
57
|
-
PPath,
|
|
58
|
-
CTX,
|
|
59
|
-
Context,
|
|
60
|
-
Config
|
|
61
|
-
>
|
|
62
|
-
) => {
|
|
63
|
-
handler: RequestHandler<
|
|
64
|
-
R2 | PR | RequestContextContainer | ContextMapContainer | RequestFiberSet,
|
|
65
|
-
M,
|
|
66
|
-
PathA,
|
|
67
|
-
CookieA,
|
|
68
|
-
QueryA,
|
|
69
|
-
BodyA,
|
|
70
|
-
HeaderA,
|
|
71
|
-
ReqA,
|
|
72
|
-
ResA,
|
|
73
|
-
ResE,
|
|
74
|
-
PPath,
|
|
75
|
-
CTX,
|
|
76
|
-
Context,
|
|
77
|
-
Config
|
|
78
|
-
>
|
|
79
|
-
makeRequestLayer: Layer<PR, MiddlewareE, R2>
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function makeRequestHandler<
|
|
83
|
-
R,
|
|
84
|
-
M,
|
|
85
|
-
PathA extends Struct.Fields,
|
|
86
|
-
CookieA extends Struct.Fields,
|
|
87
|
-
QueryA extends Struct.Fields,
|
|
88
|
-
BodyA extends Struct.Fields,
|
|
89
|
-
HeaderA extends Struct.Fields,
|
|
90
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
91
|
-
ResA extends Struct.Fields,
|
|
92
|
-
ResE,
|
|
93
|
-
MiddlewareE,
|
|
94
|
-
R2,
|
|
95
|
-
PR,
|
|
96
|
-
RErr,
|
|
97
|
-
PPath extends `/${string}`,
|
|
98
|
-
Config
|
|
99
|
-
>(
|
|
100
|
-
handler: RequestHandlerBase<
|
|
101
|
-
R,
|
|
102
|
-
M,
|
|
103
|
-
PathA,
|
|
104
|
-
CookieA,
|
|
105
|
-
QueryA,
|
|
106
|
-
BodyA,
|
|
107
|
-
HeaderA,
|
|
108
|
-
ReqA,
|
|
109
|
-
ResA,
|
|
110
|
-
ResE,
|
|
111
|
-
PPath,
|
|
112
|
-
Config
|
|
113
|
-
>,
|
|
114
|
-
errorHandler: <R>(
|
|
115
|
-
req: HttpServerRequest.HttpServerRequest,
|
|
116
|
-
res: HttpServerResponse.HttpServerResponse,
|
|
117
|
-
r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | ResE | MiddlewareE, R>
|
|
118
|
-
) => Effect<HttpServerResponse.HttpServerResponse, never, RErr | R>,
|
|
119
|
-
middlewareLayer?: Layer<PR, MiddlewareE, R2>
|
|
120
|
-
): Effect<
|
|
121
|
-
HttpServerResponse.HttpServerResponse,
|
|
122
|
-
HttpServerError.RequestError,
|
|
123
|
-
| HttpRouter.RouteContext
|
|
124
|
-
| HttpServerRequest.ParsedSearchParams
|
|
125
|
-
| HttpServerRequest.HttpServerRequest
|
|
126
|
-
| RequestContextContainer
|
|
127
|
-
| ContextMapContainer
|
|
128
|
-
| RequestFiberSet
|
|
129
|
-
| RErr
|
|
130
|
-
| Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>
|
|
131
|
-
| R2
|
|
132
|
-
> {
|
|
133
|
-
const { Request, Response, h: handle } = handler
|
|
134
|
-
|
|
135
|
-
const response: REST.ReqRes<any, any, any> = Response ? Response : S.Void
|
|
136
|
-
const resp = response as typeof response & { fields?: Struct.Fields }
|
|
137
|
-
// TODO: consider if the alternative of using the struct schema is perhaps just better.
|
|
138
|
-
const encoder = "fields" in resp && resp.fields
|
|
139
|
-
? S.encode(handler.rt === "raw" ? S.encodedSchema(S.Struct(resp.fields)) : S.Struct(resp.fields))
|
|
140
|
-
// ? (i: any) => {
|
|
141
|
-
// if (i instanceof (response as any)) return S.encodeSync(response)(i)
|
|
142
|
-
// else return S.encodeSync(response)(new (response as any)(i))
|
|
143
|
-
// }
|
|
144
|
-
: S.encode(handler.rt === "raw" ? S.encodedSchema(resp) : resp)
|
|
145
|
-
// const encodeResponse = adaptResponse
|
|
146
|
-
// ? (req: ReqA) => Encoder.for(adaptResponse(req))
|
|
147
|
-
// : () => encoder
|
|
148
|
-
|
|
149
|
-
const requestParsers = makeRequestParsers(Request)
|
|
150
|
-
const parseRequest = parseRequestParams(requestParsers)
|
|
151
|
-
|
|
152
|
-
const getParams = Effect.map(
|
|
153
|
-
Effect
|
|
154
|
-
.all({
|
|
155
|
-
rcx: HttpRouter.RouteContext,
|
|
156
|
-
searchParms: HttpServerRequest.ParsedSearchParams,
|
|
157
|
-
req: Effect.flatMap(
|
|
158
|
-
HttpServerRequest.HttpServerRequest,
|
|
159
|
-
(req) => req.json.pipe(Effect.map((body) => ({ body, headers: req.headers })))
|
|
160
|
-
)
|
|
161
|
-
}),
|
|
162
|
-
(
|
|
163
|
-
{ rcx, req, searchParms }
|
|
164
|
-
) => ({
|
|
165
|
-
params: rcx.params,
|
|
166
|
-
query: searchParms,
|
|
167
|
-
body: req.body,
|
|
168
|
-
headers: req.headers,
|
|
169
|
-
cookies: {} // req.cookies
|
|
170
|
-
})
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
return Effect
|
|
174
|
-
.gen(function*() {
|
|
175
|
-
const req = yield* HttpServerRequest.HttpServerRequest
|
|
176
|
-
const res = HttpServerResponse
|
|
177
|
-
.empty()
|
|
178
|
-
.pipe((_) => req.method === "GET" ? HttpServerResponse.setHeader(_, "Cache-Control", "no-store") : _)
|
|
179
|
-
|
|
180
|
-
const pars = yield* getParams
|
|
181
|
-
|
|
182
|
-
const settings = yield* FiberRef.get(RequestSettings)
|
|
183
|
-
|
|
184
|
-
const eff =
|
|
185
|
-
// TODO: we don;t have access to user id here cause context is not yet created
|
|
186
|
-
InfraLogger
|
|
187
|
-
.logInfo("Incoming request")
|
|
188
|
-
.pipe(
|
|
189
|
-
Effect.annotateLogs({
|
|
190
|
-
method: req.method,
|
|
191
|
-
path: req.originalUrl,
|
|
192
|
-
...(settings.verbose
|
|
193
|
-
? {
|
|
194
|
-
reqPath: pretty(pars.params),
|
|
195
|
-
reqQuery: pretty(pars.query),
|
|
196
|
-
reqBody: pretty(pars.body),
|
|
197
|
-
reqCookies: pretty(pars.cookies),
|
|
198
|
-
reqHeaders: pretty(pars.headers)
|
|
199
|
-
}
|
|
200
|
-
: undefined)
|
|
201
|
-
}),
|
|
202
|
-
Effect
|
|
203
|
-
.andThen(
|
|
204
|
-
Effect.suspend(() => {
|
|
205
|
-
const handleRequest = parseRequest(pars)
|
|
206
|
-
.pipe(
|
|
207
|
-
Effect.map(({ body, path, query }) => {
|
|
208
|
-
const hn = {
|
|
209
|
-
...body.pipe(Option.getOrUndefined) ?? {},
|
|
210
|
-
...query.pipe(Option.getOrUndefined) ?? {},
|
|
211
|
-
...path.pipe(Option.getOrUndefined) ?? {}
|
|
212
|
-
} as unknown as ReqA
|
|
213
|
-
return hn
|
|
214
|
-
}),
|
|
215
|
-
Effect.tap((parsedReq) =>
|
|
216
|
-
Effect.annotateCurrentSpan(
|
|
217
|
-
"requestInput",
|
|
218
|
-
Object.entries(parsedReq).reduce((prev, [key, value]: [string, unknown]) => {
|
|
219
|
-
prev[key] = key === "password"
|
|
220
|
-
? "<redacted>"
|
|
221
|
-
: typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
222
|
-
? typeof value === "string" && value.length > 256
|
|
223
|
-
? (value.substring(0, 253) + "...")
|
|
224
|
-
: value
|
|
225
|
-
: Array.isArray(value)
|
|
226
|
-
? `Array[${value.length}]`
|
|
227
|
-
: value === null || value === undefined
|
|
228
|
-
? `${value}`
|
|
229
|
-
: typeof value === "object" && value
|
|
230
|
-
? `Object[${Object.keys(value).length}]`
|
|
231
|
-
: typeof value
|
|
232
|
-
return prev
|
|
233
|
-
}, {} as Record<string, string | number | boolean>)
|
|
234
|
-
)
|
|
235
|
-
),
|
|
236
|
-
Effect.flatMap((parsedReq) =>
|
|
237
|
-
handle(parsedReq)
|
|
238
|
-
.pipe(
|
|
239
|
-
Effect.provideService(handler.Request.Tag, parsedReq as any),
|
|
240
|
-
Effect.flatMap(encoder),
|
|
241
|
-
Effect
|
|
242
|
-
.map((r) =>
|
|
243
|
-
res.pipe(
|
|
244
|
-
HttpServerResponse.setBody(HttpBody.unsafeJson(r)),
|
|
245
|
-
HttpServerResponse.setStatus(r === undefined ? 204 : 200)
|
|
246
|
-
)
|
|
247
|
-
)
|
|
248
|
-
)
|
|
249
|
-
)
|
|
250
|
-
) as Effect<
|
|
251
|
-
HttpServerResponse.HttpServerResponse,
|
|
252
|
-
ValidationError | ResE,
|
|
253
|
-
Exclude<R, EnforceNonEmptyRecord<M>>
|
|
254
|
-
>
|
|
255
|
-
|
|
256
|
-
const r = middlewareLayer
|
|
257
|
-
? Effect.provide(handleRequest, middlewareLayer)
|
|
258
|
-
// PR is not relevant here
|
|
259
|
-
: (handleRequest as Effect<
|
|
260
|
-
HttpServerResponse.HttpServerResponse,
|
|
261
|
-
ResE | MiddlewareE | ValidationError,
|
|
262
|
-
Exclude<Exclude<R, EnforceNonEmptyRecord<M>>, PR>
|
|
263
|
-
>)
|
|
264
|
-
return errorHandler(
|
|
265
|
-
req,
|
|
266
|
-
res,
|
|
267
|
-
r.pipe(Effect.andThen(RequestFiberSet.register))
|
|
268
|
-
)
|
|
269
|
-
})
|
|
270
|
-
),
|
|
271
|
-
Effect
|
|
272
|
-
.catchAllCause((cause) =>
|
|
273
|
-
Effect
|
|
274
|
-
.sync(() => HttpServerResponse.setStatus(res, 500))
|
|
275
|
-
.pipe(Effect
|
|
276
|
-
.tap((res) =>
|
|
277
|
-
Effect
|
|
278
|
-
.all([
|
|
279
|
-
reportError("request")(cause, {
|
|
280
|
-
path: req.originalUrl,
|
|
281
|
-
method: req.method
|
|
282
|
-
}),
|
|
283
|
-
Effect.suspend(() => {
|
|
284
|
-
const headers = res.headers
|
|
285
|
-
return InfraLogger
|
|
286
|
-
.logError("Finished request", cause)
|
|
287
|
-
.pipe(Effect.annotateLogs({
|
|
288
|
-
method: req.method,
|
|
289
|
-
path: req.originalUrl,
|
|
290
|
-
statusCode: res.status.toString(),
|
|
291
|
-
|
|
292
|
-
reqPath: pretty(pars.params),
|
|
293
|
-
reqQuery: pretty(pars.query),
|
|
294
|
-
reqBody: pretty(pars.body),
|
|
295
|
-
reqCookies: pretty(pars.cookies),
|
|
296
|
-
reqHeaders: pretty(pars.headers),
|
|
297
|
-
|
|
298
|
-
resHeaders: pretty(
|
|
299
|
-
Object
|
|
300
|
-
.entries(headers)
|
|
301
|
-
.reduce((prev, [key, value]) => {
|
|
302
|
-
prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
303
|
-
return prev
|
|
304
|
-
}, {} as Record<string, any>)
|
|
305
|
-
)
|
|
306
|
-
}))
|
|
307
|
-
})
|
|
308
|
-
], { concurrency: "inherit" })
|
|
309
|
-
))
|
|
310
|
-
.pipe(
|
|
311
|
-
Effect.tapErrorCause((cause) => Console.error("Error occurred while reporting error", cause))
|
|
312
|
-
)
|
|
313
|
-
),
|
|
314
|
-
Effect
|
|
315
|
-
.tap((res) =>
|
|
316
|
-
InfraLogger
|
|
317
|
-
.logInfo("Finished request")
|
|
318
|
-
.pipe(Effect.annotateLogs({
|
|
319
|
-
method: req.method,
|
|
320
|
-
path: req.originalUrl,
|
|
321
|
-
statusCode: res.status.toString(),
|
|
322
|
-
...(settings.verbose
|
|
323
|
-
? {
|
|
324
|
-
resHeaders: pretty(res.headers)
|
|
325
|
-
}
|
|
326
|
-
: undefined)
|
|
327
|
-
}))
|
|
328
|
-
)
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
return yield* eff
|
|
332
|
-
})
|
|
333
|
-
.pipe((_) =>
|
|
334
|
-
updateRequestContext(
|
|
335
|
-
_,
|
|
336
|
-
copy((_) => ({
|
|
337
|
-
name: NonEmptyString255(
|
|
338
|
-
handler.name
|
|
339
|
-
)
|
|
340
|
-
}))
|
|
341
|
-
)
|
|
342
|
-
)
|
|
343
|
-
}
|
package/src/api/routing/match.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/* eslint-disable @typescript-eslint/ban-types */
|
|
3
|
-
import type { ValidationError } from "@effect-app/infra/errors"
|
|
4
|
-
import { type RouteDescriptorAny } from "./schema/routing.js"
|
|
5
|
-
import type {} from "effect-app/utils"
|
|
6
|
-
import type { Struct } from "@effect/schema/Schema"
|
|
7
|
-
import type { Layer, Ref, Scope } from "effect-app"
|
|
8
|
-
import { Context, Effect } from "effect-app"
|
|
9
|
-
import { HttpRouter } from "effect-app/http"
|
|
10
|
-
import type { HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
11
|
-
import type { RequestHandler } from "./base.js"
|
|
12
|
-
import { makeRequestHandler } from "./makeRequestHandler.js"
|
|
13
|
-
import type { Middleware } from "./makeRequestHandler.js"
|
|
14
|
-
|
|
15
|
-
export const RouteDescriptors = Context.GenericTag<Ref<RouteDescriptorAny[]>>("@services/RouteDescriptors")
|
|
16
|
-
|
|
17
|
-
export function match<
|
|
18
|
-
R,
|
|
19
|
-
M,
|
|
20
|
-
PathA extends Struct.Fields,
|
|
21
|
-
CookieA extends Struct.Fields,
|
|
22
|
-
QueryA extends Struct.Fields,
|
|
23
|
-
BodyA extends Struct.Fields,
|
|
24
|
-
HeaderA extends Struct.Fields,
|
|
25
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
26
|
-
ResA extends Struct.Fields,
|
|
27
|
-
ResE,
|
|
28
|
-
MiddlewareE,
|
|
29
|
-
PPath extends `/${string}`,
|
|
30
|
-
R2,
|
|
31
|
-
PR,
|
|
32
|
-
RErr,
|
|
33
|
-
CTX,
|
|
34
|
-
Context,
|
|
35
|
-
Config
|
|
36
|
-
>(
|
|
37
|
-
requestHandler: RequestHandler<
|
|
38
|
-
R,
|
|
39
|
-
M,
|
|
40
|
-
PathA,
|
|
41
|
-
CookieA,
|
|
42
|
-
QueryA,
|
|
43
|
-
BodyA,
|
|
44
|
-
HeaderA,
|
|
45
|
-
ReqA,
|
|
46
|
-
ResA,
|
|
47
|
-
ResE,
|
|
48
|
-
PPath,
|
|
49
|
-
CTX,
|
|
50
|
-
Context,
|
|
51
|
-
Config
|
|
52
|
-
>,
|
|
53
|
-
errorHandler: <R>(
|
|
54
|
-
req: HttpServerRequest.HttpServerRequest,
|
|
55
|
-
res: HttpServerResponse.HttpServerResponse,
|
|
56
|
-
r2: Effect<HttpServerResponse.HttpServerResponse, ValidationError | MiddlewareE | ResE, R>
|
|
57
|
-
) => Effect<
|
|
58
|
-
HttpServerResponse.HttpServerResponse,
|
|
59
|
-
never,
|
|
60
|
-
Exclude<RErr | R, HttpServerRequest.HttpServerRequest | HttpRouter.RouteContext | Scope>
|
|
61
|
-
>,
|
|
62
|
-
middleware?: Middleware<
|
|
63
|
-
R,
|
|
64
|
-
M,
|
|
65
|
-
PathA,
|
|
66
|
-
CookieA,
|
|
67
|
-
QueryA,
|
|
68
|
-
BodyA,
|
|
69
|
-
HeaderA,
|
|
70
|
-
ReqA,
|
|
71
|
-
ResA,
|
|
72
|
-
ResE,
|
|
73
|
-
MiddlewareE,
|
|
74
|
-
PPath,
|
|
75
|
-
R2,
|
|
76
|
-
PR,
|
|
77
|
-
CTX,
|
|
78
|
-
Context,
|
|
79
|
-
Config
|
|
80
|
-
>
|
|
81
|
-
) {
|
|
82
|
-
let middlewareLayer: Layer<PR, MiddlewareE, R2> | undefined = undefined
|
|
83
|
-
if (middleware) {
|
|
84
|
-
const { handler, makeRequestLayer } = middleware(requestHandler)
|
|
85
|
-
requestHandler = handler as any // todo
|
|
86
|
-
middlewareLayer = makeRequestLayer
|
|
87
|
-
}
|
|
88
|
-
return Effect.gen(function*() {
|
|
89
|
-
// const rdesc = yield* $(RouteDescriptors.flatMap((_) => _.get))
|
|
90
|
-
|
|
91
|
-
const handler = makeRequestHandler<
|
|
92
|
-
R,
|
|
93
|
-
M,
|
|
94
|
-
PathA,
|
|
95
|
-
CookieA,
|
|
96
|
-
QueryA,
|
|
97
|
-
BodyA,
|
|
98
|
-
HeaderA,
|
|
99
|
-
ReqA,
|
|
100
|
-
ResA,
|
|
101
|
-
ResE,
|
|
102
|
-
MiddlewareE,
|
|
103
|
-
R2,
|
|
104
|
-
PR,
|
|
105
|
-
RErr,
|
|
106
|
-
PPath,
|
|
107
|
-
Config
|
|
108
|
-
>(
|
|
109
|
-
requestHandler as any, // one argument if no middleware, 2 if has middleware. TODO: clean this shit up
|
|
110
|
-
errorHandler,
|
|
111
|
-
middlewareLayer
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
const route = HttpRouter.makeRoute(
|
|
115
|
-
requestHandler.Request.method,
|
|
116
|
-
requestHandler.Request.path,
|
|
117
|
-
handler,
|
|
118
|
-
{ uninterruptible: requestHandler.Request.method !== "GET" } // we don't want commands to be interruptible
|
|
119
|
-
)
|
|
120
|
-
// TODO
|
|
121
|
-
// rdesc.push(makeRouteDescriptor(
|
|
122
|
-
// requestHandler.Request.path,
|
|
123
|
-
// requestHandler.Request.method,
|
|
124
|
-
// requestHandler
|
|
125
|
-
// ))
|
|
126
|
-
return route
|
|
127
|
-
})
|
|
128
|
-
}
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/ban-types */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import type { Context } from "effect-app"
|
|
4
|
-
import type { REST } from "effect-app/schema"
|
|
5
|
-
|
|
6
|
-
export type Request<
|
|
7
|
-
M,
|
|
8
|
-
PathA,
|
|
9
|
-
CookieA,
|
|
10
|
-
QueryA,
|
|
11
|
-
BodyA,
|
|
12
|
-
HeaderA,
|
|
13
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
14
|
-
PPath extends `/${string}`
|
|
15
|
-
> = REST.ReqRes<any, unknown, ReqA> & {
|
|
16
|
-
method: REST.SupportedMethods
|
|
17
|
-
path: PPath
|
|
18
|
-
Cookie?: REST.ReqRes<CookieA, Record<string, string>, any>
|
|
19
|
-
Path?: REST.ReqRes<PathA, Record<string, string>, any>
|
|
20
|
-
Body?: REST.ReqRes<BodyA, unknown, any>
|
|
21
|
-
Query?: REST.ReqRes<QueryA, Record<string, string>, any>
|
|
22
|
-
Headers?: REST.ReqRes<HeaderA, Record<string, string>, any>
|
|
23
|
-
Tag: Context.Tag<M, M>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface RouteRequestHandler<
|
|
27
|
-
M,
|
|
28
|
-
PathA,
|
|
29
|
-
CookieA,
|
|
30
|
-
QueryA,
|
|
31
|
-
BodyA,
|
|
32
|
-
HeaderA,
|
|
33
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
34
|
-
ResA,
|
|
35
|
-
PPath extends `/${string}`
|
|
36
|
-
> {
|
|
37
|
-
Request: Request<M, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, PPath>
|
|
38
|
-
Response?: REST.ReqRes<ResA, unknown, any> // | REST.ReqResSchemed<unknown, ResA>
|
|
39
|
-
ResponseOpenApi?: any
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function asRouteDescriptionAny<R extends RouteDescriptorAny>(i: R) {
|
|
43
|
-
return i as RouteDescriptorAny
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function arrAsRouteDescriptionAny<R extends RouteDescriptorAny>(
|
|
47
|
-
arr: ReadonlyArray<R>
|
|
48
|
-
) {
|
|
49
|
-
return arr.map(asRouteDescriptionAny)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface RouteDescriptor<
|
|
53
|
-
M,
|
|
54
|
-
PathA,
|
|
55
|
-
CookieA,
|
|
56
|
-
QueryA,
|
|
57
|
-
BodyA,
|
|
58
|
-
HeaderA,
|
|
59
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
60
|
-
ResA,
|
|
61
|
-
METHOD extends REST.Methods.Rest = REST.Methods.Rest
|
|
62
|
-
> {
|
|
63
|
-
_tag: "Schema"
|
|
64
|
-
path: `/${string}`
|
|
65
|
-
method: METHOD
|
|
66
|
-
handler: RouteRequestHandler<M, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, ResA, `/${string}`>
|
|
67
|
-
info?: {
|
|
68
|
-
tags: ReadonlyArray<string>
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export type RouteDescriptorAny = RouteDescriptor<
|
|
73
|
-
any,
|
|
74
|
-
any,
|
|
75
|
-
any,
|
|
76
|
-
any,
|
|
77
|
-
any,
|
|
78
|
-
any,
|
|
79
|
-
any,
|
|
80
|
-
any
|
|
81
|
-
>
|
|
82
|
-
|
|
83
|
-
export function makeRouteDescriptor<
|
|
84
|
-
M,
|
|
85
|
-
PathA,
|
|
86
|
-
CookieA,
|
|
87
|
-
QueryA,
|
|
88
|
-
BodyA,
|
|
89
|
-
HeaderA,
|
|
90
|
-
ReqA extends PathA & QueryA & BodyA,
|
|
91
|
-
ResA = void,
|
|
92
|
-
METHOD extends REST.Methods.Rest = REST.Methods.Rest
|
|
93
|
-
>(
|
|
94
|
-
path: `/${string}`,
|
|
95
|
-
method: METHOD,
|
|
96
|
-
handler: RouteRequestHandler<
|
|
97
|
-
M,
|
|
98
|
-
PathA,
|
|
99
|
-
CookieA,
|
|
100
|
-
QueryA,
|
|
101
|
-
BodyA,
|
|
102
|
-
HeaderA,
|
|
103
|
-
ReqA,
|
|
104
|
-
ResA,
|
|
105
|
-
`/${string}`
|
|
106
|
-
>
|
|
107
|
-
): RouteDescriptor<
|
|
108
|
-
M,
|
|
109
|
-
PathA,
|
|
110
|
-
CookieA,
|
|
111
|
-
QueryA,
|
|
112
|
-
BodyA,
|
|
113
|
-
HeaderA,
|
|
114
|
-
ReqA,
|
|
115
|
-
ResA,
|
|
116
|
-
METHOD
|
|
117
|
-
> {
|
|
118
|
-
return { path, handler, method, _tag: "Schema" }
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// export function makeFromSchema<ResA>(
|
|
122
|
-
// e: RouteDescriptor<any, any, any, any, any, any, ResA, any>
|
|
123
|
-
// ) {
|
|
124
|
-
// const jsonSchema_ = OpenApi.for
|
|
125
|
-
// const jsonSchema = <E, A>(r: REST.ReqRes<A, E, any>) => jsonSchema_(r)
|
|
126
|
-
// const { Request: Req, Response: Res_, ResponseOpenApi } = e.handler
|
|
127
|
-
// const r = ResponseOpenApi ?? Res_
|
|
128
|
-
// const Res = r ? S.extractSchema(r) : S.Void
|
|
129
|
-
// // TODO EffectOption.fromNullable(Req.Headers).flatMapOpt(jsonSchema)
|
|
130
|
-
// // TODO: use the path vs body etc serialisation also in the Client.
|
|
131
|
-
// const makeReqQuerySchema = Effect.sync(() => Option.fromNullable(Req.Query)).flatMap((_) =>
|
|
132
|
-
// _.match({
|
|
133
|
-
// onNone: () => Effect.sync(() => Option.none()),
|
|
134
|
-
// onSome: (_) => jsonSchema(_).map(Option.some)
|
|
135
|
-
// })
|
|
136
|
-
// )
|
|
137
|
-
// const makeReqHeadersSchema = Effect.sync(() => Option.fromNullable(Req.Headers)).flatMap((_) =>
|
|
138
|
-
// _.match({
|
|
139
|
-
// onNone: () => Effect.sync(() => Option.none()),
|
|
140
|
-
// onSome: (_) => jsonSchema(_).map(Option.some)
|
|
141
|
-
// })
|
|
142
|
-
// )
|
|
143
|
-
// const makeReqCookieSchema = Effect.sync(() => Option.fromNullable(Req.Cookie)).flatMap((_) =>
|
|
144
|
-
// _.match({
|
|
145
|
-
// onNone: () => Effect.sync(() => Option.none()),
|
|
146
|
-
// onSome: (_) => jsonSchema(_).map(Option.some)
|
|
147
|
-
// })
|
|
148
|
-
// )
|
|
149
|
-
// const makeReqPathSchema = Effect.sync(() => Option.fromNullable(Req.Path)).flatMap((_) =>
|
|
150
|
-
// _.match({
|
|
151
|
-
// onNone: () => Effect.sync(() => Option.none()),
|
|
152
|
-
// onSome: (_) => jsonSchema(_).map(Option.some)
|
|
153
|
-
// })
|
|
154
|
-
// )
|
|
155
|
-
// const makeReqBodySchema = Effect.sync(() => Option.fromNullable(Req.Body)).flatMap((_) =>
|
|
156
|
-
// _.match({
|
|
157
|
-
// onNone: () => Effect.sync(() => Option.none()),
|
|
158
|
-
// onSome: (_) => jsonSchema(_).map(Option.some)
|
|
159
|
-
// })
|
|
160
|
-
// )
|
|
161
|
-
// // const makeReqSchema = schema(Req)
|
|
162
|
-
|
|
163
|
-
// const makeResSchema = jsonSchema_(Res)
|
|
164
|
-
|
|
165
|
-
// function makeParameters(inn: ParameterLocation) {
|
|
166
|
-
// return (a: Option<JSONSchema | SubSchema>) => {
|
|
167
|
-
// return a
|
|
168
|
-
// .flatMap((o) => (isObjectSchema(o) ? Option.some(o) : Option.none()))
|
|
169
|
-
// .map((x) => {
|
|
170
|
-
// // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
171
|
-
// return Object.keys(x.properties!).map((p) => {
|
|
172
|
-
// // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
173
|
-
// const schema = x.properties![p]
|
|
174
|
-
// const required = Boolean(x.required?.includes(p))
|
|
175
|
-
// return { name: p, in: inn, required, schema }
|
|
176
|
-
// })
|
|
177
|
-
// })
|
|
178
|
-
// .getOrElse(() => [])
|
|
179
|
-
// }
|
|
180
|
-
// }
|
|
181
|
-
|
|
182
|
-
// return Effect
|
|
183
|
-
// .all({
|
|
184
|
-
// req: jsonSchema(Req.Model),
|
|
185
|
-
// reqQuery: makeReqQuerySchema,
|
|
186
|
-
// reqHeaders: makeReqHeadersSchema,
|
|
187
|
-
// reqBody: makeReqBodySchema,
|
|
188
|
-
// reqPath: makeReqPathSchema,
|
|
189
|
-
// reqCookie: makeReqCookieSchema,
|
|
190
|
-
// res: makeResSchema
|
|
191
|
-
// })
|
|
192
|
-
// .map((_) => {
|
|
193
|
-
// // console.log("$$$ REQ", _.req)
|
|
194
|
-
// const isEmpty = !e.handler.Response || e.handler.Response === S.Void
|
|
195
|
-
// return {
|
|
196
|
-
// path: e.path,
|
|
197
|
-
// method: e.method.toLowerCase(),
|
|
198
|
-
// tags: e.info?.tags,
|
|
199
|
-
// description: _.req?.description,
|
|
200
|
-
// summary: _.req?.summary,
|
|
201
|
-
// operationId: _.req?.title,
|
|
202
|
-
// parameters: [
|
|
203
|
-
// ...makeParameters("path")(_.reqPath),
|
|
204
|
-
// ...makeParameters("query")(_.reqQuery),
|
|
205
|
-
// ...makeParameters("header")(_.reqHeaders),
|
|
206
|
-
// ...makeParameters("cookie")(_.reqCookie)
|
|
207
|
-
// ],
|
|
208
|
-
// requestBody: _
|
|
209
|
-
// .reqBody
|
|
210
|
-
// .map((schema) => ({
|
|
211
|
-
// content: { "application/json": { schema } }
|
|
212
|
-
// }))
|
|
213
|
-
// .value,
|
|
214
|
-
// responses: [
|
|
215
|
-
// isEmpty
|
|
216
|
-
// ? new Response(204, { description: "Empty" })
|
|
217
|
-
// : new Response(200, {
|
|
218
|
-
// description: "OK",
|
|
219
|
-
// content: { "application/json": { schema: _.res } }
|
|
220
|
-
// }),
|
|
221
|
-
// new Response(400, { description: "ValidationError" })
|
|
222
|
-
// ]
|
|
223
|
-
// .concat(
|
|
224
|
-
// e.path.includes(":") && isEmpty
|
|
225
|
-
// ? [new Response(404, { description: "NotFoundError" })]
|
|
226
|
-
// : []
|
|
227
|
-
// )
|
|
228
|
-
// }
|
|
229
|
-
// })
|
|
230
|
-
// }
|
|
231
|
-
|
|
232
|
-
// class Response {
|
|
233
|
-
// constructor(
|
|
234
|
-
// public readonly statusCode: number,
|
|
235
|
-
// public readonly type: any // string | JSONSchema | SubSchema
|
|
236
|
-
// ) {}
|
|
237
|
-
// }
|