@effect/platform 0.15.2 → 0.16.1
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/Client.d.ts +6 -0
- package/Http/Client.d.ts.map +1 -1
- package/Http/Client.js +8 -2
- package/Http/Client.js.map +1 -1
- package/Http/IncomingMessage.d.ts +8 -1
- package/Http/IncomingMessage.d.ts.map +1 -1
- package/Http/IncomingMessage.js +44 -2
- package/Http/IncomingMessage.js.map +1 -1
- package/Http/Middleware.d.ts +5 -0
- package/Http/Middleware.d.ts.map +1 -1
- package/Http/Middleware.js +7 -1
- package/Http/Middleware.js.map +1 -1
- package/Http/ServerRequest.d.ts +5 -2
- package/Http/ServerRequest.d.ts.map +1 -1
- package/Http/ServerRequest.js.map +1 -1
- package/internal/http/client.d.ts.map +1 -1
- package/internal/http/client.js +12 -1
- package/internal/http/client.js.map +1 -1
- package/internal/http/clientResponse.js +4 -0
- package/internal/http/clientResponse.js.map +1 -1
- package/internal/http/middleware.js +14 -5
- package/internal/http/middleware.js.map +1 -1
- package/internal/http/router.d.ts.map +1 -1
- package/internal/http/router.js +17 -1
- package/internal/http/router.js.map +1 -1
- package/mjs/Http/Client.mjs +5 -0
- package/mjs/Http/Client.mjs.map +1 -1
- package/mjs/Http/IncomingMessage.mjs +42 -1
- package/mjs/Http/IncomingMessage.mjs.map +1 -1
- package/mjs/Http/Middleware.mjs +5 -0
- package/mjs/Http/Middleware.mjs.map +1 -1
- package/mjs/Http/ServerRequest.mjs.map +1 -1
- package/mjs/internal/http/client.mjs +10 -0
- package/mjs/internal/http/client.mjs.map +1 -1
- package/mjs/internal/http/clientResponse.mjs +4 -0
- package/mjs/internal/http/clientResponse.mjs.map +1 -1
- package/mjs/internal/http/middleware.mjs +12 -4
- package/mjs/internal/http/middleware.mjs.map +1 -1
- package/mjs/internal/http/router.mjs +17 -1
- package/mjs/internal/http/router.mjs.map +1 -1
- package/package.json +4 -4
- package/src/Http/Client.ts +8 -0
- package/src/Http/IncomingMessage.ts +62 -2
- package/src/Http/Middleware.ts +6 -0
- package/src/Http/ServerRequest.ts +7 -2
- package/src/internal/http/client.ts +33 -1
- package/src/internal/http/clientResponse.ts +5 -0
- package/src/internal/http/middleware.ts +39 -12
- package/src/internal/http/router.ts +15 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
4
|
+
import * as Context from "@effect/data/Context"
|
|
5
|
+
import { dual, flow } from "@effect/data/Function"
|
|
5
6
|
import * as Global from "@effect/data/GlobalValue"
|
|
6
7
|
import * as Option from "@effect/data/Option"
|
|
7
8
|
import * as Effect from "@effect/io/Effect"
|
|
8
9
|
import * as FiberRef from "@effect/io/FiberRef"
|
|
10
|
+
import type { ExternalSpan } from "@effect/io/Tracer"
|
|
9
11
|
import * as FileSystem from "@effect/platform/FileSystem"
|
|
10
12
|
import type * as Headers from "@effect/platform/Http/Headers"
|
|
11
13
|
import type * as UrlParams from "@effect/platform/Http/UrlParams"
|
|
12
|
-
import
|
|
14
|
+
import * as ParseResult from "@effect/schema/ParseResult"
|
|
13
15
|
import * as Schema from "@effect/schema/Schema"
|
|
14
16
|
import type * as Stream from "@effect/stream/Stream"
|
|
15
17
|
|
|
@@ -32,6 +34,7 @@ export type TypeId = typeof TypeId
|
|
|
32
34
|
export interface IncomingMessage<E> {
|
|
33
35
|
readonly [TypeId]: TypeId
|
|
34
36
|
readonly headers: Headers.Headers
|
|
37
|
+
readonly remoteAddress: Option.Option<string>
|
|
35
38
|
readonly json: Effect.Effect<never, E, unknown>
|
|
36
39
|
readonly text: Effect.Effect<never, E, string>
|
|
37
40
|
readonly urlParamsBody: Effect.Effect<never, E, UrlParams.UrlParams>
|
|
@@ -68,6 +71,63 @@ export const schemaHeaders = <I extends Readonly<Record<string, string>>, A>(sch
|
|
|
68
71
|
return <E>(self: IncomingMessage<E>): Effect.Effect<never, ParseResult.ParseError, A> => parse(self.headers)
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
const SpanSchema = Schema.struct({
|
|
75
|
+
traceId: Schema.string,
|
|
76
|
+
spanId: Schema.string,
|
|
77
|
+
parentSpanId: Schema.union(Schema.string, Schema.undefined)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @since 1.0.0
|
|
82
|
+
* @category schema
|
|
83
|
+
*/
|
|
84
|
+
export const schemaExternalSpan = flow(
|
|
85
|
+
schemaHeaders(Schema.union(
|
|
86
|
+
Schema.transformOrFail(
|
|
87
|
+
Schema.struct({
|
|
88
|
+
b3: Schema.NonEmpty
|
|
89
|
+
}),
|
|
90
|
+
SpanSchema,
|
|
91
|
+
(_) => {
|
|
92
|
+
const parts = _.b3.split("-")
|
|
93
|
+
if (parts.length >= 2) {
|
|
94
|
+
return ParseResult.success({
|
|
95
|
+
traceId: parts[0],
|
|
96
|
+
spanId: parts[1],
|
|
97
|
+
parentSpanId: parts[3]
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
return ParseResult.failure(ParseResult.missing)
|
|
101
|
+
},
|
|
102
|
+
(_) => ParseResult.success("")
|
|
103
|
+
),
|
|
104
|
+
Schema.transform(
|
|
105
|
+
Schema.struct({
|
|
106
|
+
"x-b3-traceid": Schema.NonEmpty,
|
|
107
|
+
"x-b3-spanid": Schema.NonEmpty,
|
|
108
|
+
"x-b3-parentspanid": Schema.optional(Schema.NonEmpty)
|
|
109
|
+
}),
|
|
110
|
+
SpanSchema,
|
|
111
|
+
(_) => ({
|
|
112
|
+
traceId: _["x-b3-traceid"],
|
|
113
|
+
spanId: _["x-b3-spanid"],
|
|
114
|
+
parentSpanId: _["x-b3-parentspanid"]
|
|
115
|
+
}),
|
|
116
|
+
(_) => ({
|
|
117
|
+
"x-b3-traceid": _.traceId,
|
|
118
|
+
"x-b3-spanid": _.spanId,
|
|
119
|
+
"x-b3-parentspanid": _.parentSpanId
|
|
120
|
+
})
|
|
121
|
+
)
|
|
122
|
+
)),
|
|
123
|
+
Effect.map((_): ExternalSpan => ({
|
|
124
|
+
_tag: "ExternalSpan",
|
|
125
|
+
traceId: _.traceId,
|
|
126
|
+
spanId: _.spanId,
|
|
127
|
+
context: Context.empty()
|
|
128
|
+
}))
|
|
129
|
+
)
|
|
130
|
+
|
|
71
131
|
/**
|
|
72
132
|
* @since 1.0.0
|
|
73
133
|
* @category fiber refs
|
package/src/Http/Middleware.ts
CHANGED
|
@@ -30,6 +30,12 @@ export declare namespace Middleware {
|
|
|
30
30
|
*/
|
|
31
31
|
export const make: <M extends Middleware>(middleware: M) => M = internal.make
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @since 1.0.0
|
|
35
|
+
* @category constructors
|
|
36
|
+
*/
|
|
37
|
+
export const b3Response: <R, E>(httpApp: App.Default<R, E>) => App.Default<R, E> = internal.b3Response
|
|
38
|
+
|
|
33
39
|
/**
|
|
34
40
|
* @since 1.0.0
|
|
35
41
|
* @category constructors
|
|
@@ -49,8 +49,13 @@ export interface ServerRequest extends IncomingMessage.IncomingMessage<Error.Req
|
|
|
49
49
|
readonly formData: Effect.Effect<Scope.Scope | FileSystem.FileSystem | Path.Path, FormData.FormDataError, FormData>
|
|
50
50
|
readonly formDataStream: Stream.Stream<never, FormData.FormDataError, FormData.Part>
|
|
51
51
|
|
|
52
|
-
readonly
|
|
53
|
-
|
|
52
|
+
readonly modify: (
|
|
53
|
+
options: {
|
|
54
|
+
readonly url?: string
|
|
55
|
+
readonly headers?: Headers.Headers
|
|
56
|
+
readonly remoteAddress?: string
|
|
57
|
+
}
|
|
58
|
+
) => ServerRequest
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
/**
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import * as Context from "@effect/data/Context"
|
|
2
|
-
import { dual } from "@effect/data/Function"
|
|
2
|
+
import { dual, pipe } from "@effect/data/Function"
|
|
3
|
+
import * as Option from "@effect/data/Option"
|
|
3
4
|
import { pipeArguments } from "@effect/data/Pipeable"
|
|
4
5
|
import type * as Predicate from "@effect/data/Predicate"
|
|
5
6
|
import * as Effect from "@effect/io/Effect"
|
|
6
7
|
import * as Layer from "@effect/io/Layer"
|
|
7
8
|
import type * as Schedule from "@effect/io/Schedule"
|
|
9
|
+
import type * as Scope from "@effect/io/Scope"
|
|
8
10
|
import type * as Body from "@effect/platform/Http/Body"
|
|
9
11
|
import type * as Client from "@effect/platform/Http/Client"
|
|
10
12
|
import type * as Error from "@effect/platform/Http/ClientError"
|
|
11
13
|
import type * as ClientRequest from "@effect/platform/Http/ClientRequest"
|
|
12
14
|
import type * as ClientResponse from "@effect/platform/Http/ClientResponse"
|
|
15
|
+
import * as IncomingMessage from "@effect/platform/Http/IncomingMessage"
|
|
13
16
|
import * as Method from "@effect/platform/Http/Method"
|
|
14
17
|
import * as UrlParams from "@effect/platform/Http/UrlParams"
|
|
15
18
|
import * as internalBody from "@effect/platform/internal/http/body"
|
|
@@ -359,6 +362,35 @@ export const mapRequestEffect = dual<
|
|
|
359
362
|
) => Client.Client<R | R2, E | E2, A>
|
|
360
363
|
>(2, (self, f) => setProto((request) => Effect.flatMap(f(request), self)))
|
|
361
364
|
|
|
365
|
+
/** @internal */
|
|
366
|
+
export const withB3Propagation = <R, E>(
|
|
367
|
+
self: Client.Client.WithResponse<R, E>
|
|
368
|
+
): Client.Client.WithResponse<R | Scope.Scope, E> =>
|
|
369
|
+
setProto((req) =>
|
|
370
|
+
pipe(
|
|
371
|
+
Effect.map(
|
|
372
|
+
Effect.currentSpan,
|
|
373
|
+
Option.match({
|
|
374
|
+
onNone: () => req,
|
|
375
|
+
onSome: (span) => {
|
|
376
|
+
const parentId = span.parent._tag === "Some" ? `-${span.parent.value.spanId}` : ""
|
|
377
|
+
return internalRequest.setHeader(
|
|
378
|
+
req,
|
|
379
|
+
"b3",
|
|
380
|
+
`${span.traceId}-${span.spanId}-1${parentId}`
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
),
|
|
385
|
+
Effect.flatMap(self),
|
|
386
|
+
Effect.tap((res) =>
|
|
387
|
+
Effect.ignore(
|
|
388
|
+
Effect.flatMap(IncomingMessage.schemaExternalSpan(res), Effect.withParentSpanScoped)
|
|
389
|
+
)
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
)
|
|
393
|
+
|
|
362
394
|
/** @internal */
|
|
363
395
|
export const retry: {
|
|
364
396
|
<R1, E extends E0, E0, B>(policy: Schedule.Schedule<R1, E0, B>): <R, A>(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Option from "@effect/data/Option"
|
|
1
2
|
import * as Effect from "@effect/io/Effect"
|
|
2
3
|
import type * as Error from "@effect/platform/Http/ClientError"
|
|
3
4
|
import type * as ClientRequest from "@effect/platform/Http/ClientRequest"
|
|
@@ -39,6 +40,10 @@ class ClientResponseImpl implements ClientResponse.ClientResponse {
|
|
|
39
40
|
return Headers.fromInput(this.source.headers)
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
get remoteAddress(): Option.Option<string> {
|
|
44
|
+
return Option.none()
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
get stream(): Stream.Stream<never, Error.ResponseError, Uint8Array> {
|
|
43
48
|
return this.source.body
|
|
44
49
|
? Stream.fromReadableStream(() => this.source.body!, (_) =>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { flow } from "@effect/data/Function"
|
|
2
2
|
import * as Effect from "@effect/io/Effect"
|
|
3
3
|
import * as Headers from "@effect/platform/Http/Headers"
|
|
4
|
+
import * as IncomingMessage from "@effect/platform/Http/IncomingMessage"
|
|
4
5
|
import type * as Middleware from "@effect/platform/Http/Middleware"
|
|
5
6
|
import * as ServerRequest from "@effect/platform/Http/ServerRequest"
|
|
7
|
+
import * as ServerResponse from "@effect/platform/Http/ServerResponse"
|
|
6
8
|
|
|
7
9
|
/** @internal */
|
|
8
10
|
export const make = <M extends Middleware.Middleware>(middleware: M): M => middleware
|
|
@@ -36,26 +38,51 @@ export const tracer = make((httpApp) =>
|
|
|
36
38
|
Effect.flatMap(
|
|
37
39
|
ServerRequest.ServerRequest,
|
|
38
40
|
(request) =>
|
|
39
|
-
Effect.
|
|
40
|
-
Effect.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
Effect.flatMap(
|
|
42
|
+
Effect.orElseSucceed(IncomingMessage.schemaExternalSpan(request), () => undefined),
|
|
43
|
+
(parent) =>
|
|
44
|
+
Effect.withSpan(
|
|
45
|
+
Effect.tap(
|
|
46
|
+
httpApp,
|
|
47
|
+
(response) => Effect.annotateCurrentSpan("http.status", response.status)
|
|
48
|
+
),
|
|
49
|
+
`http ${request.method}`,
|
|
50
|
+
{ attributes: { "http.method": request.method, "http.url": request.url }, parent }
|
|
51
|
+
)
|
|
46
52
|
)
|
|
47
53
|
)
|
|
48
54
|
)
|
|
49
55
|
|
|
56
|
+
/** @internal */
|
|
57
|
+
export const b3Response = make((httpApp) =>
|
|
58
|
+
Effect.flatMap(
|
|
59
|
+
Effect.currentSpan,
|
|
60
|
+
(span) =>
|
|
61
|
+
span._tag === "Some"
|
|
62
|
+
? Effect.map(httpApp, (res) =>
|
|
63
|
+
ServerResponse.setHeader(
|
|
64
|
+
res,
|
|
65
|
+
"b3",
|
|
66
|
+
`${span.value.traceId}-${span.value.spanId}-1${
|
|
67
|
+
span.value.parent._tag === "Some" ? `-${span.value.parent.value.spanId}` : ""
|
|
68
|
+
}`
|
|
69
|
+
))
|
|
70
|
+
: httpApp
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
|
|
50
74
|
/** @internal */
|
|
51
75
|
export const xForwardedHeaders = make((httpApp) =>
|
|
52
76
|
Effect.updateService(httpApp, ServerRequest.ServerRequest, (request) =>
|
|
53
77
|
request.headers["x-forwarded-host"]
|
|
54
|
-
? request.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
? request.modify({
|
|
79
|
+
headers: Headers.set(
|
|
80
|
+
request.headers,
|
|
81
|
+
"host",
|
|
82
|
+
request.headers["x-forwarded-host"]
|
|
83
|
+
),
|
|
84
|
+
remoteAddress: request.headers["x-forwarded-for"]?.split(",")[0].trim()
|
|
85
|
+
})
|
|
59
86
|
: request)
|
|
60
87
|
)
|
|
61
88
|
|
|
@@ -3,6 +3,7 @@ import * as Context from "@effect/data/Context"
|
|
|
3
3
|
import * as Equal from "@effect/data/Equal"
|
|
4
4
|
import { dual } from "@effect/data/Function"
|
|
5
5
|
import * as Hash from "@effect/data/Hash"
|
|
6
|
+
import * as Inspectable from "@effect/data/Inspectable"
|
|
6
7
|
import * as Option from "@effect/data/Option"
|
|
7
8
|
import { pipeArguments } from "@effect/data/Pipeable"
|
|
8
9
|
import type * as Cause from "@effect/io/Cause"
|
|
@@ -91,6 +92,19 @@ class RouterImpl<R, E> implements Router.Router<R, E> {
|
|
|
91
92
|
[Hash.symbol](this: RouterImpl<R, E>): number {
|
|
92
93
|
return Hash.random(this)
|
|
93
94
|
}
|
|
95
|
+
toJSON() {
|
|
96
|
+
return {
|
|
97
|
+
_id: "Router",
|
|
98
|
+
routes: this.routes.toJSON(),
|
|
99
|
+
mounts: this.mounts.toJSON()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
toString() {
|
|
103
|
+
return Inspectable.toString(this)
|
|
104
|
+
}
|
|
105
|
+
[Inspectable.NodeInspectSymbol]() {
|
|
106
|
+
return this.toJSON()
|
|
107
|
+
}
|
|
94
108
|
}
|
|
95
109
|
|
|
96
110
|
const toHttpApp = <R, E>(
|
|
@@ -151,7 +165,7 @@ const toHttpApp = <R, E>(
|
|
|
151
165
|
|
|
152
166
|
function sliceRequestUrl(request: ServerRequest.ServerRequest, prefix: string) {
|
|
153
167
|
const prefexLen = prefix.length
|
|
154
|
-
return request.
|
|
168
|
+
return request.modify({ url: request.url.length <= prefexLen ? "/" : request.url.slice(prefexLen) })
|
|
155
169
|
}
|
|
156
170
|
|
|
157
171
|
class RouteImpl<R, E> implements Router.Route<R, E> {
|