@effect/platform-bun 4.0.0-beta.9 → 4.0.0-beta.91
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 +44 -7
- package/dist/BunClusterHttp.d.ts.map +1 -1
- package/dist/BunClusterHttp.js +41 -10
- package/dist/BunClusterHttp.js.map +1 -1
- package/dist/BunClusterSocket.d.ts +27 -9
- package/dist/BunClusterSocket.d.ts.map +1 -1
- package/dist/BunClusterSocket.js +27 -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 +22 -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 +11 -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 +57 -20
- 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 +11 -3
- package/dist/BunHttpServerRequest.d.ts.map +1 -1
- package/dist/BunHttpServerRequest.js +4 -2
- package/dist/BunHttpServerRequest.js.map +1 -1
- package/dist/BunMultipart.d.ts +16 -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 +20 -7
- package/dist/BunPath.js.map +1 -1
- package/dist/BunRedis.d.ts +23 -9
- package/dist/BunRedis.d.ts.map +1 -1
- package/dist/BunRedis.js +26 -12
- package/dist/BunRedis.js.map +1 -1
- package/dist/BunRuntime.d.ts +21 -30
- package/dist/BunRuntime.d.ts.map +1 -1
- package/dist/BunRuntime.js +14 -11
- package/dist/BunRuntime.js.map +1 -1
- package/dist/BunServices.d.ts +19 -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 +18 -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 +13 -3
- package/dist/BunStdio.js.map +1 -1
- package/dist/BunStream.d.ts +5 -4
- package/dist/BunStream.d.ts.map +1 -1
- package/dist/BunStream.js +14 -5
- 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 +15 -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 +20 -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 +17 -5
- package/dist/BunWorkerRunner.js.map +1 -1
- package/dist/index.d.ts +25 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -23
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/BunChildProcessSpawner.ts +1 -1
- package/src/BunClusterHttp.ts +49 -11
- package/src/BunClusterSocket.ts +27 -9
- package/src/BunCrypto.ts +24 -0
- package/src/BunFileSystem.ts +11 -3
- package/src/BunHttpClient.ts +2 -2
- package/src/BunHttpPlatform.ts +14 -4
- package/src/BunHttpServer.ts +108 -57
- package/src/BunHttpServerRequest.ts +11 -3
- package/src/BunMultipart.ts +24 -6
- package/src/BunPath.ts +20 -7
- package/src/BunRedis.ts +28 -14
- package/src/BunRuntime.ts +28 -31
- package/src/BunServices.ts +21 -5
- package/src/BunSink.ts +2 -2
- package/src/BunSocket.ts +18 -4
- package/src/BunSocketServer.ts +2 -2
- package/src/BunStdio.ts +13 -3
- package/src/BunStream.ts +14 -5
- package/src/BunTerminal.ts +15 -3
- package/src/BunWorker.ts +20 -4
- package/src/BunWorkerRunner.ts +17 -5
- package/src/index.ts +26 -23
package/src/BunClusterHttp.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun HTTP and WebSocket layers for Effect Cluster runners.
|
|
3
|
+
*
|
|
4
|
+
* `layerHttpServer` provides the Bun HTTP server used by cluster runners. The
|
|
5
|
+
* main `layer` builds a sharding layer for HTTP or WebSocket transport,
|
|
6
|
+
* choosing serialization, runner health checks, runner storage, message
|
|
7
|
+
* storage, and optional client-only mode from the supplied options.
|
|
8
|
+
*
|
|
9
|
+
* @since 4.0.0
|
|
3
10
|
*/
|
|
4
11
|
import type * as Config from "effect/Config"
|
|
5
12
|
import * as Effect from "effect/Effect"
|
|
6
13
|
import * as Layer from "effect/Layer"
|
|
14
|
+
import * as Option from "effect/Option"
|
|
7
15
|
import * as HttpRunner from "effect/unstable/cluster/HttpRunner"
|
|
8
16
|
import * as MessageStorage from "effect/unstable/cluster/MessageStorage"
|
|
9
17
|
import * as RunnerHealth from "effect/unstable/cluster/RunnerHealth"
|
|
@@ -28,15 +36,19 @@ import * as BunSocket from "./BunSocket.ts"
|
|
|
28
36
|
|
|
29
37
|
export {
|
|
30
38
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
39
|
+
* Layer that provides a Kubernetes HTTP client for runner health checks.
|
|
40
|
+
*
|
|
41
|
+
* @category re-exports
|
|
42
|
+
* @since 4.0.0
|
|
33
43
|
*/
|
|
34
44
|
layerK8sHttpClient
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
48
|
+
* Layer that provides a Bun HTTP server for cluster runners.
|
|
49
|
+
*
|
|
50
|
+
* @category layers
|
|
51
|
+
* @since 4.0.0
|
|
40
52
|
*/
|
|
41
53
|
export const layerHttpServer: Layer.Layer<
|
|
42
54
|
| HttpPlatform
|
|
@@ -47,16 +59,42 @@ export const layerHttpServer: Layer.Layer<
|
|
|
47
59
|
ShardingConfig.ShardingConfig
|
|
48
60
|
> = Effect.gen(function*() {
|
|
49
61
|
const config = yield* ShardingConfig.ShardingConfig
|
|
50
|
-
const listenAddress = config.runnerListenAddress
|
|
51
|
-
if (listenAddress
|
|
52
|
-
return yield* Effect.die("BunClusterHttp.layerHttpServer: ShardingConfig.runnerAddress is
|
|
62
|
+
const listenAddress = Option.orElse(config.runnerListenAddress, () => config.runnerAddress)
|
|
63
|
+
if (Option.isNone(listenAddress)) {
|
|
64
|
+
return yield* Effect.die("BunClusterHttp.layerHttpServer: ShardingConfig.runnerAddress is None")
|
|
53
65
|
}
|
|
54
|
-
return BunHttpServer.layer(listenAddress)
|
|
66
|
+
return BunHttpServer.layer(listenAddress.value)
|
|
55
67
|
}).pipe(Layer.unwrap)
|
|
56
68
|
|
|
57
69
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
70
|
+
* Creates Bun cluster layers for HTTP or WebSocket transport, configuring serialization, storage, runner health, and optional client-only mode.
|
|
71
|
+
*
|
|
72
|
+
* **When to use**
|
|
73
|
+
*
|
|
74
|
+
* Use to install the complete Bun HTTP or WebSocket cluster layer, including
|
|
75
|
+
* client-only cluster access when a process should connect without serving
|
|
76
|
+
* runner RPCs.
|
|
77
|
+
*
|
|
78
|
+
* **Details**
|
|
79
|
+
*
|
|
80
|
+
* `serialization` defaults to MessagePack, `runnerHealth` defaults to ping
|
|
81
|
+
* checks, SQL-backed storage is used by default, and `shardingConfig` is
|
|
82
|
+
* overlaid on environment-loaded sharding configuration. `local` storage uses
|
|
83
|
+
* no-op message storage plus in-memory runner storage, while `byo` leaves both
|
|
84
|
+
* message and runner storage for the caller to provide.
|
|
85
|
+
*
|
|
86
|
+
* **Gotchas**
|
|
87
|
+
*
|
|
88
|
+
* `clientOnly` does not start the HTTP server or receive shard assignments.
|
|
89
|
+
* Non-client-only mode listens with `runnerListenAddress` when present, falling
|
|
90
|
+
* back to `runnerAddress`. HTTP and WebSocket runner RPCs use the default
|
|
91
|
+
* `HttpRunner` route.
|
|
92
|
+
*
|
|
93
|
+
* @see {@link layerHttpServer} for the server layer used by non-client-only transports
|
|
94
|
+
* @see {@link layerK8sHttpClient} for Kubernetes runner health support
|
|
95
|
+
*
|
|
96
|
+
* @category layers
|
|
97
|
+
* @since 4.0.0
|
|
60
98
|
*/
|
|
61
99
|
export const layer = <
|
|
62
100
|
const ClientOnly extends boolean = false,
|
package/src/BunClusterSocket.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun socket layers for Effect Cluster runners.
|
|
3
|
+
*
|
|
4
|
+
* The main `layer` builds a sharding layer for socket transport, choosing
|
|
5
|
+
* serialization, runner health checks, runner storage, message storage, and
|
|
6
|
+
* optional client-only mode from the supplied options. This module also
|
|
7
|
+
* re-exports the shared socket client and server protocol layers and provides
|
|
8
|
+
* `layerK8sHttpClient` for Kubernetes runner health checks.
|
|
9
|
+
*
|
|
10
|
+
* @since 4.0.0
|
|
3
11
|
*/
|
|
4
12
|
import { layerClientProtocol, layerSocketServer } from "@effect/platform-node-shared/NodeClusterSocket"
|
|
5
13
|
import type * as Config from "effect/Config"
|
|
@@ -24,20 +32,28 @@ import * as BunFileSystem from "./BunFileSystem.ts"
|
|
|
24
32
|
|
|
25
33
|
export {
|
|
26
34
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
35
|
+
* Provides the cluster `RpcClientProtocol` using the shared socket client
|
|
36
|
+
* implementation.
|
|
37
|
+
*
|
|
38
|
+
* @category re-exports
|
|
39
|
+
* @since 4.0.0
|
|
29
40
|
*/
|
|
30
41
|
layerClientProtocol,
|
|
31
42
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
43
|
+
* Provides the socket server used by Bun cluster runners through the shared
|
|
44
|
+
* socket server implementation.
|
|
45
|
+
*
|
|
46
|
+
* @category re-exports
|
|
47
|
+
* @since 4.0.0
|
|
34
48
|
*/
|
|
35
49
|
layerSocketServer
|
|
36
50
|
}
|
|
37
51
|
|
|
38
52
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
53
|
+
* Creates Bun socket cluster layers, configuring serialization, storage, runner health, and optional client-only mode.
|
|
54
|
+
*
|
|
55
|
+
* @category layers
|
|
56
|
+
* @since 4.0.0
|
|
41
57
|
*/
|
|
42
58
|
export const layer = <
|
|
43
59
|
const ClientOnly extends boolean = false,
|
|
@@ -110,8 +126,10 @@ export const layer = <
|
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
129
|
+
* Layer that provides `K8sHttpClient`, using the Kubernetes service-account CA certificate when it is available.
|
|
130
|
+
*
|
|
131
|
+
* @category layers
|
|
132
|
+
* @since 4.0.0
|
|
115
133
|
*/
|
|
116
134
|
export const layerK8sHttpClient: Layer.Layer<K8sHttpClient.K8sHttpClient> = K8sHttpClient.layer.pipe(
|
|
117
135
|
Layer.provide(Layer.unwrap(Effect.gen(function*() {
|
package/src/BunCrypto.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `BunCrypto` module provides Bun's `Crypto` service layer for Effect
|
|
3
|
+
* programs. Provide {@link layer} at the edge of a Bun app, CLI, script, or
|
|
4
|
+
* test to satisfy `effect/Crypto` with cryptographically secure random bytes,
|
|
5
|
+
* UUID generation, random values, and SHA digest operations.
|
|
6
|
+
*
|
|
7
|
+
* This adapter reuses the shared Node-compatible implementation, so randomness
|
|
8
|
+
* and digest behavior follow Bun's `node:crypto` compatibility layer. SHA-1 is
|
|
9
|
+
* present for interoperability with existing protocols, not for new
|
|
10
|
+
* security-sensitive designs.
|
|
11
|
+
*
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
15
|
+
import type * as Crypto from "effect/Crypto"
|
|
16
|
+
import type * as Layer from "effect/Layer"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Layer that provides the Bun Crypto service implementation.
|
|
20
|
+
*
|
|
21
|
+
* @category layers
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export const layer: Layer.Layer<Crypto.Crypto> = NodeCrypto.layer
|
package/src/BunFileSystem.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun layer for Effect's `FileSystem` service.
|
|
3
|
+
*
|
|
4
|
+
* This module exposes one `layer` that provides `FileSystem` in Bun by using
|
|
5
|
+
* the shared Node file-system implementation. Once the layer is provided,
|
|
6
|
+
* programs use the standard `effect/FileSystem` service operations.
|
|
7
|
+
*
|
|
8
|
+
* @since 4.0.0
|
|
3
9
|
*/
|
|
4
10
|
import * as NodeFileSystem from "@effect/platform-node-shared/NodeFileSystem"
|
|
5
11
|
import type { FileSystem } from "effect/FileSystem"
|
|
6
12
|
import type * as Layer from "effect/Layer"
|
|
7
13
|
|
|
8
14
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
15
|
+
* Layer that provides the `FileSystem` service for Bun using the shared Node file-system implementation.
|
|
16
|
+
*
|
|
17
|
+
* @category layers
|
|
18
|
+
* @since 4.0.0
|
|
11
19
|
*/
|
|
12
20
|
export const layer: Layer.Layer<FileSystem, never, never> = NodeFileSystem.layer
|
package/src/BunHttpClient.ts
CHANGED
package/src/BunHttpPlatform.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun implementation of the Effect HTTP platform service.
|
|
3
|
+
*
|
|
4
|
+
* This module provides one `layer` for `HttpPlatform`. It implements file
|
|
5
|
+
* responses with `Bun.file`, supports sliced file responses for byte ranges,
|
|
6
|
+
* and returns Web `File` values as raw HTTP server responses. The layer also
|
|
7
|
+
* provides the Bun file-system layer and ETag generator required by
|
|
8
|
+
* `HttpPlatform`.
|
|
9
|
+
*
|
|
10
|
+
* @since 4.0.0
|
|
3
11
|
*/
|
|
4
12
|
import type { Effect } from "effect"
|
|
5
13
|
import type { FileSystem } from "effect/FileSystem"
|
|
@@ -10,8 +18,8 @@ import * as Response from "effect/unstable/http/HttpServerResponse"
|
|
|
10
18
|
import * as BunFileSystem from "./BunFileSystem.ts"
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
|
-
* @since 1.0.0
|
|
14
21
|
* @category constructors
|
|
22
|
+
* @since 4.0.0
|
|
15
23
|
*/
|
|
16
24
|
const make: Effect.Effect<
|
|
17
25
|
Platform.HttpPlatform["Service"],
|
|
@@ -31,8 +39,10 @@ const make: Effect.Effect<
|
|
|
31
39
|
})
|
|
32
40
|
|
|
33
41
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
42
|
+
* Layer that provides the Bun `HttpPlatform`, including file responses backed by `Bun.file`.
|
|
43
|
+
*
|
|
44
|
+
* @category layers
|
|
45
|
+
* @since 4.0.0
|
|
36
46
|
*/
|
|
37
47
|
export const layer = Layer.effect(Platform.HttpPlatform)(make).pipe(
|
|
38
48
|
Layer.provide(BunFileSystem.layer),
|
package/src/BunHttpServer.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun implementation of the Effect `HttpServer`.
|
|
3
|
+
*
|
|
4
|
+
* `make` creates a scoped HTTP server from `Bun.serve`, converting Bun
|
|
5
|
+
* `Request` values into `HttpServerRequest` values and Effect
|
|
6
|
+
* `HttpServerResponse` values back into Web `Response` values. The server
|
|
7
|
+
* supports streaming bodies, multipart requests, file responses through
|
|
8
|
+
* `BunHttpPlatform`, and WebSocket upgrades. This module also provides layers
|
|
9
|
+
* for the server alone, the Bun HTTP support services, the combined server,
|
|
10
|
+
* configurable server options, and a test server with an HTTP client.
|
|
11
|
+
*
|
|
12
|
+
* @since 4.0.0
|
|
3
13
|
*/
|
|
4
14
|
import type { Server as BunServer, ServerWebSocket } from "bun"
|
|
5
15
|
import * as Config from "effect/Config"
|
|
6
16
|
import type { ConfigError } from "effect/Config"
|
|
17
|
+
import * as Context from "effect/Context"
|
|
7
18
|
import * as Deferred from "effect/Deferred"
|
|
19
|
+
import * as Duration from "effect/Duration"
|
|
8
20
|
import * as Effect from "effect/Effect"
|
|
9
21
|
import * as Exit from "effect/Exit"
|
|
10
22
|
import * as Fiber from "effect/Fiber"
|
|
@@ -13,11 +25,12 @@ import type * as FileSystem from "effect/FileSystem"
|
|
|
13
25
|
import { flow } from "effect/Function"
|
|
14
26
|
import * as Inspectable from "effect/Inspectable"
|
|
15
27
|
import * as Layer from "effect/Layer"
|
|
28
|
+
import * as Option from "effect/Option"
|
|
16
29
|
import type * as Path from "effect/Path"
|
|
17
30
|
import type * as Record from "effect/Record"
|
|
18
|
-
import type * as
|
|
31
|
+
import type * as Schema from "effect/Schema"
|
|
32
|
+
import * as Scope from "effect/Scope"
|
|
19
33
|
import * as Semaphore from "effect/Semaphore"
|
|
20
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
21
34
|
import * as Stream from "effect/Stream"
|
|
22
35
|
import * as Cookies from "effect/unstable/http/Cookies"
|
|
23
36
|
import * as Etag from "effect/unstable/http/Etag"
|
|
@@ -41,8 +54,10 @@ import * as BunServices from "./BunServices.ts"
|
|
|
41
54
|
import * as BunStream from "./BunStream.ts"
|
|
42
55
|
|
|
43
56
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
57
|
+
* Bun serve options accepted by the HTTP server, extended with typed route definitions.
|
|
58
|
+
*
|
|
59
|
+
* @category options
|
|
60
|
+
* @since 4.0.0
|
|
46
61
|
*/
|
|
47
62
|
export type ServeOptions<R extends string> =
|
|
48
63
|
& (
|
|
@@ -52,13 +67,19 @@ export type ServeOptions<R extends string> =
|
|
|
52
67
|
& { readonly routes?: Bun.Serve.Routes<WebSocketContext, R> }
|
|
53
68
|
|
|
54
69
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
70
|
+
* Creates a scoped Bun `HttpServer` from `Bun.serve` options, stopping the server on scope finalization with optional graceful shutdown settings.
|
|
71
|
+
*
|
|
72
|
+
* @category constructors
|
|
73
|
+
* @since 4.0.0
|
|
57
74
|
*/
|
|
58
75
|
export const make = Effect.fnUntraced(
|
|
59
76
|
function*<R extends string>(
|
|
60
|
-
options: ServeOptions<R>
|
|
77
|
+
options: ServeOptions<R> & {
|
|
78
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
79
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
80
|
+
}
|
|
61
81
|
) {
|
|
82
|
+
const scope = yield* Effect.scope
|
|
62
83
|
const handlerStack: Array<(request: Request, server: BunServer<WebSocketContext>) => Response | Promise<Response>> =
|
|
63
84
|
[
|
|
64
85
|
function(_request, _server) {
|
|
@@ -76,6 +97,7 @@ export const make = Effect.fnUntraced(
|
|
|
76
97
|
ws.data.run(message)
|
|
77
98
|
},
|
|
78
99
|
close(ws, code, closeReason) {
|
|
100
|
+
code = typeof code === "number" ? code : 1001
|
|
79
101
|
Deferred.doneUnsafe(
|
|
80
102
|
ws.data.closeDeferred,
|
|
81
103
|
Socket.defaultCloseCodeIsError(code)
|
|
@@ -90,13 +112,24 @@ export const make = Effect.fnUntraced(
|
|
|
90
112
|
}
|
|
91
113
|
})
|
|
92
114
|
|
|
93
|
-
yield* Effect.
|
|
115
|
+
const shutdown = yield* Effect.promise(() => server.stop()).pipe(
|
|
116
|
+
Effect.cached
|
|
117
|
+
)
|
|
118
|
+
const preemptiveShutdown = options.disablePreemptiveShutdown ? Effect.void : Effect.timeoutOrElse(shutdown, {
|
|
119
|
+
duration: options.gracefulShutdownTimeout ?? Duration.seconds(20),
|
|
120
|
+
orElse: () => Effect.void
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
yield* Scope.addFinalizer(scope, shutdown)
|
|
94
124
|
|
|
95
125
|
return Server.make({
|
|
96
126
|
address: { _tag: "TcpAddress", port: server.port!, hostname: server.hostname! },
|
|
97
127
|
serve: Effect.fnUntraced(function*(httpApp, middleware) {
|
|
98
|
-
const
|
|
99
|
-
const services =
|
|
128
|
+
const parent = yield* Effect.fiber
|
|
129
|
+
const services = parent.context
|
|
130
|
+
const serveScope = Context.getUnsafe(services, Scope.Scope)
|
|
131
|
+
const scope = Scope.forkUnsafe(serveScope, "parallel")
|
|
132
|
+
|
|
100
133
|
const httpEffect = HttpEffect.toHandled(httpApp, (request, response) =>
|
|
101
134
|
Effect.sync(() => {
|
|
102
135
|
;(request as BunServerRequest).resolve(makeResponse(request, response, services, scope))
|
|
@@ -109,24 +142,20 @@ export const make = Effect.fnUntraced(
|
|
|
109
142
|
ServerRequest.HttpServerRequest.key,
|
|
110
143
|
new BunServerRequest(request, resolve, removeHost(request.url), server)
|
|
111
144
|
)
|
|
112
|
-
const fiber = Fiber.runIn(Effect.runForkWith(
|
|
145
|
+
const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(httpEffect), scope)
|
|
113
146
|
request.signal.addEventListener("abort", () => {
|
|
114
|
-
fiber.interruptUnsafe(Error.
|
|
147
|
+
fiber.interruptUnsafe(parent.id, Error.ClientAbort.annotation)
|
|
115
148
|
}, { once: true })
|
|
116
149
|
})
|
|
117
150
|
}
|
|
118
151
|
|
|
119
|
-
yield*
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
handlerStack.pop()
|
|
127
|
-
server.reload({ fetch: handlerStack[handlerStack.length - 1] })
|
|
128
|
-
})
|
|
129
|
-
)
|
|
152
|
+
yield* Scope.addFinalizerExit(serveScope, () => {
|
|
153
|
+
handlerStack.pop()
|
|
154
|
+
server.reload({ fetch: handlerStack[handlerStack.length - 1] })
|
|
155
|
+
return preemptiveShutdown
|
|
156
|
+
})
|
|
157
|
+
handlerStack.push(handler)
|
|
158
|
+
server.reload({ fetch: handler })
|
|
130
159
|
})
|
|
131
160
|
})
|
|
132
161
|
}
|
|
@@ -135,7 +164,7 @@ export const make = Effect.fnUntraced(
|
|
|
135
164
|
const makeResponse = (
|
|
136
165
|
request: ServerRequest.HttpServerRequest,
|
|
137
166
|
response: ServerResponse.HttpServerResponse,
|
|
138
|
-
|
|
167
|
+
context: Context.Context<never>,
|
|
139
168
|
scope: Scope.Scope
|
|
140
169
|
): Response => {
|
|
141
170
|
const fields: {
|
|
@@ -186,7 +215,7 @@ const makeResponse = (
|
|
|
186
215
|
Fiber.runIn(fiber, scope)
|
|
187
216
|
return Effect.succeed(body.stream)
|
|
188
217
|
})),
|
|
189
|
-
|
|
218
|
+
context
|
|
190
219
|
),
|
|
191
220
|
fields
|
|
192
221
|
)
|
|
@@ -195,16 +224,23 @@ const makeResponse = (
|
|
|
195
224
|
}
|
|
196
225
|
|
|
197
226
|
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
227
|
+
* Layer that provides only `HttpServer` by constructing a scoped Bun server from the supplied serve options.
|
|
228
|
+
*
|
|
229
|
+
* @category layers
|
|
230
|
+
* @since 4.0.0
|
|
200
231
|
*/
|
|
201
232
|
export const layerServer: <R extends string>(
|
|
202
|
-
options: ServeOptions<R>
|
|
233
|
+
options: ServeOptions<R> & {
|
|
234
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
235
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
236
|
+
}
|
|
203
237
|
) => Layer.Layer<Server.HttpServer> = flow(make, Layer.effect(Server.HttpServer)) as any
|
|
204
238
|
|
|
205
239
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
240
|
+
* Layer that provides Bun HTTP support services: `HttpPlatform`, weak ETag generation, and `BunServices`.
|
|
241
|
+
*
|
|
242
|
+
* @category layers
|
|
243
|
+
* @since 4.0.0
|
|
208
244
|
*/
|
|
209
245
|
export const layerHttpServices: Layer.Layer<
|
|
210
246
|
| HttpPlatform
|
|
@@ -217,11 +253,16 @@ export const layerHttpServices: Layer.Layer<
|
|
|
217
253
|
)
|
|
218
254
|
|
|
219
255
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
256
|
+
* Layer that provides a Bun `HttpServer` together with the Bun HTTP platform, ETag generator, and Bun services.
|
|
257
|
+
*
|
|
258
|
+
* @category layers
|
|
259
|
+
* @since 4.0.0
|
|
222
260
|
*/
|
|
223
261
|
export const layer = <R extends string>(
|
|
224
|
-
options: ServeOptions<R>
|
|
262
|
+
options: ServeOptions<R> & {
|
|
263
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
264
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
265
|
+
}
|
|
225
266
|
): Layer.Layer<
|
|
226
267
|
| Server.HttpServer
|
|
227
268
|
| HttpPlatform
|
|
@@ -230,8 +271,10 @@ export const layer = <R extends string>(
|
|
|
230
271
|
> => Layer.mergeAll(layerServer(options), layerHttpServices)
|
|
231
272
|
|
|
232
273
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
274
|
+
* Layer that starts a Bun HTTP server on an ephemeral port for tests.
|
|
275
|
+
*
|
|
276
|
+
* @category layers
|
|
277
|
+
* @since 4.0.0
|
|
235
278
|
*/
|
|
236
279
|
export const layerTest: Layer.Layer<
|
|
237
280
|
Server.HttpServer | HttpPlatform | FileSystem.FileSystem | Etag.Generator | Path.Path | HttpClient
|
|
@@ -243,17 +286,24 @@ export const layerTest: Layer.Layer<
|
|
|
243
286
|
)
|
|
244
287
|
|
|
245
288
|
/**
|
|
246
|
-
*
|
|
247
|
-
*
|
|
289
|
+
* Creates the Bun HTTP server and support-services layer from configurable serve options.
|
|
290
|
+
*
|
|
291
|
+
* @category layers
|
|
292
|
+
* @since 4.0.0
|
|
248
293
|
*/
|
|
249
294
|
export const layerConfig = <R extends string>(
|
|
250
|
-
options: Config.Wrap<
|
|
295
|
+
options: Config.Wrap<
|
|
296
|
+
ServeOptions<R> & {
|
|
297
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
298
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
299
|
+
}
|
|
300
|
+
>
|
|
251
301
|
): Layer.Layer<
|
|
252
302
|
Server.HttpServer | HttpPlatform | FileSystem.FileSystem | Etag.Generator | Path.Path,
|
|
253
303
|
ConfigError
|
|
254
304
|
> =>
|
|
255
305
|
Layer.mergeAll(
|
|
256
|
-
Layer.effect(Server.HttpServer)(Effect.flatMap(Config.unwrap(options)
|
|
306
|
+
Layer.effect(Server.HttpServer)(Effect.flatMap(Config.unwrap(options), make)),
|
|
257
307
|
layerHttpServices
|
|
258
308
|
)
|
|
259
309
|
|
|
@@ -280,7 +330,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
280
330
|
readonly url: string
|
|
281
331
|
private bunServer: BunServer<WebSocketContext>
|
|
282
332
|
public headersOverride?: Headers.Headers | undefined
|
|
283
|
-
private remoteAddressOverride?: string | undefined
|
|
333
|
+
private remoteAddressOverride?: Option.Option<string> | undefined
|
|
284
334
|
|
|
285
335
|
constructor(
|
|
286
336
|
source: Request,
|
|
@@ -288,7 +338,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
288
338
|
url: string,
|
|
289
339
|
bunServer: BunServer<WebSocketContext>,
|
|
290
340
|
headersOverride?: Headers.Headers,
|
|
291
|
-
remoteAddressOverride?: string
|
|
341
|
+
remoteAddressOverride?: Option.Option<string>
|
|
292
342
|
) {
|
|
293
343
|
super()
|
|
294
344
|
this[ServerRequest.TypeId] = ServerRequest.TypeId
|
|
@@ -311,7 +361,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
311
361
|
options: {
|
|
312
362
|
readonly url?: string | undefined
|
|
313
363
|
readonly headers?: Headers.Headers | undefined
|
|
314
|
-
readonly remoteAddress?: string | undefined
|
|
364
|
+
readonly remoteAddress?: Option.Option<string> | undefined
|
|
315
365
|
}
|
|
316
366
|
) {
|
|
317
367
|
return new BunServerRequest(
|
|
@@ -320,7 +370,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
320
370
|
options.url ?? this.url,
|
|
321
371
|
this.bunServer,
|
|
322
372
|
options.headers ?? this.headersOverride,
|
|
323
|
-
options.remoteAddress
|
|
373
|
+
"remoteAddress" in options ? options.remoteAddress : this.remoteAddressOverride
|
|
324
374
|
)
|
|
325
375
|
}
|
|
326
376
|
get method(): HttpMethod {
|
|
@@ -329,8 +379,8 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
329
379
|
get originalUrl() {
|
|
330
380
|
return this.source.url
|
|
331
381
|
}
|
|
332
|
-
get remoteAddress(): string
|
|
333
|
-
return this.remoteAddressOverride ?? this.bunServer.requestIP(this.source)?.address
|
|
382
|
+
get remoteAddress(): Option.Option<string> {
|
|
383
|
+
return this.remoteAddressOverride ?? Option.fromNullishOr(this.bunServer.requestIP(this.source)?.address)
|
|
334
384
|
}
|
|
335
385
|
get headers(): Headers.Headers {
|
|
336
386
|
this.headersOverride ??= Headers.fromInput(this.source.headers)
|
|
@@ -348,7 +398,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
348
398
|
get stream(): Stream.Stream<Uint8Array, Error.HttpServerError> {
|
|
349
399
|
return this.source.body
|
|
350
400
|
? BunStream.fromReadableStream({
|
|
351
|
-
evaluate: () => this.source.body
|
|
401
|
+
evaluate: () => this.source.body ?? emptyReadbleStream,
|
|
352
402
|
onError: (cause) =>
|
|
353
403
|
new Error.HttpServerError({
|
|
354
404
|
reason: new Error.RequestParseError({
|
|
@@ -387,10 +437,10 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
387
437
|
return this.textEffect
|
|
388
438
|
}
|
|
389
439
|
|
|
390
|
-
get json(): Effect.Effect<
|
|
440
|
+
get json(): Effect.Effect<Schema.Json, Error.HttpServerError> {
|
|
391
441
|
return Effect.flatMap(this.text, (_) =>
|
|
392
442
|
Effect.try({
|
|
393
|
-
try: () => JSON.parse(_) as
|
|
443
|
+
try: () => JSON.parse(_) as Schema.Json,
|
|
394
444
|
catch: (cause) =>
|
|
395
445
|
new Error.HttpServerError({
|
|
396
446
|
reason: new Error.RequestParseError({
|
|
@@ -457,6 +507,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
457
507
|
})
|
|
458
508
|
})
|
|
459
509
|
))
|
|
510
|
+
this.textEffect = Effect.map(this.arrayBufferEffect, (_) => new TextDecoder().decode(_))
|
|
460
511
|
return this.arrayBufferEffect
|
|
461
512
|
}
|
|
462
513
|
|
|
@@ -524,14 +575,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
524
575
|
semaphore.withPermits(1)
|
|
525
576
|
)
|
|
526
577
|
|
|
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,
|
|
578
|
+
return Socket.make({
|
|
535
579
|
runRaw,
|
|
536
580
|
writer
|
|
537
581
|
})
|
|
@@ -540,6 +584,13 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
540
584
|
}
|
|
541
585
|
}
|
|
542
586
|
|
|
587
|
+
const emptyReadbleStream = new ReadableStream({
|
|
588
|
+
start(controller) {
|
|
589
|
+
controller.enqueue(new Uint8Array())
|
|
590
|
+
controller.close()
|
|
591
|
+
}
|
|
592
|
+
})
|
|
593
|
+
|
|
543
594
|
const removeHost = (url: string) => {
|
|
544
595
|
if (url[0] === "/") {
|
|
545
596
|
return url
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Accessor for the Bun request behind an Effect HTTP server request.
|
|
3
|
+
*
|
|
4
|
+
* This module exports `toBunServerRequest`, which returns the underlying
|
|
5
|
+
* `Bun.BunRequest` stored inside a Bun-backed `HttpServerRequest`. It is meant
|
|
6
|
+
* for code that needs to interoperate with Bun-specific request APIs.
|
|
7
|
+
*
|
|
8
|
+
* @since 4.0.0
|
|
3
9
|
*/
|
|
4
10
|
import type { HttpServerRequest } from "effect/unstable/http/HttpServerRequest"
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
13
|
+
* Returns the underlying `Bun.BunRequest` from an Effect `HttpServerRequest`.
|
|
14
|
+
*
|
|
15
|
+
* @category accessors
|
|
16
|
+
* @since 4.0.0
|
|
9
17
|
*/
|
|
10
18
|
export const toBunServerRequest = <T extends string = string>(self: HttpServerRequest): Bun.BunRequest<T> =>
|
|
11
19
|
(self as any).source
|
package/src/BunMultipart.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bun-specific helpers for parsing HTTP `multipart/form-data` request bodies.
|
|
3
|
+
*
|
|
4
|
+
* This module adapts a Bun `Request` body and headers into the shared
|
|
5
|
+
* `Multipart` model. `stream` returns multipart parts as a `Stream`, while
|
|
6
|
+
* `persisted` collects the form and writes file parts to scoped temporary files
|
|
7
|
+
* through the current `FileSystem`, `Path`, and `Scope` services.
|
|
8
|
+
*
|
|
9
|
+
* @since 4.0.0
|
|
3
10
|
*/
|
|
4
11
|
import type * as Effect from "effect/Effect"
|
|
5
12
|
import type { FileSystem } from "effect/FileSystem"
|
|
@@ -10,20 +17,31 @@ import * as Multipart from "effect/unstable/http/Multipart"
|
|
|
10
17
|
import * as BunStream from "./BunStream.ts"
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
20
|
+
* Parses a Bun `Request` body as multipart data and returns a stream of multipart parts.
|
|
21
|
+
*
|
|
22
|
+
* @category constructors
|
|
23
|
+
* @since 4.0.0
|
|
15
24
|
*/
|
|
16
25
|
export const stream = (source: Request): Stream.Stream<Multipart.Part, Multipart.MultipartError> =>
|
|
17
26
|
BunStream.fromReadableStream({
|
|
18
|
-
evaluate: () => source.body
|
|
27
|
+
evaluate: () => source.body ?? emptyReadbleStream,
|
|
19
28
|
onError: (cause) => Multipart.MultipartError.fromReason("InternalError", cause)
|
|
20
29
|
}).pipe(
|
|
21
30
|
Stream.pipeThroughChannel(Multipart.makeChannel(Object.fromEntries(source.headers)))
|
|
22
31
|
)
|
|
23
32
|
|
|
33
|
+
const emptyReadbleStream = new ReadableStream({
|
|
34
|
+
start(controller) {
|
|
35
|
+
controller.enqueue(new Uint8Array())
|
|
36
|
+
controller.close()
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
24
40
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
41
|
+
* Parses and persists multipart data from a Bun `Request`, requiring file-system, path, and scope services.
|
|
42
|
+
*
|
|
43
|
+
* @category constructors
|
|
44
|
+
* @since 4.0.0
|
|
27
45
|
*/
|
|
28
46
|
export const persisted = (
|
|
29
47
|
source: Request
|