@effect/platform 0.13.0 → 0.13.2

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.
@@ -11,16 +11,21 @@ export const make = <M extends Middleware.Middleware>(middleware: M): M => middl
11
11
  /** @internal */
12
12
  export const logger = make((httpApp) =>
13
13
  Effect.withLogSpan(
14
- Effect.onExit(
15
- httpApp,
16
- (exit) =>
17
- Effect.flatMap(
18
- ServerRequest.ServerRequest,
19
- (request) =>
20
- Effect.annotateLogs(Effect.log("", exit._tag === "Failure" ? exit.cause : undefined), {
14
+ Effect.flatMap(
15
+ ServerRequest.ServerRequest,
16
+ (request) =>
17
+ Effect.tap(
18
+ Effect.tapErrorCause(httpApp, (cause) =>
19
+ Effect.annotateLogs(Effect.log(cause), {
20
+ "http.method": request.method,
21
+ "http.url": request.url,
22
+ "http.status": 500
23
+ })),
24
+ (response) =>
25
+ Effect.annotateLogs(Effect.log(""), {
21
26
  "http.method": request.method,
22
27
  "http.url": request.url,
23
- "http.status": exit._tag === "Success" ? exit.value.status : 500
28
+ "http.status": response.status
24
29
  })
25
30
  )
26
31
  ),
@@ -46,13 +51,14 @@ export const tracer = make((httpApp) =>
46
51
 
47
52
  /** @internal */
48
53
  export const xForwardedHeaders = make((httpApp) =>
49
- Effect.flatMap(ServerRequest.ServerRequest, (request) => {
50
- const forwardedHost = Headers.get(request.headers, "x-forwarded-host")
51
- return forwardedHost._tag === "Some"
52
- ? Effect.updateService(httpApp, ServerRequest.ServerRequest, (_) =>
53
- _.replaceHeaders(Headers.set(request.headers, "host", forwardedHost.value)))
54
- : httpApp
55
- })
54
+ Effect.updateService(httpApp, ServerRequest.ServerRequest, (request) =>
55
+ request.headers["x-forwarded-host"]
56
+ ? request.replaceHeaders(Headers.set(
57
+ request.headers,
58
+ "host",
59
+ request.headers["x-forwarded-host"]
60
+ ))
61
+ : request)
56
62
  )
57
63
 
58
64
  /** @internal */
@@ -95,15 +95,12 @@ const toHttpApp = <R, E>(
95
95
  self: Router.Router<R, E>
96
96
  ): App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> => {
97
97
  const router = FindMyWay()
98
- Chunk.forEach(self.mounts, ([path, app]) => {
99
- const fn = () => {}
100
- fn.handler = Effect.updateService(app, ServerRequest.ServerRequest, (request) => sliceRequestUrl(request, path))
101
- router.all(path, fn)
102
- router.all(path + "/*", fn)
103
- })
98
+ const mounts = Chunk.toReadonlyArray(self.mounts)
99
+ const mountsLen = mounts.length
104
100
  Chunk.forEach(self.routes, (route) => {
105
- const fn = () => {}
106
- fn.handler = route
101
+ function fn(_: any, __: any) {
102
+ return route
103
+ }
107
104
  if (route.method === "*") {
108
105
  router.all(route.path, fn)
109
106
  } else {
@@ -113,27 +110,36 @@ const toHttpApp = <R, E>(
113
110
  return Effect.flatMap(
114
111
  ServerRequest.ServerRequest,
115
112
  (request): App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> => {
113
+ if (mountsLen > 0) {
114
+ for (let i = 0; i < mountsLen; i++) {
115
+ const [path, app] = mounts[i]
116
+ if (request.url.startsWith(path)) {
117
+ return Effect.provideService(
118
+ app,
119
+ ServerRequest.ServerRequest,
120
+ sliceRequestUrl(request, path)
121
+ ) as App.Default<Exclude<R, Router.RouteContext>, E>
122
+ }
123
+ }
124
+ }
125
+
116
126
  const result = router.find(request.method as HTTPMethod, request.url)
117
127
  if (result === null) {
118
128
  return Effect.fail(Error.RouteNotFound({ request }))
119
129
  }
120
- const handler = (result.handler as any).handler
121
- if (RouteTypeId in handler) {
122
- const route = handler as Router.Route<R, E>
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
- )
130
+ const route = (result.handler as any)() as Router.Route<R, E>
131
+ if (route.prefix._tag === "Some") {
132
+ request = sliceRequestUrl(request, route.prefix.value)
135
133
  }
136
- return (handler as App.Default<Exclude<R, Router.RouteContext>, E>)
134
+ return Effect.mapInputContext(
135
+ route.handler,
136
+ (context) =>
137
+ Context.add(
138
+ Context.add(context, ServerRequest.ServerRequest, request),
139
+ RouteContext,
140
+ new RouteContextImpl(result.params, result.searchParams)
141
+ ) as Context.Context<R>
142
+ )
137
143
  }
138
144
  )
139
145
  }
@@ -19,13 +19,26 @@ export const TypeId: ServerResponse.TypeId = Symbol.for("@effect/platform/Http/S
19
19
 
20
20
  class ServerResponseImpl implements ServerResponse.ServerResponse {
21
21
  readonly [TypeId]: ServerResponse.TypeId
22
+ readonly headers: Headers.Headers
22
23
  constructor(
23
24
  readonly status: number,
24
25
  readonly statusText: string | undefined,
25
- readonly headers: Headers.Headers,
26
+ headers: Headers.Headers,
26
27
  readonly body: Body.Body
27
28
  ) {
28
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
+ }
29
42
  }
30
43
  pipe() {
31
44
  return pipeArguments(this, arguments)
@@ -77,7 +90,7 @@ export const uint8Array = (
77
90
  options?.status ?? 200,
78
91
  options?.statusText,
79
92
  options?.headers ?? Headers.empty,
80
- internalBody.uint8Array(body, options?.contentType)
93
+ internalBody.uint8Array(body, getContentType(options))
81
94
  )
82
95
 
83
96
  /** @internal */
@@ -86,7 +99,7 @@ export const text = (body: string, options?: ServerResponse.Options.WithContentT
86
99
  options?.status ?? 200,
87
100
  options?.statusText,
88
101
  options?.headers ?? Headers.empty,
89
- internalBody.text(body, options?.contentType)
102
+ internalBody.text(body, getContentType(options))
90
103
  )
91
104
 
92
105
  /** @internal */
@@ -188,9 +201,20 @@ export const stream = (
188
201
  options?.status ?? 200,
189
202
  options?.statusText,
190
203
  options?.headers ?? Headers.empty,
191
- internalBody.stream(body, options?.contentType, options?.contentLength)
204
+ internalBody.stream(body, getContentType(options), options?.contentLength)
192
205
  )
193
206
 
207
+ /** @internal */
208
+ export const getContentType = (options?: ServerResponse.Options): string | undefined => {
209
+ if (options?.contentType) {
210
+ return options.contentType
211
+ } else if (options?.headers) {
212
+ return options.headers["content-type"]
213
+ } else {
214
+ return
215
+ }
216
+ }
217
+
194
218
  /** @internal */
195
219
  export const setHeader = dual<
196
220
  (key: string, value: string) => (self: ServerResponse.ServerResponse) => ServerResponse.ServerResponse,
@@ -235,16 +259,6 @@ export const setBody = dual<
235
259
  let headers = self.headers
236
260
  if (body._tag === "Empty") {
237
261
  headers = Headers.remove(Headers.remove(headers, "Content-Type"), "Content-length")
238
- } else {
239
- const contentType = body.contentType
240
- if (contentType) {
241
- headers = Headers.set(headers, "content-type", contentType)
242
- }
243
-
244
- const contentLength = body.contentLength
245
- if (contentLength) {
246
- headers = Headers.set(headers, "content-length", contentLength.toString())
247
- }
248
262
  }
249
263
  return new ServerResponseImpl(
250
264
  self.status,