@effect/platform 0.13.1 → 0.13.3
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/Http/Headers.d.ts +3 -3
- package/Http/Headers.d.ts.map +1 -1
- package/Http/Headers.js +16 -11
- package/Http/Headers.js.map +1 -1
- package/Http/IncomingMessage.d.ts.map +1 -1
- package/Http/IncomingMessage.js +1 -1
- package/Http/IncomingMessage.js.map +1 -1
- package/Http/Middleware.d.ts +0 -8
- package/Http/Middleware.d.ts.map +1 -1
- package/Http/Middleware.js +2 -8
- package/Http/Middleware.js.map +1 -1
- package/Http/Router.d.ts +90 -0
- package/Http/Router.d.ts.map +1 -1
- package/Http/Router.js +43 -1
- package/Http/Router.js.map +1 -1
- package/internal/http/client.js +1 -1
- package/internal/http/client.js.map +1 -1
- package/internal/http/middleware.js +9 -11
- package/internal/http/middleware.js.map +1 -1
- package/internal/http/router.d.ts +3 -1
- package/internal/http/router.d.ts.map +1 -1
- package/internal/http/router.js +38 -17
- package/internal/http/router.js.map +1 -1
- package/internal/http/serverResponse.js +15 -12
- package/internal/http/serverResponse.js.map +1 -1
- package/mjs/Http/Headers.mjs +16 -11
- package/mjs/Http/Headers.mjs.map +1 -1
- package/mjs/Http/IncomingMessage.mjs +1 -1
- package/mjs/Http/IncomingMessage.mjs.map +1 -1
- package/mjs/Http/Middleware.mjs +0 -5
- package/mjs/Http/Middleware.mjs.map +1 -1
- package/mjs/Http/Router.mjs +35 -0
- package/mjs/Http/Router.mjs.map +1 -1
- package/mjs/internal/http/client.mjs +1 -1
- package/mjs/internal/http/client.mjs.map +1 -1
- package/mjs/internal/http/middleware.mjs +9 -10
- package/mjs/internal/http/middleware.mjs.map +1 -1
- package/mjs/internal/http/router.mjs +30 -16
- package/mjs/internal/http/router.mjs.map +1 -1
- package/mjs/internal/http/serverResponse.mjs +15 -12
- package/mjs/internal/http/serverResponse.mjs.map +1 -1
- package/package.json +4 -4
- package/src/Http/Headers.ts +23 -17
- package/src/Http/IncomingMessage.ts +1 -2
- package/src/Http/Middleware.ts +0 -14
- package/src/Http/Router.ts +118 -0
- package/src/internal/http/client.ts +18 -21
- package/src/internal/http/middleware.ts +23 -31
- package/src/internal/http/router.ts +158 -24
- package/src/internal/http/serverResponse.ts +15 -13
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { flow } from "@effect/data/Function"
|
|
2
2
|
import * as Effect from "@effect/io/Effect"
|
|
3
|
-
import type * as App from "@effect/platform/Http/App"
|
|
4
3
|
import * as Headers from "@effect/platform/Http/Headers"
|
|
5
4
|
import type * as Middleware from "@effect/platform/Http/Middleware"
|
|
6
5
|
import * as ServerRequest from "@effect/platform/Http/ServerRequest"
|
|
@@ -11,16 +10,21 @@ export const make = <M extends Middleware.Middleware>(middleware: M): M => middl
|
|
|
11
10
|
/** @internal */
|
|
12
11
|
export const logger = make((httpApp) =>
|
|
13
12
|
Effect.withLogSpan(
|
|
14
|
-
Effect.
|
|
15
|
-
|
|
16
|
-
(
|
|
17
|
-
Effect.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
Effect.flatMap(
|
|
14
|
+
ServerRequest.ServerRequest,
|
|
15
|
+
(request) =>
|
|
16
|
+
Effect.tap(
|
|
17
|
+
Effect.tapErrorCause(httpApp, (cause) =>
|
|
18
|
+
Effect.annotateLogs(Effect.log(cause), {
|
|
19
|
+
"http.method": request.method,
|
|
20
|
+
"http.url": request.url,
|
|
21
|
+
"http.status": 500
|
|
22
|
+
})),
|
|
23
|
+
(response) =>
|
|
24
|
+
Effect.annotateLogs(Effect.log(""), {
|
|
21
25
|
"http.method": request.method,
|
|
22
26
|
"http.url": request.url,
|
|
23
|
-
"http.status":
|
|
27
|
+
"http.status": response.status
|
|
24
28
|
})
|
|
25
29
|
)
|
|
26
30
|
),
|
|
@@ -46,27 +50,15 @@ export const tracer = make((httpApp) =>
|
|
|
46
50
|
|
|
47
51
|
/** @internal */
|
|
48
52
|
export const xForwardedHeaders = make((httpApp) =>
|
|
49
|
-
Effect.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
Effect.updateService(httpApp, ServerRequest.ServerRequest, (request) =>
|
|
54
|
+
request.headers["x-forwarded-host"]
|
|
55
|
+
? request.replaceHeaders(Headers.set(
|
|
56
|
+
request.headers,
|
|
57
|
+
"host",
|
|
58
|
+
request.headers["x-forwarded-host"]
|
|
59
|
+
))
|
|
60
|
+
: request)
|
|
56
61
|
)
|
|
57
62
|
|
|
58
63
|
/** @internal */
|
|
59
|
-
export const
|
|
60
|
-
<B extends App.Default<any, any>, C extends App.Default<any, any>>(
|
|
61
|
-
that: (b: B) => C
|
|
62
|
-
) => <A extends App.Default<any, any>>(
|
|
63
|
-
self: (a: A) => B
|
|
64
|
-
) => (a: A) => C,
|
|
65
|
-
<A extends App.Default<any, any>, B extends App.Default<any, any>, C extends App.Default<any, any>>(
|
|
66
|
-
self: (a: A) => B,
|
|
67
|
-
that: (b: B) => C
|
|
68
|
-
) => (a: A) => C
|
|
69
|
-
>(2, (self, that) => (inApp) => that(self(inApp)))
|
|
70
|
-
|
|
71
|
-
/** @internal */
|
|
72
|
-
export const loggerTracer = compose(tracer, logger)
|
|
64
|
+
export const loggerTracer = flow(tracer, logger)
|
|
@@ -5,6 +5,7 @@ import { dual } from "@effect/data/Function"
|
|
|
5
5
|
import * as Hash from "@effect/data/Hash"
|
|
6
6
|
import * as Option from "@effect/data/Option"
|
|
7
7
|
import { pipeArguments } from "@effect/data/Pipeable"
|
|
8
|
+
import type * as Cause from "@effect/io/Cause"
|
|
8
9
|
import * as Effect from "@effect/io/Effect"
|
|
9
10
|
import type * as App from "@effect/platform/Http/App"
|
|
10
11
|
import type * as Method from "@effect/platform/Http/Method"
|
|
@@ -95,15 +96,12 @@ const toHttpApp = <R, E>(
|
|
|
95
96
|
self: Router.Router<R, E>
|
|
96
97
|
): App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> => {
|
|
97
98
|
const router = FindMyWay()
|
|
98
|
-
Chunk.
|
|
99
|
-
|
|
100
|
-
fn.handler = Effect.updateService(app, ServerRequest.ServerRequest, (request) => sliceRequestUrl(request, path))
|
|
101
|
-
router.all(path, fn)
|
|
102
|
-
router.all(path + "/*", fn)
|
|
103
|
-
})
|
|
99
|
+
const mounts = Chunk.toReadonlyArray(self.mounts)
|
|
100
|
+
const mountsLen = mounts.length
|
|
104
101
|
Chunk.forEach(self.routes, (route) => {
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
function fn() {
|
|
103
|
+
return route
|
|
104
|
+
}
|
|
107
105
|
if (route.method === "*") {
|
|
108
106
|
router.all(route.path, fn)
|
|
109
107
|
} else {
|
|
@@ -113,27 +111,36 @@ const toHttpApp = <R, E>(
|
|
|
113
111
|
return Effect.flatMap(
|
|
114
112
|
ServerRequest.ServerRequest,
|
|
115
113
|
(request): App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> => {
|
|
114
|
+
if (mountsLen > 0) {
|
|
115
|
+
for (let i = 0; i < mountsLen; i++) {
|
|
116
|
+
const [path, app] = mounts[i]
|
|
117
|
+
if (request.url.startsWith(path)) {
|
|
118
|
+
return Effect.provideService(
|
|
119
|
+
app,
|
|
120
|
+
ServerRequest.ServerRequest,
|
|
121
|
+
sliceRequestUrl(request, path)
|
|
122
|
+
) as App.Default<Exclude<R, Router.RouteContext>, E>
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
116
127
|
const result = router.find(request.method as HTTPMethod, request.url)
|
|
117
128
|
if (result === null) {
|
|
118
129
|
return Effect.fail(Error.RouteNotFound({ request }))
|
|
119
130
|
}
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
|
|
123
|
-
if (route.prefix._tag === "Some") {
|
|
124
|
-
request = sliceRequestUrl(request, route.prefix.value)
|
|
125
|
-
}
|
|
126
|
-
return Effect.mapInputContext(
|
|
127
|
-
route.handler,
|
|
128
|
-
(context) =>
|
|
129
|
-
Context.add(
|
|
130
|
-
Context.add(context, ServerRequest.ServerRequest, request),
|
|
131
|
-
RouteContext,
|
|
132
|
-
new RouteContextImpl(result.params, result.searchParams)
|
|
133
|
-
) as Context.Context<R>
|
|
134
|
-
)
|
|
131
|
+
const route = (result.handler as any)() as Router.Route<R, E>
|
|
132
|
+
if (route.prefix._tag === "Some") {
|
|
133
|
+
request = sliceRequestUrl(request, route.prefix.value)
|
|
135
134
|
}
|
|
136
|
-
return (
|
|
135
|
+
return Effect.mapInputContext(
|
|
136
|
+
route.handler,
|
|
137
|
+
(context) =>
|
|
138
|
+
Context.add(
|
|
139
|
+
Context.add(context, ServerRequest.ServerRequest, request),
|
|
140
|
+
RouteContext,
|
|
141
|
+
new RouteContextImpl(result.params, result.searchParams)
|
|
142
|
+
) as Context.Context<R>
|
|
143
|
+
)
|
|
137
144
|
}
|
|
138
145
|
)
|
|
139
146
|
}
|
|
@@ -296,3 +303,130 @@ export const head = route("HEAD")
|
|
|
296
303
|
|
|
297
304
|
/** @internal */
|
|
298
305
|
export const options = route("OPTIONS")
|
|
306
|
+
|
|
307
|
+
/** @internal */
|
|
308
|
+
export const transform = dual<
|
|
309
|
+
<R, E, R1, E1>(
|
|
310
|
+
f: (self: Router.Route.Handler<R, E>) => Router.Route.Handler<R1, E1>
|
|
311
|
+
) => (self: Router.Router<R, E>) => Router.Router<R1, E1>,
|
|
312
|
+
<R, E, R1, E1>(
|
|
313
|
+
self: Router.Router<R, E>,
|
|
314
|
+
f: (self: Router.Route.Handler<R, E>) => Router.Route.Handler<R1, E1>
|
|
315
|
+
) => Router.Router<R1, E1>
|
|
316
|
+
>(2, (self, f) =>
|
|
317
|
+
new RouterImpl(
|
|
318
|
+
Chunk.map(
|
|
319
|
+
self.routes,
|
|
320
|
+
(route) => new RouteImpl(route.method, route.path, f(route.handler), route.prefix)
|
|
321
|
+
),
|
|
322
|
+
Chunk.map(
|
|
323
|
+
self.mounts,
|
|
324
|
+
([path, app]) => [path, f(app as any)]
|
|
325
|
+
)
|
|
326
|
+
))
|
|
327
|
+
|
|
328
|
+
/** @internal */
|
|
329
|
+
export const catchAll = dual<
|
|
330
|
+
<E, R2, E2>(
|
|
331
|
+
f: (e: E) => Router.Route.Handler<R2, E2>
|
|
332
|
+
) => <R>(self: Router.Router<R, E>) => Router.Router<R2 | R, E2>,
|
|
333
|
+
<R, E, R2, E2>(
|
|
334
|
+
self: Router.Router<R, E>,
|
|
335
|
+
f: (e: E) => Router.Route.Handler<R2, E2>
|
|
336
|
+
) => Router.Router<R2 | R, E2>
|
|
337
|
+
>(2, (self, f) => transform(self, Effect.catchAll(f)))
|
|
338
|
+
|
|
339
|
+
/** @internal */
|
|
340
|
+
export const catchAllCause = dual<
|
|
341
|
+
<E, R2, E2>(
|
|
342
|
+
f: (e: Cause.Cause<E>) => Router.Route.Handler<R2, E2>
|
|
343
|
+
) => <R>(self: Router.Router<R, E>) => Router.Router<R2 | R, E2>,
|
|
344
|
+
<R, E, R2, E2>(
|
|
345
|
+
self: Router.Router<R, E>,
|
|
346
|
+
f: (e: Cause.Cause<E>) => Router.Route.Handler<R2, E2>
|
|
347
|
+
) => Router.Router<R2 | R, E2>
|
|
348
|
+
>(2, (self, f) => transform(self, Effect.catchAllCause(f)))
|
|
349
|
+
|
|
350
|
+
/** @internal */
|
|
351
|
+
export const catchTag = dual<
|
|
352
|
+
<K extends (E extends { _tag: string } ? E["_tag"] : never), E, R1, E1>(
|
|
353
|
+
k: K,
|
|
354
|
+
f: (e: Extract<E, { _tag: K }>) => Router.Route.Handler<R1, E1>
|
|
355
|
+
) => <R>(self: Router.Router<R, E>) => Router.Router<R | R1, Exclude<E, { _tag: K }> | E1>,
|
|
356
|
+
<R, E, K extends (E extends { _tag: string } ? E["_tag"] : never), R1, E1>(
|
|
357
|
+
self: Router.Router<R, E>,
|
|
358
|
+
k: K,
|
|
359
|
+
f: (e: Extract<E, { _tag: K }>) => Router.Route.Handler<R1, E1>
|
|
360
|
+
) => Router.Router<R | R1, Exclude<E, { _tag: K }> | E1>
|
|
361
|
+
>(3, (self, k, f) => transform(self, Effect.catchTag(k, f)))
|
|
362
|
+
|
|
363
|
+
/** @internal */
|
|
364
|
+
export const catchTags: {
|
|
365
|
+
<
|
|
366
|
+
E,
|
|
367
|
+
Cases extends (E extends { _tag: string } ? {
|
|
368
|
+
[K in E["_tag"]]+?: (error: Extract<E, { _tag: K }>) => Router.Route.Handler<any, any>
|
|
369
|
+
} :
|
|
370
|
+
{})
|
|
371
|
+
>(
|
|
372
|
+
cases: Cases
|
|
373
|
+
): <R>(self: Router.Router<R, E>) => Router.Router<
|
|
374
|
+
| R
|
|
375
|
+
| {
|
|
376
|
+
[K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<infer R, any, any>) ? R : never
|
|
377
|
+
}[keyof Cases],
|
|
378
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
379
|
+
| {
|
|
380
|
+
[K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, infer E, any>) ? E : never
|
|
381
|
+
}[keyof Cases]
|
|
382
|
+
>
|
|
383
|
+
<
|
|
384
|
+
R,
|
|
385
|
+
E,
|
|
386
|
+
Cases extends (E extends { _tag: string } ? {
|
|
387
|
+
[K in E["_tag"]]+?: (error: Extract<E, { _tag: K }>) => Router.Route.Handler<any, any>
|
|
388
|
+
} :
|
|
389
|
+
{})
|
|
390
|
+
>(
|
|
391
|
+
self: Router.Router<R, E>,
|
|
392
|
+
cases: Cases
|
|
393
|
+
): Router.Router<
|
|
394
|
+
| R
|
|
395
|
+
| {
|
|
396
|
+
[K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<infer R, any, any>) ? R : never
|
|
397
|
+
}[keyof Cases],
|
|
398
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
399
|
+
| {
|
|
400
|
+
[K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, infer E, any>) ? E : never
|
|
401
|
+
}[keyof Cases]
|
|
402
|
+
>
|
|
403
|
+
} = dual(2, (self: Router.Router<any, any>, cases: {}) => transform(self, Effect.catchTags(cases)))
|
|
404
|
+
|
|
405
|
+
export const provideService = dual<
|
|
406
|
+
<T extends Context.Tag<any, any>>(
|
|
407
|
+
tag: T,
|
|
408
|
+
service: Context.Tag.Service<T>
|
|
409
|
+
) => <R, E>(self: Router.Router<R, E>) => Router.Router<Exclude<R, Context.Tag.Identifier<T>>, E>,
|
|
410
|
+
<R, E, T extends Context.Tag<any, any>>(
|
|
411
|
+
self: Router.Router<R, E>,
|
|
412
|
+
tag: T,
|
|
413
|
+
service: Context.Tag.Service<T>
|
|
414
|
+
) => Router.Router<Exclude<R, Context.Tag.Identifier<T>>, E>
|
|
415
|
+
>(3, (self, tag, service) => transform(self, Effect.provideService(tag, service)))
|
|
416
|
+
|
|
417
|
+
/* @internal */
|
|
418
|
+
export const provideServiceEffect = dual<
|
|
419
|
+
<T extends Context.Tag<any, any>, R1, E1>(
|
|
420
|
+
tag: T,
|
|
421
|
+
effect: Effect.Effect<R1, E1, Context.Tag.Service<T>>
|
|
422
|
+
) => <R, E>(self: Router.Router<R, E>) => Router.Router<R1 | Exclude<R, Context.Tag.Identifier<T>>, E | E1>,
|
|
423
|
+
<R, E, T extends Context.Tag<any, any>, R1, E1>(
|
|
424
|
+
self: Router.Router<R, E>,
|
|
425
|
+
tag: T,
|
|
426
|
+
effect: Effect.Effect<R1, E1, Context.Tag.Service<T>>
|
|
427
|
+
) => Router.Router<R1 | Exclude<R, Context.Tag.Identifier<T>>, E | E1>
|
|
428
|
+
>(3, <R, E, T extends Context.Tag<any, any>, R1, E1>(
|
|
429
|
+
self: Router.Router<R, E>,
|
|
430
|
+
tag: T,
|
|
431
|
+
effect: Effect.Effect<R1, E1, Context.Tag.Service<T>>
|
|
432
|
+
) => transform(self, Effect.provideServiceEffect(tag, effect)))
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { dual } from "@effect/data/Function"
|
|
2
|
-
import * as Option from "@effect/data/Option"
|
|
3
2
|
import { pipeArguments } from "@effect/data/Pipeable"
|
|
4
3
|
import * as Effect from "@effect/io/Effect"
|
|
5
4
|
import type * as PlatformError from "@effect/platform/Error"
|
|
@@ -20,13 +19,26 @@ export const TypeId: ServerResponse.TypeId = Symbol.for("@effect/platform/Http/S
|
|
|
20
19
|
|
|
21
20
|
class ServerResponseImpl implements ServerResponse.ServerResponse {
|
|
22
21
|
readonly [TypeId]: ServerResponse.TypeId
|
|
22
|
+
readonly headers: Headers.Headers
|
|
23
23
|
constructor(
|
|
24
24
|
readonly status: number,
|
|
25
25
|
readonly statusText: string | undefined,
|
|
26
|
-
|
|
26
|
+
headers: Headers.Headers,
|
|
27
27
|
readonly body: Body.Body
|
|
28
28
|
) {
|
|
29
29
|
this[TypeId] = TypeId
|
|
30
|
+
if (body.contentType || body.contentLength) {
|
|
31
|
+
const newHeaders = { ...headers }
|
|
32
|
+
if (body.contentType) {
|
|
33
|
+
newHeaders["content-type"] = body.contentType
|
|
34
|
+
}
|
|
35
|
+
if (body.contentLength) {
|
|
36
|
+
newHeaders["content-length"] = body.contentLength.toString()
|
|
37
|
+
}
|
|
38
|
+
this.headers = newHeaders
|
|
39
|
+
} else {
|
|
40
|
+
this.headers = headers
|
|
41
|
+
}
|
|
30
42
|
}
|
|
31
43
|
pipe() {
|
|
32
44
|
return pipeArguments(this, arguments)
|
|
@@ -197,7 +209,7 @@ export const getContentType = (options?: ServerResponse.Options): string | undef
|
|
|
197
209
|
if (options?.contentType) {
|
|
198
210
|
return options.contentType
|
|
199
211
|
} else if (options?.headers) {
|
|
200
|
-
return
|
|
212
|
+
return options.headers["content-type"]
|
|
201
213
|
} else {
|
|
202
214
|
return
|
|
203
215
|
}
|
|
@@ -247,16 +259,6 @@ export const setBody = dual<
|
|
|
247
259
|
let headers = self.headers
|
|
248
260
|
if (body._tag === "Empty") {
|
|
249
261
|
headers = Headers.remove(Headers.remove(headers, "Content-Type"), "Content-length")
|
|
250
|
-
} else {
|
|
251
|
-
const contentType = body.contentType
|
|
252
|
-
if (contentType) {
|
|
253
|
-
headers = Headers.set(headers, "content-type", contentType)
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const contentLength = body.contentLength
|
|
257
|
-
if (contentLength) {
|
|
258
|
-
headers = Headers.set(headers, "content-length", contentLength.toString())
|
|
259
|
-
}
|
|
260
262
|
}
|
|
261
263
|
return new ServerResponseImpl(
|
|
262
264
|
self.status,
|