@effect/platform-bun 4.0.0-beta.7 → 4.0.0-beta.70
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/BunChildProcessSpawner.d.ts +1 -1
- package/dist/BunChildProcessSpawner.js +1 -1
- package/dist/BunClusterHttp.d.ts +46 -7
- package/dist/BunClusterHttp.d.ts.map +1 -1
- package/dist/BunClusterHttp.js +17 -10
- package/dist/BunClusterHttp.js.map +1 -1
- package/dist/BunClusterSocket.d.ts +54 -9
- package/dist/BunClusterSocket.d.ts.map +1 -1
- package/dist/BunClusterSocket.js +54 -9
- package/dist/BunClusterSocket.js.map +1 -1
- package/dist/BunCrypto.d.ts +10 -0
- package/dist/BunCrypto.d.ts.map +1 -0
- package/dist/BunCrypto.js +14 -0
- package/dist/BunCrypto.js.map +1 -0
- package/dist/BunFileSystem.d.ts +4 -2
- package/dist/BunFileSystem.d.ts.map +1 -1
- package/dist/BunFileSystem.js +27 -3
- package/dist/BunFileSystem.js.map +1 -1
- package/dist/BunHttpClient.d.ts +2 -2
- package/dist/BunHttpClient.js +2 -2
- package/dist/BunHttpPlatform.d.ts +4 -2
- package/dist/BunHttpPlatform.d.ts.map +1 -1
- package/dist/BunHttpPlatform.js +5 -3
- package/dist/BunHttpPlatform.js.map +1 -1
- package/dist/BunHttpServer.d.ts +77 -19
- package/dist/BunHttpServer.d.ts.map +1 -1
- package/dist/BunHttpServer.js +63 -36
- package/dist/BunHttpServer.js.map +1 -1
- package/dist/BunHttpServerRequest.d.ts +26 -2
- package/dist/BunHttpServerRequest.d.ts.map +1 -1
- package/dist/BunHttpServerRequest.js +3 -1
- package/dist/BunHttpServerRequest.js.map +1 -1
- package/dist/BunMultipart.d.ts +28 -5
- package/dist/BunMultipart.d.ts.map +1 -1
- package/dist/BunMultipart.js +15 -5
- package/dist/BunMultipart.js.map +1 -1
- package/dist/BunPath.d.ts +12 -6
- package/dist/BunPath.d.ts.map +1 -1
- package/dist/BunPath.js +30 -7
- package/dist/BunPath.js.map +1 -1
- package/dist/BunRedis.d.ts +39 -9
- package/dist/BunRedis.d.ts.map +1 -1
- package/dist/BunRedis.js +42 -12
- package/dist/BunRedis.js.map +1 -1
- package/dist/BunRuntime.d.ts +24 -30
- package/dist/BunRuntime.d.ts.map +1 -1
- package/dist/BunRuntime.js +25 -11
- package/dist/BunRuntime.js.map +1 -1
- package/dist/BunServices.d.ts +32 -5
- package/dist/BunServices.d.ts.map +1 -1
- package/dist/BunServices.js +7 -3
- package/dist/BunServices.js.map +1 -1
- package/dist/BunSink.d.ts +2 -2
- package/dist/BunSink.js +2 -2
- package/dist/BunSocket.d.ts +30 -4
- package/dist/BunSocket.d.ts.map +1 -1
- package/dist/BunSocket.js +10 -3
- package/dist/BunSocket.js.map +1 -1
- package/dist/BunSocketServer.d.ts +2 -2
- package/dist/BunSocketServer.js +2 -2
- package/dist/BunStdio.d.ts +5 -2
- package/dist/BunStdio.d.ts.map +1 -1
- package/dist/BunStdio.js +24 -3
- package/dist/BunStdio.js.map +1 -1
- package/dist/BunStream.d.ts +3 -2
- package/dist/BunStream.d.ts.map +1 -1
- package/dist/BunStream.js +25 -3
- package/dist/BunStream.js.map +1 -1
- package/dist/BunTerminal.d.ts +8 -2
- package/dist/BunTerminal.d.ts.map +1 -1
- package/dist/BunTerminal.js +23 -3
- package/dist/BunTerminal.js.map +1 -1
- package/dist/BunWorker.d.ts +9 -2
- package/dist/BunWorker.d.ts.map +1 -1
- package/dist/BunWorker.js +29 -4
- package/dist/BunWorker.js.map +1 -1
- package/dist/BunWorkerRunner.d.ts +5 -1
- package/dist/BunWorkerRunner.d.ts.map +1 -1
- package/dist/BunWorkerRunner.js +27 -5
- package/dist/BunWorkerRunner.js.map +1 -1
- package/dist/index.d.ts +396 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +396 -21
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/BunChildProcessSpawner.ts +1 -1
- package/src/BunClusterHttp.ts +51 -11
- package/src/BunClusterSocket.ts +54 -9
- package/src/BunCrypto.ts +16 -0
- package/src/BunFileSystem.ts +27 -3
- package/src/BunHttpClient.ts +2 -2
- package/src/BunHttpPlatform.ts +28 -4
- package/src/BunHttpServer.ts +128 -56
- package/src/BunHttpServerRequest.ts +26 -2
- package/src/BunMultipart.ts +36 -6
- package/src/BunPath.ts +30 -7
- package/src/BunRedis.ts +44 -14
- package/src/BunRuntime.ts +41 -31
- package/src/BunServices.ts +34 -5
- package/src/BunSink.ts +2 -2
- package/src/BunSocket.ts +30 -4
- package/src/BunSocketServer.ts +2 -2
- package/src/BunStdio.ts +24 -3
- package/src/BunStream.ts +25 -3
- package/src/BunTerminal.ts +23 -3
- package/src/BunWorker.ts +29 -4
- package/src/BunWorkerRunner.ts +27 -5
- package/src/index.ts +397 -21
package/src/BunClusterSocket.ts
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The `BunClusterSocket` module provides the Bun socket transport for Effect
|
|
3
|
+
* Cluster runners. It wires `SocketRunner` to Bun-compatible TCP sockets,
|
|
4
|
+
* supplies RPC client and server protocol layers, and builds a complete
|
|
5
|
+
* sharding layer with serialization, runner health, runner storage, and message
|
|
6
|
+
* storage.
|
|
7
|
+
*
|
|
8
|
+
* **Common tasks**
|
|
9
|
+
*
|
|
10
|
+
* - Run a Bun process as a cluster runner over raw TCP sockets with
|
|
11
|
+
* {@link layer}
|
|
12
|
+
* - Connect a client-only process to an existing socket cluster without
|
|
13
|
+
* starting a runner server
|
|
14
|
+
* - Use SQL-backed storage for durable multi-process clusters, `local` storage
|
|
15
|
+
* for short-lived development, or `byo` storage when the deployment owns the
|
|
16
|
+
* persistence boundary
|
|
17
|
+
* - Check runner health with socket pings or Kubernetes pod readiness through
|
|
18
|
+
* {@link layerK8sHttpClient}
|
|
19
|
+
*
|
|
20
|
+
* **Gotchas**
|
|
21
|
+
*
|
|
22
|
+
* - `runnerAddress` is the host and port advertised to other runners; set
|
|
23
|
+
* `runnerListenAddress` when the local bind address differs from the
|
|
24
|
+
* externally reachable address
|
|
25
|
+
* - The socket transport is point-to-point RPC, not cluster gossip: runner
|
|
26
|
+
* membership, shard ownership, and persisted delivery are coordinated through
|
|
27
|
+
* `RunnerStorage`, `MessageStorage`, and `RunnerHealth`
|
|
28
|
+
* - `clientOnly` does not start a socket server or receive shard assignments
|
|
29
|
+
* - SQL storage is the default; `local` storage is in-memory/noop and `byo`
|
|
30
|
+
* requires the surrounding application to provide both runner and message
|
|
31
|
+
* storage services
|
|
32
|
+
* - Ping health checks use the same socket protocol, so unreachable ports,
|
|
33
|
+
* firewalls, or serialization mismatches can make a runner appear unhealthy
|
|
34
|
+
* - Kubernetes health checks use Bun's Fetch-backed HTTP client and the service
|
|
35
|
+
* account CA certificate when it is available
|
|
36
|
+
*
|
|
37
|
+
* @since 4.0.0
|
|
3
38
|
*/
|
|
4
39
|
import { layerClientProtocol, layerSocketServer } from "@effect/platform-node-shared/NodeClusterSocket"
|
|
5
40
|
import type * as Config from "effect/Config"
|
|
@@ -24,20 +59,28 @@ import * as BunFileSystem from "./BunFileSystem.ts"
|
|
|
24
59
|
|
|
25
60
|
export {
|
|
26
61
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
62
|
+
* Provides the cluster `RpcClientProtocol` using the shared socket client
|
|
63
|
+
* implementation.
|
|
64
|
+
*
|
|
65
|
+
* @category re-exports
|
|
66
|
+
* @since 4.0.0
|
|
29
67
|
*/
|
|
30
68
|
layerClientProtocol,
|
|
31
69
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
70
|
+
* Provides the socket server used by Bun cluster runners through the shared
|
|
71
|
+
* socket server implementation.
|
|
72
|
+
*
|
|
73
|
+
* @category re-exports
|
|
74
|
+
* @since 4.0.0
|
|
34
75
|
*/
|
|
35
76
|
layerSocketServer
|
|
36
77
|
}
|
|
37
78
|
|
|
38
79
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
80
|
+
* Creates Bun socket cluster layers, configuring serialization, storage, runner health, and optional client-only mode.
|
|
81
|
+
*
|
|
82
|
+
* @category layers
|
|
83
|
+
* @since 4.0.0
|
|
41
84
|
*/
|
|
42
85
|
export const layer = <
|
|
43
86
|
const ClientOnly extends boolean = false,
|
|
@@ -110,8 +153,10 @@ export const layer = <
|
|
|
110
153
|
}
|
|
111
154
|
|
|
112
155
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
156
|
+
* Layer that provides `K8sHttpClient`, using the Kubernetes service-account CA certificate when it is available.
|
|
157
|
+
*
|
|
158
|
+
* @category layers
|
|
159
|
+
* @since 4.0.0
|
|
115
160
|
*/
|
|
116
161
|
export const layerK8sHttpClient: Layer.Layer<K8sHttpClient.K8sHttpClient> = K8sHttpClient.layer.pipe(
|
|
117
162
|
Layer.provide(Layer.unwrap(Effect.gen(function*() {
|
package/src/BunCrypto.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun platform Crypto service layer.
|
|
3
|
+
*
|
|
4
|
+
* @since 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
7
|
+
import type * as Crypto from "effect/Crypto"
|
|
8
|
+
import type * as Layer from "effect/Layer"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A layer that provides the Bun Crypto service implementation.
|
|
12
|
+
*
|
|
13
|
+
* @category layers
|
|
14
|
+
* @since 1.0.0
|
|
15
|
+
*/
|
|
16
|
+
export const layer: Layer.Layer<Crypto.Crypto> = NodeCrypto.layer
|
package/src/BunFileSystem.ts
CHANGED
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun layer for Effect's `FileSystem` service.
|
|
3
|
+
*
|
|
4
|
+
* Use this module at the edge of Bun applications, CLIs, scripts, and tests
|
|
5
|
+
* that need real local filesystem access through `effect/FileSystem`: reading
|
|
6
|
+
* and writing files, creating directories and temporary files, inspecting
|
|
7
|
+
* metadata, managing links, or watching paths for changes. It exposes only the
|
|
8
|
+
* Bun `FileSystem` layer; the operations themselves are accessed from the
|
|
9
|
+
* `FileSystem` service once the layer is provided, or from `BunServices.layer`
|
|
10
|
+
* when the program also needs the standard Bun path, stdio, terminal, and child
|
|
11
|
+
* process services.
|
|
12
|
+
*
|
|
13
|
+
* Bun supports Node-compatible filesystem APIs, so this layer reuses the shared
|
|
14
|
+
* Node filesystem implementation. Paths therefore follow the current process and
|
|
15
|
+
* host platform rules: relative paths are resolved from the current working
|
|
16
|
+
* directory, separators and drive/UNC behavior are platform-dependent, and
|
|
17
|
+
* request URLs should be decoded and validated before being mapped to local
|
|
18
|
+
* paths. The service works with bytes, scoped file handles, and Effect
|
|
19
|
+
* streams/sinks; use `FileSystem.stream` for large files instead of
|
|
20
|
+
* `readFile`, and remember that stream offsets and lengths are byte positions.
|
|
21
|
+
* Bun `File` and `Blob` values are not filesystem handles here; path-based HTTP
|
|
22
|
+
* file responses are handled by the Bun HTTP platform adapter with `Bun.file`.
|
|
23
|
+
*
|
|
24
|
+
* @since 4.0.0
|
|
3
25
|
*/
|
|
4
26
|
import * as NodeFileSystem from "@effect/platform-node-shared/NodeFileSystem"
|
|
5
27
|
import type { FileSystem } from "effect/FileSystem"
|
|
6
28
|
import type * as Layer from "effect/Layer"
|
|
7
29
|
|
|
8
30
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
31
|
+
* Layer that provides the `FileSystem` service for Bun using the shared Node file-system implementation.
|
|
32
|
+
*
|
|
33
|
+
* @category layers
|
|
34
|
+
* @since 4.0.0
|
|
11
35
|
*/
|
|
12
36
|
export const layer: Layer.Layer<FileSystem, never, never> = NodeFileSystem.layer
|
package/src/BunHttpClient.ts
CHANGED
package/src/BunHttpPlatform.ts
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun implementation of the Effect HTTP platform service.
|
|
3
|
+
*
|
|
4
|
+
* This module connects the portable `HttpPlatform` file response helpers to
|
|
5
|
+
* Bun's Web-compatible runtime. `BunHttpServer` provides this layer when
|
|
6
|
+
* applications serve local files, public assets, downloads, byte ranges, or
|
|
7
|
+
* Web `File` values from Effect `HttpServerResponse` constructors.
|
|
8
|
+
*
|
|
9
|
+
* Path-based responses are backed by `Bun.file`, and Web `File` responses are
|
|
10
|
+
* returned directly as raw response bodies. The shared `HttpPlatform` service
|
|
11
|
+
* still computes file metadata such as ETags and last-modified headers, while
|
|
12
|
+
* this adapter lets Bun's `Response` implementation handle the platform body.
|
|
13
|
+
*
|
|
14
|
+
* Because the Bun server adapter sits on top of Web `Request` and `Response`,
|
|
15
|
+
* request bodies follow the usual single-consumption rules: choose the
|
|
16
|
+
* streamed, text, URL-encoded, or multipart view that matches the route. For
|
|
17
|
+
* `FormData` responses, let the `Response` constructor create the multipart
|
|
18
|
+
* content type and boundary unless you intentionally override it. File
|
|
19
|
+
* responses take filesystem paths, not request URLs; Bun request URLs are
|
|
20
|
+
* absolute at the runtime edge, and route paths are normalized by
|
|
21
|
+
* `BunHttpServer`, so decode and validate URL pathnames before mapping them to
|
|
22
|
+
* files.
|
|
23
|
+
*
|
|
24
|
+
* @since 4.0.0
|
|
3
25
|
*/
|
|
4
26
|
import type { Effect } from "effect"
|
|
5
27
|
import type { FileSystem } from "effect/FileSystem"
|
|
@@ -10,8 +32,8 @@ import * as Response from "effect/unstable/http/HttpServerResponse"
|
|
|
10
32
|
import * as BunFileSystem from "./BunFileSystem.ts"
|
|
11
33
|
|
|
12
34
|
/**
|
|
13
|
-
* @since 1.0.0
|
|
14
35
|
* @category constructors
|
|
36
|
+
* @since 4.0.0
|
|
15
37
|
*/
|
|
16
38
|
const make: Effect.Effect<
|
|
17
39
|
Platform.HttpPlatform["Service"],
|
|
@@ -31,8 +53,10 @@ const make: Effect.Effect<
|
|
|
31
53
|
})
|
|
32
54
|
|
|
33
55
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
56
|
+
* Layer that provides the Bun `HttpPlatform`, including file responses backed by `Bun.file`.
|
|
57
|
+
*
|
|
58
|
+
* @category layers
|
|
59
|
+
* @since 4.0.0
|
|
36
60
|
*/
|
|
37
61
|
export const layer = Layer.effect(Platform.HttpPlatform)(make).pipe(
|
|
38
62
|
Layer.provide(BunFileSystem.layer),
|
package/src/BunHttpServer.ts
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun implementation of the Effect `HttpServer`.
|
|
3
|
+
*
|
|
4
|
+
* This module builds an Effect HTTP server from `Bun.serve`, translating Bun's
|
|
5
|
+
* Web `Request` objects into `HttpServerRequest` values and Effect
|
|
6
|
+
* `HttpServerResponse` values back into Web `Response` objects. It is the Bun
|
|
7
|
+
* runtime entry point for serving `HttpApp`s, streaming responses, file
|
|
8
|
+
* responses through `BunHttpPlatform`, multipart requests, and websocket
|
|
9
|
+
* endpoints through `HttpServerRequest.upgrade`.
|
|
10
|
+
*
|
|
11
|
+
* Common use cases include using {@link layer} or {@link layerConfig} to serve
|
|
12
|
+
* an application from Bun configuration, {@link layerServer} when only the
|
|
13
|
+
* `HttpServer` service is needed, and {@link layerTest} for tests that need an
|
|
14
|
+
* ephemeral Bun listener and fetch-compatible client.
|
|
15
|
+
*
|
|
16
|
+
* Bun supplies absolute request URLs and Web-standard request bodies. This
|
|
17
|
+
* adapter stores the normalized path-and-query URL on `HttpServerRequest.url`,
|
|
18
|
+
* while the underlying `Request` still follows Web body rules: pick the
|
|
19
|
+
* streamed, text, JSON, URL-encoded, or multipart view that matches the route
|
|
20
|
+
* instead of consuming the same body in incompatible ways. Because `Bun.serve`
|
|
21
|
+
* has a single active `fetch` handler, each `serve` call reloads that handler
|
|
22
|
+
* and restores the previous one when the serve scope finalizes.
|
|
23
|
+
*
|
|
24
|
+
* WebSocket upgrades must happen from the Bun request handler. The
|
|
25
|
+
* `HttpServerRequest.upgrade` effect calls `server.upgrade`, fails when Bun says
|
|
26
|
+
* the request is not upgradeable, buffers messages that arrive before the
|
|
27
|
+
* Effect socket handler is installed, and maps non-normal close codes into
|
|
28
|
+
* `Socket` errors. The server is stopped with `server.stop()` when its
|
|
29
|
+
* acquisition scope closes; unless preemptive shutdown is disabled, finalizing
|
|
30
|
+
* a serve scope also starts that stop with the configured graceful shutdown
|
|
31
|
+
* timeout or the default timeout.
|
|
32
|
+
*
|
|
33
|
+
* @since 4.0.0
|
|
3
34
|
*/
|
|
4
35
|
import type { Server as BunServer, ServerWebSocket } from "bun"
|
|
5
36
|
import * as Config from "effect/Config"
|
|
6
37
|
import type { ConfigError } from "effect/Config"
|
|
38
|
+
import * as Context from "effect/Context"
|
|
7
39
|
import * as Deferred from "effect/Deferred"
|
|
40
|
+
import * as Duration from "effect/Duration"
|
|
8
41
|
import * as Effect from "effect/Effect"
|
|
9
42
|
import * as Exit from "effect/Exit"
|
|
10
43
|
import * as Fiber from "effect/Fiber"
|
|
@@ -13,11 +46,12 @@ import type * as FileSystem from "effect/FileSystem"
|
|
|
13
46
|
import { flow } from "effect/Function"
|
|
14
47
|
import * as Inspectable from "effect/Inspectable"
|
|
15
48
|
import * as Layer from "effect/Layer"
|
|
49
|
+
import * as Option from "effect/Option"
|
|
16
50
|
import type * as Path from "effect/Path"
|
|
17
51
|
import type * as Record from "effect/Record"
|
|
18
|
-
import type * as
|
|
52
|
+
import type * as Schema from "effect/Schema"
|
|
53
|
+
import * as Scope from "effect/Scope"
|
|
19
54
|
import * as Semaphore from "effect/Semaphore"
|
|
20
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
21
55
|
import * as Stream from "effect/Stream"
|
|
22
56
|
import * as Cookies from "effect/unstable/http/Cookies"
|
|
23
57
|
import * as Etag from "effect/unstable/http/Etag"
|
|
@@ -41,8 +75,10 @@ import * as BunServices from "./BunServices.ts"
|
|
|
41
75
|
import * as BunStream from "./BunStream.ts"
|
|
42
76
|
|
|
43
77
|
/**
|
|
44
|
-
*
|
|
78
|
+
* Bun serve options accepted by the HTTP server, extended with typed route definitions.
|
|
79
|
+
*
|
|
45
80
|
* @category Options
|
|
81
|
+
* @since 4.0.0
|
|
46
82
|
*/
|
|
47
83
|
export type ServeOptions<R extends string> =
|
|
48
84
|
& (
|
|
@@ -52,13 +88,19 @@ export type ServeOptions<R extends string> =
|
|
|
52
88
|
& { readonly routes?: Bun.Serve.Routes<WebSocketContext, R> }
|
|
53
89
|
|
|
54
90
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
91
|
+
* Creates a scoped Bun `HttpServer` from `Bun.serve` options, stopping the server on scope finalization with optional graceful shutdown settings.
|
|
92
|
+
*
|
|
93
|
+
* @category constructors
|
|
94
|
+
* @since 4.0.0
|
|
57
95
|
*/
|
|
58
96
|
export const make = Effect.fnUntraced(
|
|
59
97
|
function*<R extends string>(
|
|
60
|
-
options: ServeOptions<R>
|
|
98
|
+
options: ServeOptions<R> & {
|
|
99
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
100
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
101
|
+
}
|
|
61
102
|
) {
|
|
103
|
+
const scope = yield* Effect.scope
|
|
62
104
|
const handlerStack: Array<(request: Request, server: BunServer<WebSocketContext>) => Response | Promise<Response>> =
|
|
63
105
|
[
|
|
64
106
|
function(_request, _server) {
|
|
@@ -76,6 +118,7 @@ export const make = Effect.fnUntraced(
|
|
|
76
118
|
ws.data.run(message)
|
|
77
119
|
},
|
|
78
120
|
close(ws, code, closeReason) {
|
|
121
|
+
code = typeof code === "number" ? code : 1001
|
|
79
122
|
Deferred.doneUnsafe(
|
|
80
123
|
ws.data.closeDeferred,
|
|
81
124
|
Socket.defaultCloseCodeIsError(code)
|
|
@@ -90,13 +133,24 @@ export const make = Effect.fnUntraced(
|
|
|
90
133
|
}
|
|
91
134
|
})
|
|
92
135
|
|
|
93
|
-
yield* Effect.
|
|
136
|
+
const shutdown = yield* Effect.promise(() => server.stop()).pipe(
|
|
137
|
+
Effect.cached
|
|
138
|
+
)
|
|
139
|
+
const preemptiveShutdown = options.disablePreemptiveShutdown ? Effect.void : Effect.timeoutOrElse(shutdown, {
|
|
140
|
+
duration: options.gracefulShutdownTimeout ?? Duration.seconds(20),
|
|
141
|
+
orElse: () => Effect.void
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
yield* Scope.addFinalizer(scope, shutdown)
|
|
94
145
|
|
|
95
146
|
return Server.make({
|
|
96
147
|
address: { _tag: "TcpAddress", port: server.port!, hostname: server.hostname! },
|
|
97
148
|
serve: Effect.fnUntraced(function*(httpApp, middleware) {
|
|
98
|
-
const
|
|
99
|
-
const services =
|
|
149
|
+
const parent = yield* Effect.fiber
|
|
150
|
+
const services = parent.context
|
|
151
|
+
const serveScope = Context.getUnsafe(services, Scope.Scope)
|
|
152
|
+
const scope = Scope.forkUnsafe(serveScope, "parallel")
|
|
153
|
+
|
|
100
154
|
const httpEffect = HttpEffect.toHandled(httpApp, (request, response) =>
|
|
101
155
|
Effect.sync(() => {
|
|
102
156
|
;(request as BunServerRequest).resolve(makeResponse(request, response, services, scope))
|
|
@@ -109,24 +163,20 @@ export const make = Effect.fnUntraced(
|
|
|
109
163
|
ServerRequest.HttpServerRequest.key,
|
|
110
164
|
new BunServerRequest(request, resolve, removeHost(request.url), server)
|
|
111
165
|
)
|
|
112
|
-
const fiber = Fiber.runIn(Effect.runForkWith(
|
|
166
|
+
const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(httpEffect), scope)
|
|
113
167
|
request.signal.addEventListener("abort", () => {
|
|
114
|
-
fiber.interruptUnsafe(Error.
|
|
168
|
+
fiber.interruptUnsafe(parent.id, Error.ClientAbort.annotation)
|
|
115
169
|
}, { once: true })
|
|
116
170
|
})
|
|
117
171
|
}
|
|
118
172
|
|
|
119
|
-
yield*
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
handlerStack.pop()
|
|
127
|
-
server.reload({ fetch: handlerStack[handlerStack.length - 1] })
|
|
128
|
-
})
|
|
129
|
-
)
|
|
173
|
+
yield* Scope.addFinalizerExit(serveScope, () => {
|
|
174
|
+
handlerStack.pop()
|
|
175
|
+
server.reload({ fetch: handlerStack[handlerStack.length - 1] })
|
|
176
|
+
return preemptiveShutdown
|
|
177
|
+
})
|
|
178
|
+
handlerStack.push(handler)
|
|
179
|
+
server.reload({ fetch: handler })
|
|
130
180
|
})
|
|
131
181
|
})
|
|
132
182
|
}
|
|
@@ -135,7 +185,7 @@ export const make = Effect.fnUntraced(
|
|
|
135
185
|
const makeResponse = (
|
|
136
186
|
request: ServerRequest.HttpServerRequest,
|
|
137
187
|
response: ServerResponse.HttpServerResponse,
|
|
138
|
-
|
|
188
|
+
context: Context.Context<never>,
|
|
139
189
|
scope: Scope.Scope
|
|
140
190
|
): Response => {
|
|
141
191
|
const fields: {
|
|
@@ -186,7 +236,7 @@ const makeResponse = (
|
|
|
186
236
|
Fiber.runIn(fiber, scope)
|
|
187
237
|
return Effect.succeed(body.stream)
|
|
188
238
|
})),
|
|
189
|
-
|
|
239
|
+
context
|
|
190
240
|
),
|
|
191
241
|
fields
|
|
192
242
|
)
|
|
@@ -195,16 +245,23 @@ const makeResponse = (
|
|
|
195
245
|
}
|
|
196
246
|
|
|
197
247
|
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
248
|
+
* Layer that provides only `HttpServer` by constructing a scoped Bun server from the supplied serve options.
|
|
249
|
+
*
|
|
250
|
+
* @category layers
|
|
251
|
+
* @since 4.0.0
|
|
200
252
|
*/
|
|
201
253
|
export const layerServer: <R extends string>(
|
|
202
|
-
options: ServeOptions<R>
|
|
254
|
+
options: ServeOptions<R> & {
|
|
255
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
256
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
257
|
+
}
|
|
203
258
|
) => Layer.Layer<Server.HttpServer> = flow(make, Layer.effect(Server.HttpServer)) as any
|
|
204
259
|
|
|
205
260
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
261
|
+
* Layer that provides Bun HTTP support services: `HttpPlatform`, weak ETag generation, and `BunServices`.
|
|
262
|
+
*
|
|
263
|
+
* @category layers
|
|
264
|
+
* @since 4.0.0
|
|
208
265
|
*/
|
|
209
266
|
export const layerHttpServices: Layer.Layer<
|
|
210
267
|
| HttpPlatform
|
|
@@ -217,11 +274,16 @@ export const layerHttpServices: Layer.Layer<
|
|
|
217
274
|
)
|
|
218
275
|
|
|
219
276
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
277
|
+
* Layer that provides a Bun `HttpServer` together with the Bun HTTP platform, ETag generator, and Bun services.
|
|
278
|
+
*
|
|
279
|
+
* @category layers
|
|
280
|
+
* @since 4.0.0
|
|
222
281
|
*/
|
|
223
282
|
export const layer = <R extends string>(
|
|
224
|
-
options: ServeOptions<R>
|
|
283
|
+
options: ServeOptions<R> & {
|
|
284
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
285
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
286
|
+
}
|
|
225
287
|
): Layer.Layer<
|
|
226
288
|
| Server.HttpServer
|
|
227
289
|
| HttpPlatform
|
|
@@ -230,8 +292,10 @@ export const layer = <R extends string>(
|
|
|
230
292
|
> => Layer.mergeAll(layerServer(options), layerHttpServices)
|
|
231
293
|
|
|
232
294
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
295
|
+
* Test layer that starts a Bun HTTP server on an ephemeral port and provides the HTTP test client dependencies.
|
|
296
|
+
*
|
|
297
|
+
* @category layers
|
|
298
|
+
* @since 4.0.0
|
|
235
299
|
*/
|
|
236
300
|
export const layerTest: Layer.Layer<
|
|
237
301
|
Server.HttpServer | HttpPlatform | FileSystem.FileSystem | Etag.Generator | Path.Path | HttpClient
|
|
@@ -243,17 +307,24 @@ export const layerTest: Layer.Layer<
|
|
|
243
307
|
)
|
|
244
308
|
|
|
245
309
|
/**
|
|
246
|
-
*
|
|
247
|
-
*
|
|
310
|
+
* Creates the Bun HTTP server and support-services layer from configurable serve options.
|
|
311
|
+
*
|
|
312
|
+
* @category layers
|
|
313
|
+
* @since 4.0.0
|
|
248
314
|
*/
|
|
249
315
|
export const layerConfig = <R extends string>(
|
|
250
|
-
options: Config.Wrap<
|
|
316
|
+
options: Config.Wrap<
|
|
317
|
+
ServeOptions<R> & {
|
|
318
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
319
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
320
|
+
}
|
|
321
|
+
>
|
|
251
322
|
): Layer.Layer<
|
|
252
323
|
Server.HttpServer | HttpPlatform | FileSystem.FileSystem | Etag.Generator | Path.Path,
|
|
253
324
|
ConfigError
|
|
254
325
|
> =>
|
|
255
326
|
Layer.mergeAll(
|
|
256
|
-
Layer.effect(Server.HttpServer)(Effect.flatMap(Config.unwrap(options)
|
|
327
|
+
Layer.effect(Server.HttpServer)(Effect.flatMap(Config.unwrap(options), make)),
|
|
257
328
|
layerHttpServices
|
|
258
329
|
)
|
|
259
330
|
|
|
@@ -280,7 +351,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
280
351
|
readonly url: string
|
|
281
352
|
private bunServer: BunServer<WebSocketContext>
|
|
282
353
|
public headersOverride?: Headers.Headers | undefined
|
|
283
|
-
private remoteAddressOverride?: string | undefined
|
|
354
|
+
private remoteAddressOverride?: Option.Option<string> | undefined
|
|
284
355
|
|
|
285
356
|
constructor(
|
|
286
357
|
source: Request,
|
|
@@ -288,7 +359,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
288
359
|
url: string,
|
|
289
360
|
bunServer: BunServer<WebSocketContext>,
|
|
290
361
|
headersOverride?: Headers.Headers,
|
|
291
|
-
remoteAddressOverride?: string
|
|
362
|
+
remoteAddressOverride?: Option.Option<string>
|
|
292
363
|
) {
|
|
293
364
|
super()
|
|
294
365
|
this[ServerRequest.TypeId] = ServerRequest.TypeId
|
|
@@ -311,7 +382,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
311
382
|
options: {
|
|
312
383
|
readonly url?: string | undefined
|
|
313
384
|
readonly headers?: Headers.Headers | undefined
|
|
314
|
-
readonly remoteAddress?: string | undefined
|
|
385
|
+
readonly remoteAddress?: Option.Option<string> | undefined
|
|
315
386
|
}
|
|
316
387
|
) {
|
|
317
388
|
return new BunServerRequest(
|
|
@@ -320,7 +391,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
320
391
|
options.url ?? this.url,
|
|
321
392
|
this.bunServer,
|
|
322
393
|
options.headers ?? this.headersOverride,
|
|
323
|
-
options.remoteAddress
|
|
394
|
+
"remoteAddress" in options ? options.remoteAddress : this.remoteAddressOverride
|
|
324
395
|
)
|
|
325
396
|
}
|
|
326
397
|
get method(): HttpMethod {
|
|
@@ -329,8 +400,8 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
329
400
|
get originalUrl() {
|
|
330
401
|
return this.source.url
|
|
331
402
|
}
|
|
332
|
-
get remoteAddress(): string
|
|
333
|
-
return this.remoteAddressOverride ?? this.bunServer.requestIP(this.source)?.address
|
|
403
|
+
get remoteAddress(): Option.Option<string> {
|
|
404
|
+
return this.remoteAddressOverride ?? Option.fromNullishOr(this.bunServer.requestIP(this.source)?.address)
|
|
334
405
|
}
|
|
335
406
|
get headers(): Headers.Headers {
|
|
336
407
|
this.headersOverride ??= Headers.fromInput(this.source.headers)
|
|
@@ -348,7 +419,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
348
419
|
get stream(): Stream.Stream<Uint8Array, Error.HttpServerError> {
|
|
349
420
|
return this.source.body
|
|
350
421
|
? BunStream.fromReadableStream({
|
|
351
|
-
evaluate: () => this.source.body
|
|
422
|
+
evaluate: () => this.source.body ?? emptyReadbleStream,
|
|
352
423
|
onError: (cause) =>
|
|
353
424
|
new Error.HttpServerError({
|
|
354
425
|
reason: new Error.RequestParseError({
|
|
@@ -387,10 +458,10 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
387
458
|
return this.textEffect
|
|
388
459
|
}
|
|
389
460
|
|
|
390
|
-
get json(): Effect.Effect<
|
|
461
|
+
get json(): Effect.Effect<Schema.Json, Error.HttpServerError> {
|
|
391
462
|
return Effect.flatMap(this.text, (_) =>
|
|
392
463
|
Effect.try({
|
|
393
|
-
try: () => JSON.parse(_) as
|
|
464
|
+
try: () => JSON.parse(_) as Schema.Json,
|
|
394
465
|
catch: (cause) =>
|
|
395
466
|
new Error.HttpServerError({
|
|
396
467
|
reason: new Error.RequestParseError({
|
|
@@ -457,6 +528,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
457
528
|
})
|
|
458
529
|
})
|
|
459
530
|
))
|
|
531
|
+
this.textEffect = Effect.map(this.arrayBufferEffect, (_) => new TextDecoder().decode(_))
|
|
460
532
|
return this.arrayBufferEffect
|
|
461
533
|
}
|
|
462
534
|
|
|
@@ -524,14 +596,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
524
596
|
semaphore.withPermits(1)
|
|
525
597
|
)
|
|
526
598
|
|
|
527
|
-
|
|
528
|
-
const run = <R, E, _>(handler: (_: Uint8Array) => Effect.Effect<_, E, R> | void, opts?: {
|
|
529
|
-
readonly onOpen?: Effect.Effect<void> | undefined
|
|
530
|
-
}) => runRaw((data) => typeof data === "string" ? handler(encoder.encode(data)) : handler(data), opts)
|
|
531
|
-
|
|
532
|
-
return Socket.Socket.of({
|
|
533
|
-
[Socket.TypeId]: Socket.TypeId as typeof Socket.TypeId,
|
|
534
|
-
run,
|
|
599
|
+
return Socket.make({
|
|
535
600
|
runRaw,
|
|
536
601
|
writer
|
|
537
602
|
})
|
|
@@ -540,6 +605,13 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
540
605
|
}
|
|
541
606
|
}
|
|
542
607
|
|
|
608
|
+
const emptyReadbleStream = new ReadableStream({
|
|
609
|
+
start(controller) {
|
|
610
|
+
controller.enqueue(new Uint8Array())
|
|
611
|
+
controller.close()
|
|
612
|
+
}
|
|
613
|
+
})
|
|
614
|
+
|
|
543
615
|
const removeHost = (url: string) => {
|
|
544
616
|
if (url[0] === "/") {
|
|
545
617
|
return url
|
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Accessors for the Bun `Request` object backing a platform Bun
|
|
3
|
+
* `HttpServerRequest`.
|
|
4
|
+
*
|
|
5
|
+
* Use this module at interop boundaries when an Effect HTTP handler needs the
|
|
6
|
+
* original `Bun.BunRequest`, for example to read Bun route parameters, pass the
|
|
7
|
+
* request to Bun-specific APIs, inspect Web `Request` fields that are not
|
|
8
|
+
* exposed by the portable `HttpServerRequest` interface, or coordinate with code
|
|
9
|
+
* that already works directly with Bun's server request type.
|
|
10
|
+
*
|
|
11
|
+
* The returned request is the original Web request supplied by `Bun.serve`. It
|
|
12
|
+
* does not reflect Effect request overrides made by middleware, such as a
|
|
13
|
+
* rewritten URL, adjusted headers, or a substituted remote address. Its body is
|
|
14
|
+
* the same one-shot Web `ReadableStream` used by the Effect body helpers, so
|
|
15
|
+
* calling `text`, `json`, `formData`, `arrayBuffer`, or reading `body` directly
|
|
16
|
+
* can disturb the request and conflict with Effect body, multipart, or stream
|
|
17
|
+
* helpers unless ownership of the body is clear.
|
|
18
|
+
*
|
|
19
|
+
* Bun stores client IP information on the server rather than on the request
|
|
20
|
+
* object. Prefer `HttpServerRequest.remoteAddress` when you need the address
|
|
21
|
+
* seen by Effect or middleware; the raw request returned here will not expose
|
|
22
|
+
* middleware-provided remote address overrides.
|
|
23
|
+
*
|
|
24
|
+
* @since 4.0.0
|
|
3
25
|
*/
|
|
4
26
|
import type { HttpServerRequest } from "effect/unstable/http/HttpServerRequest"
|
|
5
27
|
|
|
6
28
|
/**
|
|
7
|
-
*
|
|
29
|
+
* Returns the underlying `Bun.BunRequest` from an Effect `HttpServerRequest`.
|
|
30
|
+
*
|
|
8
31
|
* @category Accessors
|
|
32
|
+
* @since 4.0.0
|
|
9
33
|
*/
|
|
10
34
|
export const toBunServerRequest = <T extends string = string>(self: HttpServerRequest): Bun.BunRequest<T> =>
|
|
11
35
|
(self as any).source
|