@effect/platform 0.31.0 → 0.31.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.
- package/dist/cjs/Http/App.js +43 -1
- package/dist/cjs/Http/App.js.map +1 -1
- package/dist/cjs/Http/Middleware.js +11 -1
- package/dist/cjs/Http/Middleware.js.map +1 -1
- package/dist/cjs/Http/ServerRequest.js +6 -1
- package/dist/cjs/Http/ServerRequest.js.map +1 -1
- package/dist/cjs/Http/ServerResponse.js +6 -1
- package/dist/cjs/Http/ServerResponse.js.map +1 -1
- package/dist/cjs/internal/http/middleware.js +7 -2
- package/dist/cjs/internal/http/middleware.js.map +1 -1
- package/dist/cjs/internal/http/serverRequest.js +112 -1
- package/dist/cjs/internal/http/serverRequest.js.map +1 -1
- package/dist/cjs/internal/http/serverResponse.js +49 -1
- package/dist/cjs/internal/http/serverResponse.js.map +1 -1
- package/dist/dts/Http/App.d.ts +22 -2
- package/dist/dts/Http/App.d.ts.map +1 -1
- package/dist/dts/Http/Middleware.d.ts +15 -0
- package/dist/dts/Http/Middleware.d.ts.map +1 -1
- package/dist/dts/Http/ServerRequest.d.ts +5 -0
- package/dist/dts/Http/ServerRequest.d.ts.map +1 -1
- package/dist/dts/Http/ServerResponse.d.ts +5 -0
- package/dist/dts/Http/ServerResponse.d.ts.map +1 -1
- package/dist/esm/Http/App.js +40 -0
- package/dist/esm/Http/App.js.map +1 -1
- package/dist/esm/Http/Middleware.js +10 -0
- package/dist/esm/Http/Middleware.js.map +1 -1
- package/dist/esm/Http/ServerRequest.js +5 -0
- package/dist/esm/Http/ServerRequest.js.map +1 -1
- package/dist/esm/Http/ServerResponse.js +5 -0
- package/dist/esm/Http/ServerResponse.js.map +1 -1
- package/dist/esm/internal/http/middleware.js +6 -1
- package/dist/esm/internal/http/middleware.js.map +1 -1
- package/dist/esm/internal/http/serverRequest.js +110 -0
- package/dist/esm/internal/http/serverRequest.js.map +1 -1
- package/dist/esm/internal/http/serverResponse.js +47 -0
- package/dist/esm/internal/http/serverResponse.js.map +1 -1
- package/package.json +1 -1
- package/src/Http/App.ts +50 -2
- package/src/Http/Middleware.ts +23 -0
- package/src/Http/ServerRequest.ts +6 -0
- package/src/Http/ServerResponse.ts +6 -0
- package/src/internal/http/middleware.ts +28 -7
- package/src/internal/http/serverRequest.ts +159 -0
- package/src/internal/http/serverResponse.ts +44 -1
package/src/Http/Middleware.ts
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type * as Effect from "effect/Effect"
|
|
5
5
|
import type * as FiberRef from "effect/FiberRef"
|
|
6
|
+
import type * as Predicate from "effect/Predicate"
|
|
6
7
|
import * as internal from "../internal/http/middleware.js"
|
|
7
8
|
import type * as App from "./App.js"
|
|
9
|
+
import type * as ServerRequest from "./ServerRequest.js"
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* @since 1.0.0
|
|
@@ -51,6 +53,27 @@ export const loggerDisabled: FiberRef.FiberRef<boolean> = internal.loggerDisable
|
|
|
51
53
|
export const withLoggerDisabled: <R, E, A>(self: Effect.Effect<R, E, A>) => Effect.Effect<R, E, A> =
|
|
52
54
|
internal.withLoggerDisabled
|
|
53
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @since 1.0.0
|
|
58
|
+
* @category fiber refs
|
|
59
|
+
*/
|
|
60
|
+
export const currentTracerDisabledWhen: FiberRef.FiberRef<Predicate.Predicate<ServerRequest.ServerRequest>> =
|
|
61
|
+
internal.currentTracerDisabledWhen
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @since 1.0.0
|
|
65
|
+
* @category fiber refs
|
|
66
|
+
*/
|
|
67
|
+
export const withTracerDisabledWhen: {
|
|
68
|
+
(
|
|
69
|
+
predicate: Predicate.Predicate<ServerRequest.ServerRequest>
|
|
70
|
+
): <R, E, A>(effect: Effect.Effect<R, E, A>) => Effect.Effect<R, E, A>
|
|
71
|
+
<R, E, A>(
|
|
72
|
+
effect: Effect.Effect<R, E, A>,
|
|
73
|
+
predicate: Predicate.Predicate<ServerRequest.ServerRequest>
|
|
74
|
+
): Effect.Effect<R, E, A>
|
|
75
|
+
} = internal.withTracerDisabledWhen
|
|
76
|
+
|
|
54
77
|
/**
|
|
55
78
|
* @since 1.0.0
|
|
56
79
|
* @category constructors
|
|
@@ -127,3 +127,9 @@ export const schemaFormDataJson: <I, A>(
|
|
|
127
127
|
Error.RequestError | FormData.FormDataError | ParseResult.ParseError,
|
|
128
128
|
A
|
|
129
129
|
> = internal.schemaFormDataJson
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @since 1.0.0
|
|
133
|
+
* @category conversions
|
|
134
|
+
*/
|
|
135
|
+
export const fromWeb: (request: Request) => ServerRequest = internal.fromWeb
|
|
@@ -190,3 +190,9 @@ export const setStatus: {
|
|
|
190
190
|
(status: number, statusText?: string | undefined): (self: ServerResponse) => ServerResponse
|
|
191
191
|
(self: ServerResponse, status: number, statusText?: string | undefined): ServerResponse
|
|
192
192
|
} = internal.setStatus
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @since 1.0.0
|
|
196
|
+
* @category conversions
|
|
197
|
+
*/
|
|
198
|
+
export const toWeb: (response: ServerResponse, withoutBody?: boolean) => Response = internal.toWeb
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect"
|
|
2
2
|
import * as FiberRef from "effect/FiberRef"
|
|
3
|
+
import * as Function from "effect/Function"
|
|
3
4
|
import { globalValue } from "effect/GlobalValue"
|
|
5
|
+
import type * as Predicate from "effect/Predicate"
|
|
4
6
|
import * as Headers from "../../Http/Headers.js"
|
|
5
7
|
import * as IncomingMessage from "../../Http/IncomingMessage.js"
|
|
6
8
|
import type * as Middleware from "../../Http/Middleware.js"
|
|
@@ -22,6 +24,23 @@ export const withLoggerDisabled = <R, E, A>(self: Effect.Effect<R, E, A>): Effec
|
|
|
22
24
|
self
|
|
23
25
|
)
|
|
24
26
|
|
|
27
|
+
/** @internal */
|
|
28
|
+
export const currentTracerDisabledWhen = globalValue(
|
|
29
|
+
Symbol.for("@effect/platform/Http/Middleware/tracerDisabledWhen"),
|
|
30
|
+
() => FiberRef.unsafeMake<Predicate.Predicate<ServerRequest.ServerRequest>>(Function.constFalse)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
/** @internal */
|
|
34
|
+
export const withTracerDisabledWhen = Function.dual<
|
|
35
|
+
(
|
|
36
|
+
predicate: Predicate.Predicate<ServerRequest.ServerRequest>
|
|
37
|
+
) => <R, E, A>(effect: Effect.Effect<R, E, A>) => Effect.Effect<R, E, A>,
|
|
38
|
+
<R, E, A>(
|
|
39
|
+
effect: Effect.Effect<R, E, A>,
|
|
40
|
+
predicate: Predicate.Predicate<ServerRequest.ServerRequest>
|
|
41
|
+
) => Effect.Effect<R, E, A>
|
|
42
|
+
>(2, (self, pred) => Effect.locally(self, currentTracerDisabledWhen, pred))
|
|
43
|
+
|
|
25
44
|
/** @internal */
|
|
26
45
|
export const logger = make((httpApp) => {
|
|
27
46
|
let counter = 0
|
|
@@ -61,18 +80,20 @@ export const tracer = make((httpApp) => {
|
|
|
61
80
|
(response) => Effect.annotateCurrentSpan("http.status", response.status)
|
|
62
81
|
)
|
|
63
82
|
return Effect.flatMap(
|
|
64
|
-
ServerRequest.ServerRequest,
|
|
65
|
-
(request) =>
|
|
83
|
+
Effect.zip(ServerRequest.ServerRequest, FiberRef.get(currentTracerDisabledWhen)),
|
|
84
|
+
([request, disabledWhen]) =>
|
|
66
85
|
Effect.flatMap(
|
|
67
86
|
request.headers["x-b3-traceid"] || request.headers["b3"] ?
|
|
68
87
|
Effect.orElseSucceed(IncomingMessage.schemaExternalSpan(request), () => undefined) :
|
|
69
88
|
Effect.succeed(undefined),
|
|
70
89
|
(parent) =>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
disabledWhen(request) ?
|
|
91
|
+
httpApp :
|
|
92
|
+
Effect.withSpan(
|
|
93
|
+
appWithStatus,
|
|
94
|
+
`http ${request.method}`,
|
|
95
|
+
{ attributes: { "http.method": request.method, "http.url": request.url }, parent }
|
|
96
|
+
)
|
|
76
97
|
)
|
|
77
98
|
)
|
|
78
99
|
})
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type * as Schema from "@effect/schema/Schema"
|
|
2
2
|
import * as Context from "effect/Context"
|
|
3
3
|
import * as Effect from "effect/Effect"
|
|
4
|
+
import * as Option from "effect/Option"
|
|
5
|
+
import type * as Scope from "effect/Scope"
|
|
6
|
+
import * as Stream from "effect/Stream"
|
|
7
|
+
import type * as FileSystem from "../../FileSystem.js"
|
|
4
8
|
import * as FormData from "../../Http/FormData.js"
|
|
9
|
+
import * as Headers from "../../Http/Headers.js"
|
|
5
10
|
import * as IncomingMessage from "../../Http/IncomingMessage.js"
|
|
11
|
+
import type { Method } from "../../Http/Method.js"
|
|
6
12
|
import * as Error from "../../Http/ServerError.js"
|
|
7
13
|
import type * as ServerRequest from "../../Http/ServerRequest.js"
|
|
14
|
+
import * as UrlParams from "../../Http/UrlParams.js"
|
|
15
|
+
import type * as Path from "../../Path.js"
|
|
8
16
|
|
|
9
17
|
/** @internal */
|
|
10
18
|
export const TypeId: ServerRequest.TypeId = Symbol.for("@effect/platform/Http/ServerRequest") as ServerRequest.TypeId
|
|
@@ -63,3 +71,154 @@ export const schemaFormDataJson = <I, A>(schema: Schema.Schema<I, A>) => {
|
|
|
63
71
|
)
|
|
64
72
|
))
|
|
65
73
|
}
|
|
74
|
+
|
|
75
|
+
/** @internal */
|
|
76
|
+
export const fromWeb = (request: globalThis.Request): ServerRequest.ServerRequest =>
|
|
77
|
+
new ServerRequestImpl(request, request.url)
|
|
78
|
+
|
|
79
|
+
class ServerRequestImpl implements ServerRequest.ServerRequest {
|
|
80
|
+
readonly [TypeId]: ServerRequest.TypeId
|
|
81
|
+
readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId
|
|
82
|
+
constructor(
|
|
83
|
+
readonly source: Request,
|
|
84
|
+
readonly url: string,
|
|
85
|
+
public headersOverride?: Headers.Headers,
|
|
86
|
+
private remoteAddressOverride?: string
|
|
87
|
+
) {
|
|
88
|
+
this[TypeId] = TypeId
|
|
89
|
+
this[IncomingMessage.TypeId] = IncomingMessage.TypeId
|
|
90
|
+
}
|
|
91
|
+
modify(
|
|
92
|
+
options: {
|
|
93
|
+
readonly url?: string | undefined
|
|
94
|
+
readonly headers?: Headers.Headers | undefined
|
|
95
|
+
readonly remoteAddress?: string | undefined
|
|
96
|
+
}
|
|
97
|
+
) {
|
|
98
|
+
return new ServerRequestImpl(
|
|
99
|
+
this.source,
|
|
100
|
+
options.url ?? this.url,
|
|
101
|
+
options.headers ?? this.headersOverride,
|
|
102
|
+
options.remoteAddress ?? this.remoteAddressOverride
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
get method(): Method {
|
|
106
|
+
return this.source.method.toUpperCase() as Method
|
|
107
|
+
}
|
|
108
|
+
get originalUrl() {
|
|
109
|
+
return this.source.url
|
|
110
|
+
}
|
|
111
|
+
get remoteAddress(): Option.Option<string> {
|
|
112
|
+
return this.remoteAddressOverride ? Option.some(this.remoteAddressOverride) : Option.none()
|
|
113
|
+
}
|
|
114
|
+
get headers(): Headers.Headers {
|
|
115
|
+
this.headersOverride ??= Headers.fromInput(this.source.headers)
|
|
116
|
+
return this.headersOverride
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get stream(): Stream.Stream<never, Error.RequestError, Uint8Array> {
|
|
120
|
+
return this.source.body
|
|
121
|
+
? Stream.fromReadableStream(() => this.source.body as any, (_) =>
|
|
122
|
+
Error.RequestError({
|
|
123
|
+
request: this,
|
|
124
|
+
reason: "Decode",
|
|
125
|
+
error: _
|
|
126
|
+
}))
|
|
127
|
+
: Stream.fail(Error.RequestError({
|
|
128
|
+
request: this,
|
|
129
|
+
reason: "Decode",
|
|
130
|
+
error: "can not create stream from empty body"
|
|
131
|
+
}))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private textEffect: Effect.Effect<never, Error.RequestError, string> | undefined
|
|
135
|
+
get text(): Effect.Effect<never, Error.RequestError, string> {
|
|
136
|
+
if (this.textEffect) {
|
|
137
|
+
return this.textEffect
|
|
138
|
+
}
|
|
139
|
+
this.textEffect = Effect.runSync(Effect.cached(
|
|
140
|
+
Effect.tryPromise({
|
|
141
|
+
try: () => this.source.text(),
|
|
142
|
+
catch: (error) =>
|
|
143
|
+
Error.RequestError({
|
|
144
|
+
request: this,
|
|
145
|
+
reason: "Decode",
|
|
146
|
+
error
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
))
|
|
150
|
+
return this.textEffect
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
get json(): Effect.Effect<never, Error.RequestError, unknown> {
|
|
154
|
+
return Effect.tryMap(this.text, {
|
|
155
|
+
try: (_) => JSON.parse(_) as unknown,
|
|
156
|
+
catch: (error) =>
|
|
157
|
+
Error.RequestError({
|
|
158
|
+
request: this,
|
|
159
|
+
reason: "Decode",
|
|
160
|
+
error
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
get urlParamsBody(): Effect.Effect<never, Error.RequestError, UrlParams.UrlParams> {
|
|
166
|
+
return Effect.flatMap(this.text, (_) =>
|
|
167
|
+
Effect.try({
|
|
168
|
+
try: () => UrlParams.fromInput(new URLSearchParams(_)),
|
|
169
|
+
catch: (error) =>
|
|
170
|
+
Error.RequestError({
|
|
171
|
+
request: this,
|
|
172
|
+
reason: "Decode",
|
|
173
|
+
error
|
|
174
|
+
})
|
|
175
|
+
}))
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private formDataEffect:
|
|
179
|
+
| Effect.Effect<
|
|
180
|
+
Scope.Scope | FileSystem.FileSystem | Path.Path,
|
|
181
|
+
FormData.FormDataError,
|
|
182
|
+
FormData.PersistedFormData
|
|
183
|
+
>
|
|
184
|
+
| undefined
|
|
185
|
+
get formData(): Effect.Effect<
|
|
186
|
+
Scope.Scope | FileSystem.FileSystem | Path.Path,
|
|
187
|
+
FormData.FormDataError,
|
|
188
|
+
FormData.PersistedFormData
|
|
189
|
+
> {
|
|
190
|
+
if (this.formDataEffect) {
|
|
191
|
+
return this.formDataEffect
|
|
192
|
+
}
|
|
193
|
+
this.formDataEffect = Effect.runSync(Effect.cached(
|
|
194
|
+
FormData.formData(this.formDataStream)
|
|
195
|
+
))
|
|
196
|
+
return this.formDataEffect
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
get formDataStream(): Stream.Stream<never, FormData.FormDataError, FormData.Part> {
|
|
200
|
+
return Stream.pipeThroughChannel(
|
|
201
|
+
Stream.mapError(this.stream, (error) => FormData.FormDataError("InternalError", error)),
|
|
202
|
+
FormData.makeChannel(this.headers)
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private arrayBufferEffect: Effect.Effect<never, Error.RequestError, ArrayBuffer> | undefined
|
|
207
|
+
get arrayBuffer(): Effect.Effect<never, Error.RequestError, ArrayBuffer> {
|
|
208
|
+
if (this.arrayBuffer) {
|
|
209
|
+
return this.arrayBuffer
|
|
210
|
+
}
|
|
211
|
+
this.arrayBufferEffect = Effect.runSync(Effect.cached(
|
|
212
|
+
Effect.tryPromise({
|
|
213
|
+
try: () => this.source.arrayBuffer(),
|
|
214
|
+
catch: (error) =>
|
|
215
|
+
Error.RequestError({
|
|
216
|
+
request: this,
|
|
217
|
+
reason: "Decode",
|
|
218
|
+
error
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
))
|
|
222
|
+
return this.arrayBufferEffect
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -2,7 +2,7 @@ import type * as Schema from "@effect/schema/Schema"
|
|
|
2
2
|
import * as Effect from "effect/Effect"
|
|
3
3
|
import * as Effectable from "effect/Effectable"
|
|
4
4
|
import { dual } from "effect/Function"
|
|
5
|
-
import
|
|
5
|
+
import * as Stream from "effect/Stream"
|
|
6
6
|
import type * as PlatformError from "../../Error.js"
|
|
7
7
|
import type * as FileSystem from "../../FileSystem.js"
|
|
8
8
|
import type * as Body from "../../Http/Body.js"
|
|
@@ -259,3 +259,46 @@ export const setBody = dual<
|
|
|
259
259
|
body
|
|
260
260
|
)
|
|
261
261
|
})
|
|
262
|
+
|
|
263
|
+
/** @internal */
|
|
264
|
+
export const toWeb = (response: ServerResponse.ServerResponse, withoutBody = false): Response => {
|
|
265
|
+
if (withoutBody) {
|
|
266
|
+
return new Response(undefined, {
|
|
267
|
+
status: response.status,
|
|
268
|
+
statusText: response.statusText,
|
|
269
|
+
headers: response.headers
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
const body = response.body
|
|
273
|
+
switch (body._tag) {
|
|
274
|
+
case "Empty": {
|
|
275
|
+
return new Response(undefined, {
|
|
276
|
+
status: response.status,
|
|
277
|
+
statusText: response.statusText,
|
|
278
|
+
headers: response.headers
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
case "Uint8Array":
|
|
282
|
+
case "Raw": {
|
|
283
|
+
return new Response(body.body as any, {
|
|
284
|
+
status: response.status,
|
|
285
|
+
statusText: response.statusText,
|
|
286
|
+
headers: response.headers
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
case "FormData": {
|
|
290
|
+
return new Response(body.formData as any, {
|
|
291
|
+
status: response.status,
|
|
292
|
+
statusText: response.statusText,
|
|
293
|
+
headers: response.headers
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
case "Stream": {
|
|
297
|
+
return new Response(Stream.toReadableStream(body.stream), {
|
|
298
|
+
status: response.status,
|
|
299
|
+
statusText: response.statusText,
|
|
300
|
+
headers: response.headers
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|