@effect/platform 0.48.22 → 0.48.24
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/TraceContext/package.json +6 -0
- package/dist/cjs/FileSystem.js.map +1 -1
- package/dist/cjs/Http/Client.js +11 -1
- package/dist/cjs/Http/Client.js.map +1 -1
- package/dist/cjs/Http/IncomingMessage.js +2 -51
- package/dist/cjs/Http/IncomingMessage.js.map +1 -1
- package/dist/cjs/Http/Router.js.map +1 -1
- package/dist/cjs/Http/TraceContext.js +132 -0
- package/dist/cjs/Http/TraceContext.js.map +1 -0
- package/dist/cjs/internal/http/client.js +51 -34
- package/dist/cjs/internal/http/client.js.map +1 -1
- package/dist/cjs/internal/http/middleware.js +36 -22
- package/dist/cjs/internal/http/middleware.js.map +1 -1
- package/dist/dts/FileSystem.d.ts +7 -3
- package/dist/dts/FileSystem.d.ts.map +1 -1
- package/dist/dts/Http/Client.d.ts +16 -1
- package/dist/dts/Http/Client.d.ts.map +1 -1
- package/dist/dts/Http/IncomingMessage.d.ts +1 -7
- package/dist/dts/Http/IncomingMessage.d.ts.map +1 -1
- package/dist/dts/Http/Router.d.ts +17 -17
- package/dist/dts/Http/Router.d.ts.map +1 -1
- package/dist/dts/Http/TraceContext.d.ts +39 -0
- package/dist/dts/Http/TraceContext.d.ts.map +1 -0
- package/dist/esm/FileSystem.js.map +1 -1
- package/dist/esm/Http/Client.js +10 -0
- package/dist/esm/Http/Client.js.map +1 -1
- package/dist/esm/Http/IncomingMessage.js +1 -50
- package/dist/esm/Http/IncomingMessage.js.map +1 -1
- package/dist/esm/Http/Router.js.map +1 -1
- package/dist/esm/Http/TraceContext.js +95 -0
- package/dist/esm/Http/TraceContext.js.map +1 -0
- package/dist/esm/internal/http/client.js +50 -33
- package/dist/esm/internal/http/client.js.map +1 -1
- package/dist/esm/internal/http/middleware.js +36 -22
- package/dist/esm/internal/http/middleware.js.map +1 -1
- package/package.json +11 -3
- package/src/FileSystem.ts +7 -3
- package/src/Http/Client.ts +25 -1
- package/src/Http/IncomingMessage.ts +2 -71
- package/src/Http/Router.ts +21 -20
- package/src/Http/TraceContext.ts +109 -0
- package/src/internal/http/client.ts +89 -55
- package/src/internal/http/middleware.ts +46 -49
- package/src/internal/http/router.ts +17 -17
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
import type { ParseOptions } from "@effect/schema/AST"
|
|
5
|
-
import * as ParseResult from "@effect/schema/ParseResult"
|
|
5
|
+
import type * as ParseResult from "@effect/schema/ParseResult"
|
|
6
6
|
import * as Schema from "@effect/schema/Schema"
|
|
7
7
|
import * as Effect from "effect/Effect"
|
|
8
8
|
import * as FiberRef from "effect/FiberRef"
|
|
9
|
-
import { dual
|
|
9
|
+
import { dual } from "effect/Function"
|
|
10
10
|
import * as Global from "effect/GlobalValue"
|
|
11
11
|
import type { Inspectable } from "effect/Inspectable"
|
|
12
12
|
import * as Option from "effect/Option"
|
|
13
13
|
import type * as Stream from "effect/Stream"
|
|
14
|
-
import * as Tracer from "effect/Tracer"
|
|
15
|
-
import type { ExternalSpan } from "effect/Tracer"
|
|
16
14
|
import * as FileSystem from "../FileSystem.js"
|
|
17
15
|
import type * as Headers from "./Headers.js"
|
|
18
16
|
import type * as UrlParams from "./UrlParams.js"
|
|
@@ -112,73 +110,6 @@ export const schemaHeadersEffect = <R, I extends Readonly<Record<string, string>
|
|
|
112
110
|
return <E, E2, R2>(effect: Effect.Effect<IncomingMessage<E>, E2, R2>) => Effect.scoped(Effect.flatMap(effect, decode))
|
|
113
111
|
}
|
|
114
112
|
|
|
115
|
-
const SpanSchema = Schema.struct({
|
|
116
|
-
traceId: Schema.string,
|
|
117
|
-
spanId: Schema.string,
|
|
118
|
-
parentSpanId: Schema.union(Schema.string, Schema.undefined),
|
|
119
|
-
sampled: Schema.boolean
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* @since 1.0.0
|
|
124
|
-
* @category schema
|
|
125
|
-
*/
|
|
126
|
-
export const schemaExternalSpan: <E>(
|
|
127
|
-
self: IncomingMessage<E>
|
|
128
|
-
) => Effect.Effect<Tracer.ExternalSpan, ParseResult.ParseError> = flow(
|
|
129
|
-
schemaHeaders(Schema.union(
|
|
130
|
-
Schema.transformOrFail(
|
|
131
|
-
Schema.struct({
|
|
132
|
-
b3: Schema.NonEmpty
|
|
133
|
-
}),
|
|
134
|
-
SpanSchema,
|
|
135
|
-
(input, _, ast) => {
|
|
136
|
-
const parts = input.b3.split("-")
|
|
137
|
-
if (parts.length >= 2) {
|
|
138
|
-
return ParseResult.succeed(
|
|
139
|
-
{
|
|
140
|
-
traceId: parts[0],
|
|
141
|
-
spanId: parts[1],
|
|
142
|
-
sampled: parts[2] ? parts[2] === "1" : true,
|
|
143
|
-
parentSpanId: parts[3]
|
|
144
|
-
} as const
|
|
145
|
-
)
|
|
146
|
-
}
|
|
147
|
-
return ParseResult.fail(new ParseResult.Type(ast, input))
|
|
148
|
-
},
|
|
149
|
-
(_) => ParseResult.succeed({ b3: "" } as const)
|
|
150
|
-
),
|
|
151
|
-
Schema.transform(
|
|
152
|
-
Schema.struct({
|
|
153
|
-
"x-b3-traceid": Schema.NonEmpty,
|
|
154
|
-
"x-b3-spanid": Schema.NonEmpty,
|
|
155
|
-
"x-b3-parentspanid": Schema.optional(Schema.NonEmpty),
|
|
156
|
-
"x-b3-sampled": Schema.optional(Schema.NonEmpty, { default: () => "1" })
|
|
157
|
-
}),
|
|
158
|
-
SpanSchema,
|
|
159
|
-
(_) => ({
|
|
160
|
-
traceId: _["x-b3-traceid"],
|
|
161
|
-
spanId: _["x-b3-spanid"],
|
|
162
|
-
parentSpanId: _["x-b3-parentspanid"],
|
|
163
|
-
sampled: _["x-b3-sampled"] === "1"
|
|
164
|
-
} as const),
|
|
165
|
-
(_) => ({
|
|
166
|
-
"x-b3-traceid": _.traceId,
|
|
167
|
-
"x-b3-spanid": _.spanId,
|
|
168
|
-
"x-b3-parentspanid": _.parentSpanId,
|
|
169
|
-
"x-b3-sampled": _.sampled ? "1" : "0"
|
|
170
|
-
} as const)
|
|
171
|
-
)
|
|
172
|
-
)),
|
|
173
|
-
Effect.map((_): ExternalSpan =>
|
|
174
|
-
Tracer.externalSpan({
|
|
175
|
-
traceId: _.traceId,
|
|
176
|
-
spanId: _.spanId,
|
|
177
|
-
sampled: _.sampled
|
|
178
|
-
})
|
|
179
|
-
)
|
|
180
|
-
)
|
|
181
|
-
|
|
182
113
|
/**
|
|
183
114
|
* @since 1.0.0
|
|
184
115
|
* @category fiber refs
|
package/src/Http/Router.ts
CHANGED
|
@@ -155,20 +155,22 @@ export const searchParams: Effect.Effect<
|
|
|
155
155
|
*/
|
|
156
156
|
export const schemaJson: <
|
|
157
157
|
R,
|
|
158
|
-
I extends
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
158
|
+
I extends Partial<
|
|
159
|
+
{
|
|
160
|
+
readonly method: Method.Method
|
|
161
|
+
readonly url: string
|
|
162
|
+
readonly cookies: Readonly<Record<string, string>>
|
|
163
|
+
readonly headers: Readonly<Record<string, string>>
|
|
164
|
+
readonly pathParams: Readonly<Record<string, string>>
|
|
165
|
+
readonly searchParams: Readonly<Record<string, string>>
|
|
166
|
+
readonly body: any
|
|
167
|
+
}
|
|
168
|
+
>,
|
|
167
169
|
A
|
|
168
170
|
>(
|
|
169
171
|
schema: Schema.Schema<A, I, R>,
|
|
170
172
|
options?: ParseOptions | undefined
|
|
171
|
-
) => Effect.Effect<A,
|
|
173
|
+
) => Effect.Effect<A, Error.RequestError | ParseResult.ParseError, RouteContext | R | ServerRequest.ServerRequest> =
|
|
172
174
|
internal.schemaJson
|
|
173
175
|
|
|
174
176
|
/**
|
|
@@ -177,20 +179,19 @@ export const schemaJson: <
|
|
|
177
179
|
*/
|
|
178
180
|
export const schemaNoBody: <
|
|
179
181
|
R,
|
|
180
|
-
I extends {
|
|
181
|
-
readonly method
|
|
182
|
-
readonly url
|
|
183
|
-
readonly cookies
|
|
184
|
-
readonly headers
|
|
185
|
-
readonly pathParams
|
|
186
|
-
readonly searchParams
|
|
187
|
-
}
|
|
182
|
+
I extends Partial<{
|
|
183
|
+
readonly method: Method.Method
|
|
184
|
+
readonly url: string
|
|
185
|
+
readonly cookies: Readonly<Record<string, string>>
|
|
186
|
+
readonly headers: Readonly<Record<string, string>>
|
|
187
|
+
readonly pathParams: Readonly<Record<string, string>>
|
|
188
|
+
readonly searchParams: Readonly<Record<string, string>>
|
|
189
|
+
}>,
|
|
188
190
|
A
|
|
189
191
|
>(
|
|
190
192
|
schema: Schema.Schema<A, I, R>,
|
|
191
193
|
options?: ParseOptions | undefined
|
|
192
|
-
) => Effect.Effect<A, ParseResult.ParseError
|
|
193
|
-
internal.schemaNoBody
|
|
194
|
+
) => Effect.Effect<A, ParseResult.ParseError, R | RouteContext | ServerRequest.ServerRequest> = internal.schemaNoBody
|
|
194
195
|
|
|
195
196
|
/**
|
|
196
197
|
* @since 1.0.0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import * as Option from "effect/Option"
|
|
5
|
+
import * as Tracer from "effect/Tracer"
|
|
6
|
+
import * as Headers from "./Headers.js"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @since 1.0.0
|
|
10
|
+
* @category models
|
|
11
|
+
*/
|
|
12
|
+
export interface FromHeaders {
|
|
13
|
+
(headers: Headers.Headers): Option.Option<Tracer.ExternalSpan>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
* @category encoding
|
|
19
|
+
*/
|
|
20
|
+
export const toHeaders = (span: Tracer.Span): Headers.Headers =>
|
|
21
|
+
Headers.unsafeFromRecord({
|
|
22
|
+
b3: `${span.traceId}-${span.spanId}-${span.sampled ? "1" : "0"}${
|
|
23
|
+
span.parent._tag === "Some" ? `-${span.parent.value.spanId}` : ""
|
|
24
|
+
}`,
|
|
25
|
+
traceparent: `00-${span.traceId}-${span.spanId}-${span.sampled ? "01" : "00"}`
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @since 1.0.0
|
|
30
|
+
* @category decoding
|
|
31
|
+
*/
|
|
32
|
+
export const fromHeaders = (headers: Headers.Headers): Option.Option<Tracer.ExternalSpan> => {
|
|
33
|
+
let span = w3c(headers)
|
|
34
|
+
if (span._tag === "Some") {
|
|
35
|
+
return span
|
|
36
|
+
}
|
|
37
|
+
span = b3(headers)
|
|
38
|
+
if (span._tag === "Some") {
|
|
39
|
+
return span
|
|
40
|
+
}
|
|
41
|
+
return xb3(headers)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @since 1.0.0
|
|
46
|
+
* @category decoding
|
|
47
|
+
*/
|
|
48
|
+
export const b3: FromHeaders = (headers) => {
|
|
49
|
+
if (!("b3" in headers)) {
|
|
50
|
+
return Option.none()
|
|
51
|
+
}
|
|
52
|
+
const parts = headers["b3"].split("-")
|
|
53
|
+
if (parts.length < 2) {
|
|
54
|
+
return Option.none()
|
|
55
|
+
}
|
|
56
|
+
return Option.some(Tracer.externalSpan({
|
|
57
|
+
traceId: parts[0],
|
|
58
|
+
spanId: parts[1],
|
|
59
|
+
sampled: parts[2] ? parts[2] === "1" : true
|
|
60
|
+
}))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @since 1.0.0
|
|
65
|
+
* @category decoding
|
|
66
|
+
*/
|
|
67
|
+
export const xb3: FromHeaders = (headers) => {
|
|
68
|
+
if (!(headers["x-b3-traceid"]) || !(headers["x-b3-spanid"])) {
|
|
69
|
+
return Option.none()
|
|
70
|
+
}
|
|
71
|
+
return Option.some(Tracer.externalSpan({
|
|
72
|
+
traceId: headers["x-b3-traceid"],
|
|
73
|
+
spanId: headers["x-b3-spanid"],
|
|
74
|
+
sampled: headers["x-b3-sampled"] ? headers["x-b3-sampled"] === "1" : true
|
|
75
|
+
}))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const w3cTraceId = /^[0-9a-f]{32}$/gi
|
|
79
|
+
const w3cSpanId = /^[0-9a-f]{16}$/gi
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @since 1.0.0
|
|
83
|
+
* @category decoding
|
|
84
|
+
*/
|
|
85
|
+
export const w3c: FromHeaders = (headers) => {
|
|
86
|
+
if (!(headers["traceparent"])) {
|
|
87
|
+
return Option.none()
|
|
88
|
+
}
|
|
89
|
+
const parts = headers["traceparent"].split("-")
|
|
90
|
+
if (parts.length !== 4) {
|
|
91
|
+
return Option.none()
|
|
92
|
+
}
|
|
93
|
+
const [version, traceId, spanId, flags] = parts
|
|
94
|
+
switch (version) {
|
|
95
|
+
case "00": {
|
|
96
|
+
if (w3cTraceId.test(traceId) === false || w3cSpanId.test(spanId) === false) {
|
|
97
|
+
return Option.none()
|
|
98
|
+
}
|
|
99
|
+
return Option.some(Tracer.externalSpan({
|
|
100
|
+
traceId,
|
|
101
|
+
spanId,
|
|
102
|
+
sampled: (parseInt(flags, 16) & 1) === 1
|
|
103
|
+
}))
|
|
104
|
+
}
|
|
105
|
+
default: {
|
|
106
|
+
return Option.none()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -3,7 +3,10 @@ import type * as ParseResult from "@effect/schema/ParseResult"
|
|
|
3
3
|
import * as Schema from "@effect/schema/Schema"
|
|
4
4
|
import * as Context from "effect/Context"
|
|
5
5
|
import * as Effect from "effect/Effect"
|
|
6
|
-
import
|
|
6
|
+
import type * as Fiber from "effect/Fiber"
|
|
7
|
+
import * as FiberRef from "effect/FiberRef"
|
|
8
|
+
import { constFalse, dual, pipe } from "effect/Function"
|
|
9
|
+
import { globalValue } from "effect/GlobalValue"
|
|
7
10
|
import * as Layer from "effect/Layer"
|
|
8
11
|
import { pipeArguments } from "effect/Pipeable"
|
|
9
12
|
import * as Predicate from "effect/Predicate"
|
|
@@ -18,6 +21,7 @@ import type * as ClientRequest from "../../Http/ClientRequest.js"
|
|
|
18
21
|
import type * as ClientResponse from "../../Http/ClientResponse.js"
|
|
19
22
|
import * as Cookies from "../../Http/Cookies.js"
|
|
20
23
|
import * as Method from "../../Http/Method.js"
|
|
24
|
+
import * as TraceContext from "../../Http/TraceContext.js"
|
|
21
25
|
import * as UrlParams from "../../Http/UrlParams.js"
|
|
22
26
|
import * as internalBody from "./body.js"
|
|
23
27
|
import * as internalRequest from "./clientRequest.js"
|
|
@@ -31,6 +35,23 @@ export const TypeId: Client.TypeId = Symbol.for(
|
|
|
31
35
|
/** @internal */
|
|
32
36
|
export const tag = Context.GenericTag<Client.Client.Default>("@effect/platform/Http/Client")
|
|
33
37
|
|
|
38
|
+
/** @internal */
|
|
39
|
+
export const currentTracerDisabledWhen = globalValue(
|
|
40
|
+
Symbol.for("@effect/platform/Http/Client/tracerDisabledWhen"),
|
|
41
|
+
() => FiberRef.unsafeMake<Predicate.Predicate<ClientRequest.ClientRequest>>(constFalse)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
/** @internal */
|
|
45
|
+
export const withTracerDisabledWhen = dual<
|
|
46
|
+
(
|
|
47
|
+
predicate: Predicate.Predicate<ClientRequest.ClientRequest>
|
|
48
|
+
) => <R, E, A>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>,
|
|
49
|
+
<R, E, A>(
|
|
50
|
+
effect: Effect.Effect<A, E, R>,
|
|
51
|
+
predicate: Predicate.Predicate<ClientRequest.ClientRequest>
|
|
52
|
+
) => Effect.Effect<A, E, R>
|
|
53
|
+
>(2, (self, pred) => Effect.locally(self, currentTracerDisabledWhen, pred))
|
|
54
|
+
|
|
34
55
|
const clientProto = {
|
|
35
56
|
[TypeId]: TypeId,
|
|
36
57
|
pipe() {
|
|
@@ -56,25 +77,38 @@ export const make = <R, E, A, R2, E2>(
|
|
|
56
77
|
return client as any
|
|
57
78
|
}
|
|
58
79
|
|
|
59
|
-
const addB3Headers = (req: ClientRequest.ClientRequest) =>
|
|
60
|
-
Effect.match(Effect.currentSpan, {
|
|
61
|
-
onFailure: () => req,
|
|
62
|
-
onSuccess: (span) =>
|
|
63
|
-
internalRequest.setHeader(
|
|
64
|
-
req,
|
|
65
|
-
"b3",
|
|
66
|
-
`${span.traceId}-${span.spanId}-${span.sampled ? "1" : "0"}${
|
|
67
|
-
span.parent._tag === "Some" ? `-${span.parent.value.spanId}` : ""
|
|
68
|
-
}`
|
|
69
|
-
)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
80
|
/** @internal */
|
|
73
81
|
export const makeDefault = (
|
|
74
82
|
f: (
|
|
75
|
-
request: ClientRequest.ClientRequest
|
|
83
|
+
request: ClientRequest.ClientRequest,
|
|
84
|
+
fiber: Fiber.RuntimeFiber<ClientResponse.ClientResponse, Error.HttpClientError>
|
|
76
85
|
) => Effect.Effect<ClientResponse.ClientResponse, Error.HttpClientError, Scope.Scope>
|
|
77
|
-
): Client.Client.Default =>
|
|
86
|
+
): Client.Client.Default =>
|
|
87
|
+
make(
|
|
88
|
+
(effect) =>
|
|
89
|
+
Effect.flatMap(effect, (request) =>
|
|
90
|
+
Effect.withFiberRuntime((fiber) => {
|
|
91
|
+
const tracerDisabled = fiber.getFiberRef(currentTracerDisabledWhen)(request)
|
|
92
|
+
if (tracerDisabled) {
|
|
93
|
+
return f(request, fiber)
|
|
94
|
+
}
|
|
95
|
+
return Effect.useSpan(
|
|
96
|
+
`http.client ${request.method}`,
|
|
97
|
+
{
|
|
98
|
+
attributes: {
|
|
99
|
+
"http.method": request.method,
|
|
100
|
+
"http.url": request.url
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
(span) =>
|
|
104
|
+
Effect.withParentSpan(
|
|
105
|
+
f(internalRequest.setHeaders(request, TraceContext.toHeaders(span)), fiber),
|
|
106
|
+
span
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
})),
|
|
110
|
+
Effect.succeed as Client.Client.Preprocess<never, never>
|
|
111
|
+
)
|
|
78
112
|
|
|
79
113
|
/** @internal */
|
|
80
114
|
export const Fetch = Context.GenericTag<Client.Fetch, typeof globalThis.fetch>(
|
|
@@ -83,52 +117,52 @@ export const Fetch = Context.GenericTag<Client.Fetch, typeof globalThis.fetch>(
|
|
|
83
117
|
|
|
84
118
|
/** @internal */
|
|
85
119
|
export const fetch = (options?: RequestInit): Client.Client.Default =>
|
|
86
|
-
makeDefault((request) =>
|
|
87
|
-
|
|
120
|
+
makeDefault((request, fiber) => {
|
|
121
|
+
const context = fiber.getFiberRef(FiberRef.currentContext)
|
|
122
|
+
const fetch: typeof globalThis.fetch = context.unsafeMap.get(Fetch.key) ?? globalThis.fetch
|
|
123
|
+
return Effect.flatMap(
|
|
88
124
|
UrlParams.makeUrl(request.url, request.urlParams, (_) =>
|
|
89
125
|
new Error.RequestError({
|
|
90
126
|
request,
|
|
91
127
|
reason: "InvalidUrl",
|
|
92
128
|
error: _
|
|
93
129
|
})),
|
|
94
|
-
(url) =>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Effect.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return send(undefined)
|
|
129
|
-
})
|
|
130
|
+
(url) => {
|
|
131
|
+
const headers = new Headers(request.headers)
|
|
132
|
+
const send = (body: BodyInit | undefined) =>
|
|
133
|
+
pipe(
|
|
134
|
+
Effect.acquireRelease(
|
|
135
|
+
Effect.sync(() => new AbortController()),
|
|
136
|
+
(controller) => Effect.sync(() => controller.abort())
|
|
137
|
+
),
|
|
138
|
+
Effect.flatMap((controller) =>
|
|
139
|
+
Effect.tryPromise({
|
|
140
|
+
try: () =>
|
|
141
|
+
fetch(url, {
|
|
142
|
+
...options,
|
|
143
|
+
method: request.method,
|
|
144
|
+
headers,
|
|
145
|
+
body,
|
|
146
|
+
duplex: request.body._tag === "Stream" ? "half" : undefined,
|
|
147
|
+
signal: controller.signal
|
|
148
|
+
} as any),
|
|
149
|
+
catch: (_) =>
|
|
150
|
+
new Error.RequestError({
|
|
151
|
+
request,
|
|
152
|
+
reason: "Transport",
|
|
153
|
+
error: _
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
),
|
|
157
|
+
Effect.map((_) => internalResponse.fromWeb(request, _))
|
|
158
|
+
)
|
|
159
|
+
if (Method.hasBody(request.method)) {
|
|
160
|
+
return send(convertBody(request.body))
|
|
161
|
+
}
|
|
162
|
+
return send(undefined)
|
|
163
|
+
}
|
|
130
164
|
)
|
|
131
|
-
)
|
|
165
|
+
})
|
|
132
166
|
|
|
133
167
|
const convertBody = (body: Body.Body): BodyInit | undefined => {
|
|
134
168
|
switch (body._tag) {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import * as Cause from "effect/Cause"
|
|
2
|
+
import * as Context from "effect/Context"
|
|
2
3
|
import * as Effect from "effect/Effect"
|
|
3
4
|
import * as FiberRef from "effect/FiberRef"
|
|
4
5
|
import { constFalse, dual } from "effect/Function"
|
|
5
6
|
import { globalValue } from "effect/GlobalValue"
|
|
7
|
+
import * as Option from "effect/Option"
|
|
6
8
|
import type * as Predicate from "effect/Predicate"
|
|
7
9
|
import * as Headers from "../../Http/Headers.js"
|
|
8
|
-
import * as IncomingMessage from "../../Http/IncomingMessage.js"
|
|
9
10
|
import type * as Middleware from "../../Http/Middleware.js"
|
|
10
11
|
import * as ServerError from "../../Http/ServerError.js"
|
|
11
12
|
import * as ServerRequest from "../../Http/ServerRequest.js"
|
|
13
|
+
import * as TraceContext from "../../Http/TraceContext.js"
|
|
12
14
|
|
|
13
15
|
/** @internal */
|
|
14
16
|
export const make = <M extends Middleware.Middleware>(middleware: M): M => middleware
|
|
@@ -46,37 +48,33 @@ export const withTracerDisabledWhen = dual<
|
|
|
46
48
|
/** @internal */
|
|
47
49
|
export const logger = make((httpApp) => {
|
|
48
50
|
let counter = 0
|
|
49
|
-
return Effect.
|
|
50
|
-
|
|
51
|
-
(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)),
|
|
77
|
-
`http.span.${++counter}`
|
|
78
|
-
)
|
|
79
|
-
)
|
|
51
|
+
return Effect.withFiberRuntime((fiber) => {
|
|
52
|
+
const context = fiber.getFiberRef(FiberRef.currentContext)
|
|
53
|
+
const request = Context.unsafeGet(context, ServerRequest.ServerRequest)
|
|
54
|
+
return Effect.withLogSpan(
|
|
55
|
+
Effect.onExit(httpApp, (exit) => {
|
|
56
|
+
if (fiber.getFiberRef(loggerDisabled)) {
|
|
57
|
+
return Effect.unit
|
|
58
|
+
}
|
|
59
|
+
return exit._tag === "Failure" ?
|
|
60
|
+
Effect.annotateLogs(Effect.log(exit.cause), {
|
|
61
|
+
"http.method": request.method,
|
|
62
|
+
"http.url": request.url,
|
|
63
|
+
"http.status": Cause.isInterruptedOnly(exit.cause)
|
|
64
|
+
? ServerError.isClientAbortCause(exit.cause)
|
|
65
|
+
? 499
|
|
66
|
+
: 503
|
|
67
|
+
: 500
|
|
68
|
+
}) :
|
|
69
|
+
Effect.annotateLogs(Effect.log("Sent HTTP response"), {
|
|
70
|
+
"http.method": request.method,
|
|
71
|
+
"http.url": request.url,
|
|
72
|
+
"http.status": exit.value.status
|
|
73
|
+
})
|
|
74
|
+
}),
|
|
75
|
+
`http.span.${++counter}`
|
|
76
|
+
)
|
|
77
|
+
})
|
|
80
78
|
})
|
|
81
79
|
|
|
82
80
|
/** @internal */
|
|
@@ -85,23 +83,22 @@ export const tracer = make((httpApp) => {
|
|
|
85
83
|
httpApp,
|
|
86
84
|
(response) => Effect.annotateCurrentSpan("http.status", response.status)
|
|
87
85
|
)
|
|
88
|
-
return Effect.
|
|
89
|
-
|
|
90
|
-
(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
86
|
+
return Effect.withFiberRuntime((fiber) => {
|
|
87
|
+
const context = fiber.getFiberRef(FiberRef.currentContext)
|
|
88
|
+
const request = Context.unsafeGet(context, ServerRequest.ServerRequest)
|
|
89
|
+
const disabled = fiber.getFiberRef(currentTracerDisabledWhen)(request)
|
|
90
|
+
if (disabled) {
|
|
91
|
+
return httpApp
|
|
92
|
+
}
|
|
93
|
+
return Effect.withSpan(
|
|
94
|
+
appWithStatus,
|
|
95
|
+
`http.server ${request.method}`,
|
|
96
|
+
{
|
|
97
|
+
attributes: { "http.method": request.method, "http.url": request.url },
|
|
98
|
+
parent: Option.getOrUndefined(TraceContext.fromHeaders(request.headers))
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
})
|
|
105
102
|
})
|
|
106
103
|
|
|
107
104
|
/** @internal */
|
|
@@ -40,15 +40,15 @@ export const searchParams = Effect.map(RouteContext, (_) => _.searchParams)
|
|
|
40
40
|
/** @internal */
|
|
41
41
|
export const schemaJson = <
|
|
42
42
|
R,
|
|
43
|
-
I extends {
|
|
44
|
-
readonly method
|
|
45
|
-
readonly url
|
|
46
|
-
readonly cookies
|
|
47
|
-
readonly headers
|
|
48
|
-
readonly pathParams
|
|
49
|
-
readonly searchParams
|
|
50
|
-
readonly body
|
|
51
|
-
}
|
|
43
|
+
I extends Partial<{
|
|
44
|
+
readonly method: Method.Method
|
|
45
|
+
readonly url: string
|
|
46
|
+
readonly cookies: Readonly<Record<string, string>>
|
|
47
|
+
readonly headers: Readonly<Record<string, string>>
|
|
48
|
+
readonly pathParams: Readonly<Record<string, string>>
|
|
49
|
+
readonly searchParams: Readonly<Record<string, string>>
|
|
50
|
+
readonly body: any
|
|
51
|
+
}>,
|
|
52
52
|
A
|
|
53
53
|
>(
|
|
54
54
|
schema: Schema.Schema<A, I, R>,
|
|
@@ -74,14 +74,14 @@ export const schemaJson = <
|
|
|
74
74
|
/** @internal */
|
|
75
75
|
export const schemaNoBody = <
|
|
76
76
|
R,
|
|
77
|
-
I extends {
|
|
78
|
-
readonly method
|
|
79
|
-
readonly url
|
|
80
|
-
readonly cookies
|
|
81
|
-
readonly headers
|
|
82
|
-
readonly pathParams
|
|
83
|
-
readonly searchParams
|
|
84
|
-
}
|
|
77
|
+
I extends Partial<{
|
|
78
|
+
readonly method: Method.Method
|
|
79
|
+
readonly url: string
|
|
80
|
+
readonly cookies: Readonly<Record<string, string>>
|
|
81
|
+
readonly headers: Readonly<Record<string, string>>
|
|
82
|
+
readonly pathParams: Readonly<Record<string, string>>
|
|
83
|
+
readonly searchParams: Readonly<Record<string, string>>
|
|
84
|
+
}>,
|
|
85
85
|
A
|
|
86
86
|
>(
|
|
87
87
|
schema: Schema.Schema<A, I, R>,
|