@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.
Files changed (44) hide show
  1. package/Http/TraceContext/package.json +6 -0
  2. package/dist/cjs/FileSystem.js.map +1 -1
  3. package/dist/cjs/Http/Client.js +11 -1
  4. package/dist/cjs/Http/Client.js.map +1 -1
  5. package/dist/cjs/Http/IncomingMessage.js +2 -51
  6. package/dist/cjs/Http/IncomingMessage.js.map +1 -1
  7. package/dist/cjs/Http/Router.js.map +1 -1
  8. package/dist/cjs/Http/TraceContext.js +132 -0
  9. package/dist/cjs/Http/TraceContext.js.map +1 -0
  10. package/dist/cjs/internal/http/client.js +51 -34
  11. package/dist/cjs/internal/http/client.js.map +1 -1
  12. package/dist/cjs/internal/http/middleware.js +36 -22
  13. package/dist/cjs/internal/http/middleware.js.map +1 -1
  14. package/dist/dts/FileSystem.d.ts +7 -3
  15. package/dist/dts/FileSystem.d.ts.map +1 -1
  16. package/dist/dts/Http/Client.d.ts +16 -1
  17. package/dist/dts/Http/Client.d.ts.map +1 -1
  18. package/dist/dts/Http/IncomingMessage.d.ts +1 -7
  19. package/dist/dts/Http/IncomingMessage.d.ts.map +1 -1
  20. package/dist/dts/Http/Router.d.ts +17 -17
  21. package/dist/dts/Http/Router.d.ts.map +1 -1
  22. package/dist/dts/Http/TraceContext.d.ts +39 -0
  23. package/dist/dts/Http/TraceContext.d.ts.map +1 -0
  24. package/dist/esm/FileSystem.js.map +1 -1
  25. package/dist/esm/Http/Client.js +10 -0
  26. package/dist/esm/Http/Client.js.map +1 -1
  27. package/dist/esm/Http/IncomingMessage.js +1 -50
  28. package/dist/esm/Http/IncomingMessage.js.map +1 -1
  29. package/dist/esm/Http/Router.js.map +1 -1
  30. package/dist/esm/Http/TraceContext.js +95 -0
  31. package/dist/esm/Http/TraceContext.js.map +1 -0
  32. package/dist/esm/internal/http/client.js +50 -33
  33. package/dist/esm/internal/http/client.js.map +1 -1
  34. package/dist/esm/internal/http/middleware.js +36 -22
  35. package/dist/esm/internal/http/middleware.js.map +1 -1
  36. package/package.json +11 -3
  37. package/src/FileSystem.ts +7 -3
  38. package/src/Http/Client.ts +25 -1
  39. package/src/Http/IncomingMessage.ts +2 -71
  40. package/src/Http/Router.ts +21 -20
  41. package/src/Http/TraceContext.ts +109 -0
  42. package/src/internal/http/client.ts +89 -55
  43. package/src/internal/http/middleware.ts +46 -49
  44. 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, flow } from "effect/Function"
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
@@ -155,20 +155,22 @@ export const searchParams: Effect.Effect<
155
155
  */
156
156
  export const schemaJson: <
157
157
  R,
158
- I extends {
159
- readonly method?: Method.Method | undefined
160
- readonly url?: string | undefined
161
- readonly cookies?: Readonly<Record<string, string>> | undefined
162
- readonly headers?: Readonly<Record<string, string>> | undefined
163
- readonly pathParams?: Readonly<Record<string, string>> | undefined
164
- readonly searchParams?: Readonly<Record<string, string>> | undefined
165
- readonly body?: any
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, ParseResult.ParseError | Error.RequestError, RouteContext | R | ServerRequest.ServerRequest> =
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?: Method.Method | undefined
182
- readonly url?: string | undefined
183
- readonly cookies?: Readonly<Record<string, string>> | undefined
184
- readonly headers?: Readonly<Record<string, string>> | undefined
185
- readonly pathParams?: Readonly<Record<string, string>> | undefined
186
- readonly searchParams?: Readonly<Record<string, string>> | undefined
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 | Error.RequestError, RouteContext | R | ServerRequest.ServerRequest> =
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 { dual, pipe } from "effect/Function"
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 => make(Effect.flatMap(f), addB3Headers)
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
- Effect.flatMap(
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
- Effect.flatMap(Effect.serviceOption(Fetch), (fetch_) => {
96
- const fetch = fetch_._tag === "Some" ? fetch_.value : globalThis.fetch
97
- const headers = new Headers(request.headers)
98
- const send = (body: BodyInit | undefined) =>
99
- pipe(
100
- Effect.acquireRelease(
101
- Effect.sync(() => new AbortController()),
102
- (controller) => Effect.sync(() => controller.abort())
103
- ),
104
- Effect.flatMap((controller) =>
105
- Effect.tryPromise({
106
- try: () =>
107
- fetch(url, {
108
- ...options,
109
- method: request.method,
110
- headers,
111
- body,
112
- duplex: request.body._tag === "Stream" ? "half" : undefined,
113
- signal: controller.signal
114
- } as any),
115
- catch: (_) =>
116
- new Error.RequestError({
117
- request,
118
- reason: "Transport",
119
- error: _
120
- })
121
- })
122
- ),
123
- Effect.map((_) => internalResponse.fromWeb(request, _))
124
- )
125
- if (Method.hasBody(request.method)) {
126
- return send(convertBody(request.body))
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.flatMap(
50
- ServerRequest.ServerRequest,
51
- (request) =>
52
- Effect.withLogSpan(
53
- Effect.onExit(httpApp, (exit) =>
54
- Effect.flatMap(
55
- FiberRef.get(loggerDisabled),
56
- (disabled) => {
57
- if (disabled) {
58
- return Effect.unit
59
- }
60
- return exit._tag === "Failure" ?
61
- Effect.annotateLogs(Effect.log(exit.cause), {
62
- "http.method": request.method,
63
- "http.url": request.url,
64
- "http.status": Cause.isInterruptedOnly(exit.cause)
65
- ? ServerError.isClientAbortCause(exit.cause)
66
- ? 499
67
- : 503
68
- : 500
69
- }) :
70
- Effect.annotateLogs(Effect.log("Sent HTTP response"), {
71
- "http.method": request.method,
72
- "http.url": request.url,
73
- "http.status": exit.value.status
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.flatMap(
89
- Effect.zip(ServerRequest.ServerRequest, FiberRef.get(currentTracerDisabledWhen)),
90
- ([request, disabledWhen]) =>
91
- Effect.flatMap(
92
- request.headers["x-b3-traceid"] || request.headers["b3"] ?
93
- Effect.orElseSucceed(IncomingMessage.schemaExternalSpan(request), () => undefined) :
94
- Effect.succeed(undefined),
95
- (parent) =>
96
- disabledWhen(request) ?
97
- httpApp :
98
- Effect.withSpan(
99
- appWithStatus,
100
- `http ${request.method}`,
101
- { attributes: { "http.method": request.method, "http.url": request.url }, parent }
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?: 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
- },
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?: 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
- },
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>,