effect 4.0.0-beta.11 → 4.0.0-beta.12
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/Config.d.ts +157 -0
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +56 -1
- package/dist/Config.js.map +1 -1
- package/dist/Effect.d.ts +79 -0
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +26 -0
- package/dist/Effect.js.map +1 -1
- package/dist/Fiber.d.ts +2 -2
- package/dist/Fiber.d.ts.map +1 -1
- package/dist/Fiber.js.map +1 -1
- package/dist/Graph.d.ts.map +1 -1
- package/dist/Graph.js +3 -6
- package/dist/Graph.js.map +1 -1
- package/dist/Random.d.ts +17 -0
- package/dist/Random.d.ts.map +1 -1
- package/dist/Random.js +17 -0
- package/dist/Random.js.map +1 -1
- package/dist/Schema.d.ts +3 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/internal/effect.js +59 -44
- package/dist/internal/effect.js.map +1 -1
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +49 -18
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/ai/McpSchema.d.ts +112 -36
- package/dist/unstable/ai/McpSchema.d.ts.map +1 -1
- package/dist/unstable/ai/McpSchema.js +47 -10
- package/dist/unstable/ai/McpSchema.js.map +1 -1
- package/dist/unstable/ai/McpServer.d.ts.map +1 -1
- package/dist/unstable/ai/McpServer.js +33 -6
- package/dist/unstable/ai/McpServer.js.map +1 -1
- package/dist/unstable/ai/Tool.d.ts +16 -0
- package/dist/unstable/ai/Tool.d.ts.map +1 -1
- package/dist/unstable/ai/Tool.js +14 -0
- package/dist/unstable/ai/Tool.js.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.js +2 -2
- package/dist/unstable/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/unstable/http/HttpClient.d.ts +28 -4
- package/dist/unstable/http/HttpClient.d.ts.map +1 -1
- package/dist/unstable/http/HttpClient.js.map +1 -1
- package/dist/unstable/http/HttpEffect.d.ts +3 -8
- package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
- package/dist/unstable/http/HttpEffect.js +13 -24
- package/dist/unstable/http/HttpEffect.js.map +1 -1
- package/dist/unstable/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/unstable/http/HttpMiddleware.js +4 -8
- package/dist/unstable/http/HttpMiddleware.js.map +1 -1
- package/dist/unstable/http/HttpServerError.d.ts +6 -1
- package/dist/unstable/http/HttpServerError.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerError.js +26 -17
- package/dist/unstable/http/HttpServerError.js.map +1 -1
- package/dist/unstable/http/internal/preResponseHandler.d.ts +2 -0
- package/dist/unstable/http/internal/preResponseHandler.d.ts.map +1 -0
- package/dist/unstable/http/internal/preResponseHandler.js +10 -0
- package/dist/unstable/http/internal/preResponseHandler.js.map +1 -0
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
- package/dist/unstable/reactivity/Atom.js +1 -1
- package/dist/unstable/reactivity/Atom.js.map +1 -1
- package/dist/unstable/rpc/RpcSchema.d.ts +13 -0
- package/dist/unstable/rpc/RpcSchema.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcSchema.js +14 -0
- package/dist/unstable/rpc/RpcSchema.js.map +1 -1
- package/dist/unstable/rpc/RpcSerialization.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcSerialization.js +34 -9
- package/dist/unstable/rpc/RpcSerialization.js.map +1 -1
- package/dist/unstable/rpc/RpcServer.d.ts +0 -7
- package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcServer.js +5 -10
- package/dist/unstable/rpc/RpcServer.js.map +1 -1
- package/package.json +1 -1
- package/src/Config.ts +171 -9
- package/src/Effect.ts +80 -0
- package/src/Fiber.ts +9 -2
- package/src/Graph.ts +16 -6
- package/src/Random.ts +18 -0
- package/src/Schema.ts +1 -1
- package/src/internal/effect.ts +82 -49
- package/src/unstable/ai/LanguageModel.ts +54 -24
- package/src/unstable/ai/McpSchema.ts +57 -11
- package/src/unstable/ai/McpServer.ts +44 -6
- package/src/unstable/ai/Tool.ts +15 -0
- package/src/unstable/cluster/ClusterWorkflowEngine.ts +2 -2
- package/src/unstable/http/HttpClient.ts +45 -10
- package/src/unstable/http/HttpEffect.ts +20 -39
- package/src/unstable/http/HttpMiddleware.ts +4 -14
- package/src/unstable/http/HttpServerError.ts +29 -18
- package/src/unstable/http/internal/preResponseHandler.ts +15 -0
- package/src/unstable/httpapi/HttpApiBuilder.ts +1 -1
- package/src/unstable/reactivity/Atom.ts +1 -1
- package/src/unstable/rpc/RpcSchema.ts +17 -0
- package/src/unstable/rpc/RpcSerialization.ts +44 -9
- package/src/unstable/rpc/RpcServer.ts +10 -19
|
@@ -949,13 +949,16 @@ export const retryTransient: {
|
|
|
949
949
|
* @category error handling
|
|
950
950
|
*/
|
|
951
951
|
<
|
|
952
|
-
B,
|
|
953
952
|
E,
|
|
953
|
+
B = never,
|
|
954
954
|
ES = never,
|
|
955
955
|
R1 = never,
|
|
956
|
-
const RetryOn extends "errors-only" | "response-only" | "errors-and-responses" =
|
|
957
|
-
|
|
958
|
-
|
|
956
|
+
const RetryOn extends "errors-only" | "response-only" | "errors-and-responses" =
|
|
957
|
+
| "errors-only"
|
|
958
|
+
| "response-only"
|
|
959
|
+
| "errors-and-responses",
|
|
960
|
+
Input = RetryOn extends "errors-only" ? E
|
|
961
|
+
: RetryOn extends "response-only" ? HttpClientResponse.HttpClientResponse
|
|
959
962
|
: HttpClientResponse.HttpClientResponse | E
|
|
960
963
|
>(
|
|
961
964
|
options: {
|
|
@@ -963,7 +966,7 @@ export const retryTransient: {
|
|
|
963
966
|
readonly while?: Predicate.Predicate<NoInfer<E | ES>>
|
|
964
967
|
readonly schedule?: Schedule.Schedule<B, NoInfer<Input>, ES, R1>
|
|
965
968
|
readonly times?: number
|
|
966
|
-
}
|
|
969
|
+
}
|
|
967
970
|
): <R>(self: HttpClient.With<E, R>) => HttpClient.With<E | ES, R1 | R>
|
|
968
971
|
/**
|
|
969
972
|
* Retries common transient errors, such as rate limiting, timeouts or network issues.
|
|
@@ -979,12 +982,15 @@ export const retryTransient: {
|
|
|
979
982
|
<
|
|
980
983
|
E,
|
|
981
984
|
R,
|
|
982
|
-
B,
|
|
985
|
+
B = never,
|
|
983
986
|
ES = never,
|
|
984
987
|
R1 = never,
|
|
985
|
-
const RetryOn extends "errors-only" | "response-only" | "errors-and-responses" =
|
|
986
|
-
|
|
987
|
-
|
|
988
|
+
const RetryOn extends "errors-only" | "response-only" | "errors-and-responses" =
|
|
989
|
+
| "errors-only"
|
|
990
|
+
| "response-only"
|
|
991
|
+
| "errors-and-responses",
|
|
992
|
+
Input = RetryOn extends "errors-only" ? E
|
|
993
|
+
: RetryOn extends "response-only" ? HttpClientResponse.HttpClientResponse
|
|
988
994
|
: HttpClientResponse.HttpClientResponse | E
|
|
989
995
|
>(
|
|
990
996
|
self: HttpClient.With<E, R>,
|
|
@@ -993,7 +999,36 @@ export const retryTransient: {
|
|
|
993
999
|
readonly while?: Predicate.Predicate<NoInfer<E | ES>>
|
|
994
1000
|
readonly schedule?: Schedule.Schedule<B, NoInfer<Input>, ES, R1>
|
|
995
1001
|
readonly times?: number
|
|
996
|
-
}
|
|
1002
|
+
}
|
|
1003
|
+
): HttpClient.With<E | ES, R1 | R>
|
|
1004
|
+
/**
|
|
1005
|
+
* Retries common transient errors, such as rate limiting, timeouts or network issues.
|
|
1006
|
+
*
|
|
1007
|
+
* Use `retryOn` to focus on retrying errors, transient responses, or both.
|
|
1008
|
+
*
|
|
1009
|
+
* Specifying a `while` predicate allows you to consider other errors as
|
|
1010
|
+
* transient, and is ignored in "response-only" mode.
|
|
1011
|
+
*
|
|
1012
|
+
* @since 4.0.0
|
|
1013
|
+
* @category error handling
|
|
1014
|
+
*/
|
|
1015
|
+
<B, E, ES = never, R1 = never>(
|
|
1016
|
+
options: Schedule.Schedule<B, NoInfer<HttpClientResponse.HttpClientResponse | E>, ES, R1>
|
|
1017
|
+
): <R>(self: HttpClient.With<E, R>) => HttpClient.With<E | ES, R1 | R>
|
|
1018
|
+
/**
|
|
1019
|
+
* Retries common transient errors, such as rate limiting, timeouts or network issues.
|
|
1020
|
+
*
|
|
1021
|
+
* Use `retryOn` to focus on retrying errors, transient responses, or both.
|
|
1022
|
+
*
|
|
1023
|
+
* Specifying a `while` predicate allows you to consider other errors as
|
|
1024
|
+
* transient, and is ignored in "response-only" mode.
|
|
1025
|
+
*
|
|
1026
|
+
* @since 4.0.0
|
|
1027
|
+
* @category error handling
|
|
1028
|
+
*/
|
|
1029
|
+
<E, R, B, ES = never, R1 = never>(
|
|
1030
|
+
self: HttpClient.With<E, R>,
|
|
1031
|
+
options: Schedule.Schedule<B, NoInfer<HttpClientResponse.HttpClientResponse | E>, ES, R1>
|
|
997
1032
|
): HttpClient.With<E | ES, R1 | R>
|
|
998
1033
|
} = dual(
|
|
999
1034
|
2,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 4.0.0
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
4
|
+
import type * as Cause from "../../Cause.ts"
|
|
5
5
|
import * as Effect from "../../Effect.ts"
|
|
6
6
|
import * as Exit from "../../Exit.ts"
|
|
7
7
|
import * as Fiber from "../../Fiber.ts"
|
|
@@ -11,14 +11,14 @@ import * as Layer from "../../Layer.ts"
|
|
|
11
11
|
import * as Scope from "../../Scope.ts"
|
|
12
12
|
import * as ServiceMap from "../../ServiceMap.ts"
|
|
13
13
|
import * as Stream from "../../Stream.ts"
|
|
14
|
-
import * as UndefinedOr from "../../UndefinedOr.ts"
|
|
15
14
|
import * as HttpBody from "./HttpBody.ts"
|
|
16
15
|
import { type HttpMiddleware, tracer } from "./HttpMiddleware.ts"
|
|
17
|
-
import { causeResponse,
|
|
16
|
+
import { causeResponse, ClientAbort, HttpServerError, InternalError } from "./HttpServerError.ts"
|
|
18
17
|
import { HttpServerRequest } from "./HttpServerRequest.ts"
|
|
19
18
|
import * as Request from "./HttpServerRequest.ts"
|
|
20
19
|
import type { HttpServerResponse } from "./HttpServerResponse.ts"
|
|
21
20
|
import * as Response from "./HttpServerResponse.ts"
|
|
21
|
+
import { appendPreResponseHandlerUnsafe, requestPreResponseHandlers } from "./internal/preResponseHandler.ts"
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* @since 4.0.0
|
|
@@ -32,12 +32,12 @@ export const toHandled = <E, R, EH, RH>(
|
|
|
32
32
|
) => Effect.Effect<unknown, EH, RH>,
|
|
33
33
|
middleware?: HttpMiddleware | undefined
|
|
34
34
|
): Effect.Effect<void, never, Exclude<R | RH | HttpServerRequest, Scope.Scope>> => {
|
|
35
|
-
const handleCause = (cause: Cause<E | EH | HttpServerError>) =>
|
|
35
|
+
const handleCause = (cause: Cause.Cause<E | EH | HttpServerError>) =>
|
|
36
36
|
Effect.flatMapEager(causeResponse(cause), ([response, cause]) => {
|
|
37
37
|
const fiber = Fiber.getCurrent()!
|
|
38
38
|
reportCauseUnsafe(fiber, cause)
|
|
39
39
|
const request = ServiceMap.getUnsafe(fiber.services, HttpServerRequest)
|
|
40
|
-
const handler =
|
|
40
|
+
const handler = requestPreResponseHandlers.get(request)
|
|
41
41
|
const cont = cause.reasons.length === 0 ? Effect.succeed(response) : Effect.failCause(cause)
|
|
42
42
|
if (handler === undefined) {
|
|
43
43
|
;(request as any)[handledSymbol] = true
|
|
@@ -60,7 +60,7 @@ export const toHandled = <E, R, EH, RH>(
|
|
|
60
60
|
onSuccess: (response) => {
|
|
61
61
|
const fiber = Fiber.getCurrent()!
|
|
62
62
|
const request = ServiceMap.getUnsafe(fiber.services, HttpServerRequest)
|
|
63
|
-
const handler =
|
|
63
|
+
const handler = requestPreResponseHandlers.get(request)
|
|
64
64
|
if (handler === undefined) {
|
|
65
65
|
;(request as any)[handledSymbol] = true
|
|
66
66
|
return Effect.mapEager(handleResponse(request, response), () => response)
|
|
@@ -145,10 +145,10 @@ const scopeEjected = Symbol.for("effect/http/HttpEffect/scopeEjected")
|
|
|
145
145
|
const scoped = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
|
146
146
|
Effect.withFiber((fiber) => {
|
|
147
147
|
const scope = Scope.makeUnsafe()
|
|
148
|
-
const
|
|
148
|
+
const prevServices = fiber.services
|
|
149
149
|
fiber.setServices(ServiceMap.add(fiber.services, Scope.Scope, scope))
|
|
150
150
|
return Effect.onExitPrimitive(effect, (exit) => {
|
|
151
|
-
fiber.setServices(
|
|
151
|
+
fiber.setServices(prevServices)
|
|
152
152
|
if (scopeEjected in scope) return undefined
|
|
153
153
|
return Scope.closeUnsafe(scope, exit)
|
|
154
154
|
}, true)
|
|
@@ -163,27 +163,13 @@ export type PreResponseHandler = (
|
|
|
163
163
|
response: HttpServerResponse
|
|
164
164
|
) => Effect.Effect<HttpServerResponse, HttpServerError>
|
|
165
165
|
|
|
166
|
-
/**
|
|
167
|
-
* @since 4.0.0
|
|
168
|
-
* @category Pre-response handlers
|
|
169
|
-
*/
|
|
170
|
-
export const PreResponseHandlers = ServiceMap.Reference<PreResponseHandler | undefined>(
|
|
171
|
-
"effect/http/HttpEffect/PreResponseHandlers",
|
|
172
|
-
{ defaultValue: () => undefined }
|
|
173
|
-
)
|
|
174
|
-
|
|
175
166
|
/**
|
|
176
167
|
* @since 4.0.0
|
|
177
168
|
* @category fiber refs
|
|
178
169
|
*/
|
|
179
|
-
export const appendPreResponseHandler = (handler: PreResponseHandler): Effect.Effect<void> =>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
onUndefined: () => handler,
|
|
183
|
-
onDefined: (prev) => (request, response) =>
|
|
184
|
-
Effect.flatMap(prev(request, response), (response) => handler(request, response))
|
|
185
|
-
})
|
|
186
|
-
fiber.setServices(ServiceMap.add(fiber.services, PreResponseHandlers, next))
|
|
170
|
+
export const appendPreResponseHandler = (handler: PreResponseHandler): Effect.Effect<void, never, HttpServerRequest> =>
|
|
171
|
+
HttpServerRequest.use((request) => {
|
|
172
|
+
appendPreResponseHandlerUnsafe(request, handler)
|
|
187
173
|
return Effect.void
|
|
188
174
|
})
|
|
189
175
|
|
|
@@ -196,33 +182,28 @@ export const withPreResponseHandler: {
|
|
|
196
182
|
* @since 4.0.0
|
|
197
183
|
* @category fiber refs
|
|
198
184
|
*/
|
|
199
|
-
(handler: PreResponseHandler): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
|
|
185
|
+
(handler: PreResponseHandler): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R | HttpServerRequest>
|
|
200
186
|
/**
|
|
201
187
|
* @since 4.0.0
|
|
202
188
|
* @category fiber refs
|
|
203
189
|
*/
|
|
204
|
-
<A, E, R>(self: Effect.Effect<A, E, R>, handler: PreResponseHandler): Effect.Effect<A, E, R>
|
|
190
|
+
<A, E, R>(self: Effect.Effect<A, E, R>, handler: PreResponseHandler): Effect.Effect<A, E, R | HttpServerRequest>
|
|
205
191
|
} = dual<
|
|
206
192
|
/**
|
|
207
193
|
* @since 4.0.0
|
|
208
194
|
* @category fiber refs
|
|
209
195
|
*/
|
|
210
|
-
(handler: PreResponseHandler) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>,
|
|
196
|
+
(handler: PreResponseHandler) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R | HttpServerRequest>,
|
|
211
197
|
/**
|
|
212
198
|
* @since 4.0.0
|
|
213
199
|
* @category fiber refs
|
|
214
200
|
*/
|
|
215
|
-
<A, E, R>(self: Effect.Effect<A, E, R>, handler: PreResponseHandler) => Effect.Effect<A, E, R>
|
|
201
|
+
<A, E, R>(self: Effect.Effect<A, E, R>, handler: PreResponseHandler) => Effect.Effect<A, E, R | HttpServerRequest>
|
|
216
202
|
>(2, (self, handler) =>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
onUndefined: () => handler,
|
|
222
|
-
onDefined: (prev) => (request, response) =>
|
|
223
|
-
Effect.flatMap(prev(request, response), (response) => handler(request, response))
|
|
224
|
-
})
|
|
225
|
-
))
|
|
203
|
+
HttpServerRequest.use((request) => {
|
|
204
|
+
appendPreResponseHandlerUnsafe(request, handler)
|
|
205
|
+
return self
|
|
206
|
+
}))
|
|
226
207
|
|
|
227
208
|
/**
|
|
228
209
|
* @since 4.0.0
|
|
@@ -259,7 +240,7 @@ export const toWebHandlerWith = <Provided, R = never, ReqR = Exclude<R, Provided
|
|
|
259
240
|
;(httpServerRequest as any)[resolveSymbol] = resolve
|
|
260
241
|
const fiber = Effect.runForkWith(ServiceMap.makeUnsafe(contextMap))(httpApp as any)
|
|
261
242
|
request.signal?.addEventListener("abort", () => {
|
|
262
|
-
fiber.interruptUnsafe(
|
|
243
|
+
fiber.interruptUnsafe(undefined, ClientAbort.annotation)
|
|
263
244
|
}, { once: true })
|
|
264
245
|
})
|
|
265
246
|
}
|
|
@@ -12,13 +12,13 @@ import { TracerEnabled } from "../../References.ts"
|
|
|
12
12
|
import * as ServiceMap from "../../ServiceMap.ts"
|
|
13
13
|
import { ParentSpan } from "../../Tracer.ts"
|
|
14
14
|
import * as Headers from "./Headers.ts"
|
|
15
|
-
import type { PreResponseHandler } from "./HttpEffect.ts"
|
|
16
15
|
import { causeResponseStripped, exitResponse } from "./HttpServerError.ts"
|
|
17
16
|
import { HttpServerRequest } from "./HttpServerRequest.ts"
|
|
18
17
|
import * as Request from "./HttpServerRequest.ts"
|
|
19
18
|
import * as Response from "./HttpServerResponse.ts"
|
|
20
19
|
import type { HttpServerResponse } from "./HttpServerResponse.ts"
|
|
21
20
|
import * as TraceContext from "./HttpTraceContext.ts"
|
|
21
|
+
import { appendPreResponseHandlerUnsafe } from "./internal/preResponseHandler.ts"
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* @since 4.0.0
|
|
@@ -142,10 +142,10 @@ export const tracer: <E, R>(
|
|
|
142
142
|
parent: TraceContext.fromHeaders(request.headers),
|
|
143
143
|
kind: "server"
|
|
144
144
|
})
|
|
145
|
-
const
|
|
145
|
+
const prevServices = fiber.services
|
|
146
146
|
fiber.setServices(ServiceMap.add(fiber.services, ParentSpan, span))
|
|
147
147
|
return Effect.onExitPrimitive(httpApp, (exit) => {
|
|
148
|
-
fiber.setServices(
|
|
148
|
+
fiber.setServices(prevServices)
|
|
149
149
|
const endTime = fiber.getRef(Clock).currentTimeNanosUnsafe()
|
|
150
150
|
fiber.currentScheduler.scheduleTask(() => {
|
|
151
151
|
const url = Request.toURL(request)
|
|
@@ -338,17 +338,7 @@ export const cors = (options?: {
|
|
|
338
338
|
headers: headersFromRequestOptions(request)
|
|
339
339
|
}))
|
|
340
340
|
}
|
|
341
|
-
|
|
342
|
-
const next = prev
|
|
343
|
-
? ((req: HttpServerRequest, res: HttpServerResponse) =>
|
|
344
|
-
Effect.flatMap(prev(req, res), (res) => preResponseHandler(req, res)))
|
|
345
|
-
: preResponseHandler
|
|
346
|
-
fiber.setServices(ServiceMap.add(fiber.services, PreResponseHandlers, next))
|
|
341
|
+
appendPreResponseHandlerUnsafe(request, preResponseHandler)
|
|
347
342
|
return httpApp
|
|
348
343
|
})
|
|
349
344
|
}
|
|
350
|
-
|
|
351
|
-
const PreResponseHandlers = ServiceMap.Reference<PreResponseHandler | undefined>(
|
|
352
|
-
"effect/http/HttpEffect/PreResponseHandlers",
|
|
353
|
-
{ defaultValue: () => undefined }
|
|
354
|
-
)
|
|
@@ -6,7 +6,9 @@ import * as Data from "../../Data.ts"
|
|
|
6
6
|
import * as Effect from "../../Effect.ts"
|
|
7
7
|
import * as ErrorReporter from "../../ErrorReporter.ts"
|
|
8
8
|
import type * as Exit from "../../Exit.ts"
|
|
9
|
+
import { constUndefined } from "../../Function.ts"
|
|
9
10
|
import { hasProperty } from "../../Predicate.ts"
|
|
11
|
+
import * as ServiceMap from "../../ServiceMap.ts"
|
|
10
12
|
import type * as Request from "./HttpServerRequest.ts"
|
|
11
13
|
import * as Respondable from "./HttpServerRespondable.ts"
|
|
12
14
|
import * as Response from "./HttpServerResponse.ts"
|
|
@@ -182,16 +184,25 @@ export class ServeError extends Data.TaggedError("ServeError")<{
|
|
|
182
184
|
readonly cause: unknown
|
|
183
185
|
}> {}
|
|
184
186
|
|
|
187
|
+
/**
|
|
188
|
+
* @since 4.0.0
|
|
189
|
+
* @category Annotations
|
|
190
|
+
*/
|
|
191
|
+
export class ClientAbort extends ServiceMap.Service<ClientAbort, true>()("effect/http/HttpServerError/ClientAbort") {
|
|
192
|
+
static annotation = this.serviceMap(true).pipe(
|
|
193
|
+
ServiceMap.add(Cause.StackTrace, {
|
|
194
|
+
name: "ClientAbort",
|
|
195
|
+
stack: constUndefined,
|
|
196
|
+
parent: undefined
|
|
197
|
+
})
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
185
201
|
const formatRequestMessage = (reason: string, description: string | undefined, info: string) => {
|
|
186
202
|
const prefix = `${reason} (${info})`
|
|
187
203
|
return description ? `${prefix}: ${description}` : prefix
|
|
188
204
|
}
|
|
189
205
|
|
|
190
|
-
/**
|
|
191
|
-
* @since 4.0.0
|
|
192
|
-
*/
|
|
193
|
-
export const clientAbortFiberId = -499
|
|
194
|
-
|
|
195
206
|
/**
|
|
196
207
|
* @since 4.0.0
|
|
197
208
|
*/
|
|
@@ -201,37 +212,37 @@ export const causeResponse = <E>(
|
|
|
201
212
|
let response: Response.HttpServerResponse | undefined
|
|
202
213
|
let effect = succeedInternalServerError
|
|
203
214
|
const failures: Array<Cause.Reason<E>> = []
|
|
204
|
-
let
|
|
215
|
+
let interrupts: Array<Cause.Interrupt> = []
|
|
205
216
|
let isClientInterrupt = false
|
|
206
217
|
for (let i = 0; i < cause.reasons.length; i++) {
|
|
207
|
-
const
|
|
208
|
-
switch (
|
|
218
|
+
const reason = cause.reasons[i]
|
|
219
|
+
switch (reason._tag) {
|
|
209
220
|
case "Fail": {
|
|
210
|
-
effect = Respondable.toResponseOrElse(
|
|
211
|
-
failures.push(
|
|
221
|
+
effect = Respondable.toResponseOrElse(reason.error, internalServerError)
|
|
222
|
+
failures.push(reason)
|
|
212
223
|
break
|
|
213
224
|
}
|
|
214
225
|
case "Die": {
|
|
215
|
-
if (Response.isHttpServerResponse(
|
|
216
|
-
response =
|
|
226
|
+
if (Response.isHttpServerResponse(reason.defect)) {
|
|
227
|
+
response = reason.defect
|
|
217
228
|
} else {
|
|
218
|
-
effect = Respondable.toResponseOrElseDefect(
|
|
219
|
-
failures.push(
|
|
229
|
+
effect = Respondable.toResponseOrElseDefect(reason.defect, internalServerError)
|
|
230
|
+
failures.push(reason)
|
|
220
231
|
}
|
|
221
232
|
break
|
|
222
233
|
}
|
|
223
234
|
case "Interrupt": {
|
|
224
|
-
isClientInterrupt =
|
|
235
|
+
isClientInterrupt = reason.annotations.has(ClientAbort.key)
|
|
225
236
|
if (failures.length > 0) break
|
|
226
|
-
|
|
237
|
+
interrupts.push(reason)
|
|
227
238
|
break
|
|
228
239
|
}
|
|
229
240
|
}
|
|
230
241
|
}
|
|
231
242
|
if (response) {
|
|
232
243
|
return Effect.succeed([response, Cause.fromReasons(failures)] as const)
|
|
233
|
-
} else if (
|
|
234
|
-
failures.push(
|
|
244
|
+
} else if (interrupts.length > 0 && failures.length === 0) {
|
|
245
|
+
failures.push(...interrupts)
|
|
235
246
|
effect = isClientInterrupt ? clientAbortError : serverAbortError
|
|
236
247
|
}
|
|
237
248
|
return Effect.mapEager(effect, (response) => {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as Effect from "../../../Effect.ts"
|
|
2
|
+
import type { PreResponseHandler } from "../HttpEffect.ts"
|
|
3
|
+
import type { HttpServerRequest } from "../HttpServerRequest.ts"
|
|
4
|
+
|
|
5
|
+
/** @internal */
|
|
6
|
+
export const requestPreResponseHandlers = new WeakMap<HttpServerRequest, PreResponseHandler>()
|
|
7
|
+
|
|
8
|
+
/** @internal */
|
|
9
|
+
export const appendPreResponseHandlerUnsafe = (request: HttpServerRequest, handler: PreResponseHandler): void => {
|
|
10
|
+
const prev = requestPreResponseHandlers.get(request)
|
|
11
|
+
const next: PreResponseHandler = prev ?
|
|
12
|
+
(request, response) => Effect.flatMap(prev(request, response), (response) => handler(request, response))
|
|
13
|
+
: handler
|
|
14
|
+
requestPreResponseHandlers.set(request, next)
|
|
15
|
+
}
|
|
@@ -356,7 +356,7 @@ export const securitySetCookie = (
|
|
|
356
356
|
self: HttpApiSecurity.ApiKey,
|
|
357
357
|
value: string | Redacted.Redacted,
|
|
358
358
|
options?: Cookie["options"]
|
|
359
|
-
): Effect.Effect<void> =>
|
|
359
|
+
): Effect.Effect<void, never, HttpServerRequest> =>
|
|
360
360
|
HttpEffect.appendPreResponseHandler((_req, response) =>
|
|
361
361
|
Effect.orDie(
|
|
362
362
|
Response.setCookie(response, self.key, stringOrRedacted(value), {
|
|
@@ -2070,7 +2070,7 @@ export const searchParam = <S extends Schema.Codec<any, string> = never>(name: s
|
|
|
2070
2070
|
window.removeEventListener("pushstate", handleUpdate)
|
|
2071
2071
|
})
|
|
2072
2072
|
const value = new URLSearchParams(window.location.search).get(name) || ""
|
|
2073
|
-
return decode ? Exit.
|
|
2073
|
+
return decode ? Exit.getSuccess(decode(value)) : value as any
|
|
2074
2074
|
},
|
|
2075
2075
|
(ctx, value: any) => {
|
|
2076
2076
|
if (typeof window === "undefined") {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 4.0.0
|
|
3
3
|
*/
|
|
4
|
+
import * as Cause from "../../Cause.ts"
|
|
5
|
+
import { constUndefined } from "../../Function.ts"
|
|
4
6
|
import * as Predicate from "../../Predicate.ts"
|
|
5
7
|
import * as Schema from "../../Schema.ts"
|
|
6
8
|
import type * as AST from "../../SchemaAST.ts"
|
|
9
|
+
import * as ServiceMap from "../../ServiceMap.ts"
|
|
7
10
|
import * as Stream_ from "../../Stream.ts"
|
|
8
11
|
|
|
9
12
|
const StreamSchemaTypeId = "~effect/rpc/RpcSchema/StreamSchema"
|
|
@@ -58,3 +61,17 @@ const schema = Schema.declare(Stream_.isStream)
|
|
|
58
61
|
export function Stream<A extends Schema.Top, E extends Schema.Top>(success: A, error: E): Stream<A, E> {
|
|
59
62
|
return Schema.make(schema.ast, { [StreamSchemaTypeId]: StreamSchemaTypeId, success, error })
|
|
60
63
|
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @since 4.0.0
|
|
67
|
+
* @category Cause annotations
|
|
68
|
+
*/
|
|
69
|
+
export class ClientAbort extends ServiceMap.Service<ClientAbort, true>()("effect/rpc/RpcSchema/ClientAbort") {
|
|
70
|
+
static annotation = this.serviceMap(true).pipe(
|
|
71
|
+
ServiceMap.add(Cause.StackTrace, {
|
|
72
|
+
name: "ClientAbort",
|
|
73
|
+
stack: constUndefined,
|
|
74
|
+
parent: undefined
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -107,11 +107,7 @@ export const jsonRpc = (options?: {
|
|
|
107
107
|
return decodeJsonRpcRaw(decoded, batches)
|
|
108
108
|
},
|
|
109
109
|
encode: (response) => {
|
|
110
|
-
|
|
111
|
-
if (response.length === 0) return undefined
|
|
112
|
-
return JSON.stringify(response.map(encodeJsonRpcMessage))
|
|
113
|
-
}
|
|
114
|
-
const encoded = encodeJsonRpcRaw(response as any, batches)
|
|
110
|
+
const encoded = encodeJsonRpcResponse(response as any, batches)
|
|
115
111
|
return encoded && JSON.stringify(encoded)
|
|
116
112
|
}
|
|
117
113
|
}
|
|
@@ -146,10 +142,7 @@ export const ndJsonRpc = (options?: {
|
|
|
146
142
|
return messages
|
|
147
143
|
},
|
|
148
144
|
encode: (response) => {
|
|
149
|
-
|
|
150
|
-
return parser.encode(response.map(encodeJsonRpcMessage))
|
|
151
|
-
}
|
|
152
|
-
const encoded = encodeJsonRpcRaw(response as any, batches)
|
|
145
|
+
const encoded = encodeJsonRpcResponse(response as any, batches)
|
|
153
146
|
return encoded && parser.encode(encoded)
|
|
154
147
|
}
|
|
155
148
|
})
|
|
@@ -171,6 +164,7 @@ function decodeJsonRpcRaw(
|
|
|
171
164
|
const messages: Array<RpcMessage.FromClientEncoded | RpcMessage.FromServerEncoded> = []
|
|
172
165
|
for (let i = 0; i < decoded.length; i++) {
|
|
173
166
|
const message = decodeJsonRpcMessage(decoded[i])
|
|
167
|
+
messages.push(message)
|
|
174
168
|
if (message._tag === "Request") {
|
|
175
169
|
batch.size++
|
|
176
170
|
batches.set(message.id, batch)
|
|
@@ -263,6 +257,47 @@ function encodeJsonRpcRaw(
|
|
|
263
257
|
return encodeJsonRpcMessage(response)
|
|
264
258
|
}
|
|
265
259
|
|
|
260
|
+
function encodeJsonRpcResponse(
|
|
261
|
+
response:
|
|
262
|
+
| RpcMessage.FromServerEncoded
|
|
263
|
+
| RpcMessage.FromClientEncoded
|
|
264
|
+
| Array<RpcMessage.FromServerEncoded | RpcMessage.FromClientEncoded>,
|
|
265
|
+
batches: Map<string, {
|
|
266
|
+
readonly size: number
|
|
267
|
+
readonly responses: Map<string, RpcMessage.FromServerEncoded>
|
|
268
|
+
}>
|
|
269
|
+
) {
|
|
270
|
+
if (Array.isArray(response) === false) {
|
|
271
|
+
return encodeJsonRpcRaw(response, batches)
|
|
272
|
+
}
|
|
273
|
+
if (response.length === 0) {
|
|
274
|
+
return undefined
|
|
275
|
+
}
|
|
276
|
+
const encoded: Array<JsonRpcMessage | Array<JsonRpcMessage>> = []
|
|
277
|
+
for (let i = 0; i < response.length; i++) {
|
|
278
|
+
const current = encodeJsonRpcRaw(response[i], batches)
|
|
279
|
+
if (current !== undefined) {
|
|
280
|
+
encoded.push(current)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (encoded.length === 0) {
|
|
284
|
+
return undefined
|
|
285
|
+
}
|
|
286
|
+
if (encoded.length === 1) {
|
|
287
|
+
return encoded[0]
|
|
288
|
+
}
|
|
289
|
+
const messages: Array<JsonRpcMessage> = []
|
|
290
|
+
for (let i = 0; i < encoded.length; i++) {
|
|
291
|
+
const current = encoded[i]
|
|
292
|
+
if (Array.isArray(current)) {
|
|
293
|
+
messages.push(...current)
|
|
294
|
+
} else {
|
|
295
|
+
messages.push(current)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return messages
|
|
299
|
+
}
|
|
300
|
+
|
|
266
301
|
function encodeJsonRpcMessage(response: RpcMessage.FromServerEncoded | RpcMessage.FromClientEncoded): JsonRpcMessage {
|
|
267
302
|
switch (response._tag) {
|
|
268
303
|
case "Request":
|
|
@@ -175,17 +175,16 @@ export const makeNoSerialization: <Rpcs extends Rpc.Any>(
|
|
|
175
175
|
}
|
|
176
176
|
case "Interrupt": {
|
|
177
177
|
const fiber = client.fibers.get(message.requestId)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
})
|
|
178
|
+
if (fiber) {
|
|
179
|
+
fiber.interruptUnsafe(requestFiber.id, RpcSchema.ClientAbort.annotation)
|
|
180
|
+
return Effect.void
|
|
181
|
+
}
|
|
182
|
+
return options.onFromServer({
|
|
183
|
+
_tag: "Exit",
|
|
184
|
+
clientId,
|
|
185
|
+
requestId: message.requestId,
|
|
186
|
+
exit: Exit.interrupt()
|
|
187
|
+
})
|
|
189
188
|
}
|
|
190
189
|
case "Eof": {
|
|
191
190
|
client.ended = true
|
|
@@ -1282,14 +1281,6 @@ export const layerProtocolWorkerRunner: Layer.Layer<
|
|
|
1282
1281
|
WorkerRunner.WorkerRunnerPlatform
|
|
1283
1282
|
> = Layer.effect(Protocol)(makeProtocolWorkerRunner)
|
|
1284
1283
|
|
|
1285
|
-
/**
|
|
1286
|
-
* Fiber id used to indicate client induced interrupts
|
|
1287
|
-
*
|
|
1288
|
-
* @since 4.0.0
|
|
1289
|
-
* @category Interruption
|
|
1290
|
-
*/
|
|
1291
|
-
export const fiberIdClientInterrupt = -499
|
|
1292
|
-
|
|
1293
1284
|
// internal
|
|
1294
1285
|
|
|
1295
1286
|
const makeSocketProtocol: Effect.Effect<
|