@effect/platform-bun 4.0.0-beta.1 → 4.0.0-beta.100
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/README.md +1 -1
- package/dist/BunChildProcessSpawner.d.ts +2 -2
- package/dist/BunChildProcessSpawner.js +2 -2
- 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 +58 -21
- package/dist/BunHttpServer.d.ts.map +1 -1
- package/dist/BunHttpServer.js +65 -37
- 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 +19 -5
- 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 +28 -20
- 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 +7 -8
- package/src/BunChildProcessSpawner.ts +2 -2
- 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 +110 -58
- 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 +19 -5
- package/src/BunSocketServer.ts +2 -2
- package/src/BunStdio.ts +13 -3
- package/src/BunStream.ts +31 -23
- 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/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect/platform-bun",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0.0-beta.
|
|
4
|
+
"version": "4.0.0-beta.100",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Platform specific implementations for the Bun runtime",
|
|
7
7
|
"homepage": "https://effect.website",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/Effect-TS/effect
|
|
10
|
+
"url": "https://github.com/Effect-TS/effect.git",
|
|
11
11
|
"directory": "packages/platform-bun"
|
|
12
12
|
},
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/Effect-TS/effect
|
|
14
|
+
"url": "https://github.com/Effect-TS/effect/issues"
|
|
15
15
|
},
|
|
16
16
|
"tags": [
|
|
17
17
|
"bun",
|
|
@@ -45,19 +45,18 @@
|
|
|
45
45
|
"provenance": true
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"effect": "^4.0.0-beta.
|
|
48
|
+
"effect": "^4.0.0-beta.100"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@effect/platform-node-shared": "^4.0.0-beta.
|
|
51
|
+
"@effect/platform-node-shared": "^4.0.0-beta.100"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@types/bun": "^1.3.
|
|
55
|
-
"effect": "^4.0.0-beta.
|
|
54
|
+
"@types/bun": "^1.3.14",
|
|
55
|
+
"effect": "^4.0.0-beta.100"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"codegen": "effect-utils codegen",
|
|
59
59
|
"build": "tsc -b tsconfig.json && pnpm babel",
|
|
60
|
-
"build:tsgo": "tsgo -b tsconfig.json && pnpm babel",
|
|
61
60
|
"babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps",
|
|
62
61
|
"check": "tsc -b tsconfig.json",
|
|
63
62
|
"test": "vitest",
|
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,10 +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
|
|
19
|
-
import * as
|
|
31
|
+
import type * as Schema from "effect/Schema"
|
|
32
|
+
import * as Scope from "effect/Scope"
|
|
33
|
+
import * as Semaphore from "effect/Semaphore"
|
|
20
34
|
import * as Stream from "effect/Stream"
|
|
21
35
|
import * as Cookies from "effect/unstable/http/Cookies"
|
|
22
36
|
import * as Etag from "effect/unstable/http/Etag"
|
|
@@ -40,8 +54,10 @@ import * as BunServices from "./BunServices.ts"
|
|
|
40
54
|
import * as BunStream from "./BunStream.ts"
|
|
41
55
|
|
|
42
56
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
57
|
+
* Bun serve options accepted by the HTTP server, extended with typed route definitions.
|
|
58
|
+
*
|
|
59
|
+
* @category options
|
|
60
|
+
* @since 4.0.0
|
|
45
61
|
*/
|
|
46
62
|
export type ServeOptions<R extends string> =
|
|
47
63
|
& (
|
|
@@ -51,13 +67,19 @@ export type ServeOptions<R extends string> =
|
|
|
51
67
|
& { readonly routes?: Bun.Serve.Routes<WebSocketContext, R> }
|
|
52
68
|
|
|
53
69
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
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
|
|
56
74
|
*/
|
|
57
75
|
export const make = Effect.fnUntraced(
|
|
58
76
|
function*<R extends string>(
|
|
59
|
-
options: ServeOptions<R>
|
|
77
|
+
options: ServeOptions<R> & {
|
|
78
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
79
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
80
|
+
}
|
|
60
81
|
) {
|
|
82
|
+
const scope = yield* Effect.scope
|
|
61
83
|
const handlerStack: Array<(request: Request, server: BunServer<WebSocketContext>) => Response | Promise<Response>> =
|
|
62
84
|
[
|
|
63
85
|
function(_request, _server) {
|
|
@@ -75,6 +97,7 @@ export const make = Effect.fnUntraced(
|
|
|
75
97
|
ws.data.run(message)
|
|
76
98
|
},
|
|
77
99
|
close(ws, code, closeReason) {
|
|
100
|
+
code = typeof code === "number" ? code : 1001
|
|
78
101
|
Deferred.doneUnsafe(
|
|
79
102
|
ws.data.closeDeferred,
|
|
80
103
|
Socket.defaultCloseCodeIsError(code)
|
|
@@ -89,13 +112,24 @@ export const make = Effect.fnUntraced(
|
|
|
89
112
|
}
|
|
90
113
|
})
|
|
91
114
|
|
|
92
|
-
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)
|
|
93
124
|
|
|
94
125
|
return Server.make({
|
|
95
126
|
address: { _tag: "TcpAddress", port: server.port!, hostname: server.hostname! },
|
|
96
127
|
serve: Effect.fnUntraced(function*(httpApp, middleware) {
|
|
97
|
-
const
|
|
98
|
-
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
|
+
|
|
99
133
|
const httpEffect = HttpEffect.toHandled(httpApp, (request, response) =>
|
|
100
134
|
Effect.sync(() => {
|
|
101
135
|
;(request as BunServerRequest).resolve(makeResponse(request, response, services, scope))
|
|
@@ -108,24 +142,20 @@ export const make = Effect.fnUntraced(
|
|
|
108
142
|
ServerRequest.HttpServerRequest.key,
|
|
109
143
|
new BunServerRequest(request, resolve, removeHost(request.url), server)
|
|
110
144
|
)
|
|
111
|
-
const fiber = Fiber.runIn(Effect.runForkWith(
|
|
145
|
+
const fiber = Fiber.runIn(Effect.runForkWith(Context.makeUnsafe<any>(map))(httpEffect), scope)
|
|
112
146
|
request.signal.addEventListener("abort", () => {
|
|
113
|
-
fiber.interruptUnsafe(Error.
|
|
147
|
+
fiber.interruptUnsafe(parent.id, Error.ClientAbort.annotation)
|
|
114
148
|
}, { once: true })
|
|
115
149
|
})
|
|
116
150
|
}
|
|
117
151
|
|
|
118
|
-
yield*
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
handlerStack.pop()
|
|
126
|
-
server.reload({ fetch: handlerStack[handlerStack.length - 1] })
|
|
127
|
-
})
|
|
128
|
-
)
|
|
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 })
|
|
129
159
|
})
|
|
130
160
|
})
|
|
131
161
|
}
|
|
@@ -134,7 +164,7 @@ export const make = Effect.fnUntraced(
|
|
|
134
164
|
const makeResponse = (
|
|
135
165
|
request: ServerRequest.HttpServerRequest,
|
|
136
166
|
response: ServerResponse.HttpServerResponse,
|
|
137
|
-
|
|
167
|
+
context: Context.Context<never>,
|
|
138
168
|
scope: Scope.Scope
|
|
139
169
|
): Response => {
|
|
140
170
|
const fields: {
|
|
@@ -185,7 +215,7 @@ const makeResponse = (
|
|
|
185
215
|
Fiber.runIn(fiber, scope)
|
|
186
216
|
return Effect.succeed(body.stream)
|
|
187
217
|
})),
|
|
188
|
-
|
|
218
|
+
context
|
|
189
219
|
),
|
|
190
220
|
fields
|
|
191
221
|
)
|
|
@@ -194,16 +224,23 @@ const makeResponse = (
|
|
|
194
224
|
}
|
|
195
225
|
|
|
196
226
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
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
|
|
199
231
|
*/
|
|
200
232
|
export const layerServer: <R extends string>(
|
|
201
|
-
options: ServeOptions<R>
|
|
233
|
+
options: ServeOptions<R> & {
|
|
234
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
235
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
236
|
+
}
|
|
202
237
|
) => Layer.Layer<Server.HttpServer> = flow(make, Layer.effect(Server.HttpServer)) as any
|
|
203
238
|
|
|
204
239
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
240
|
+
* Layer that provides Bun HTTP support services: `HttpPlatform`, weak ETag generation, and `BunServices`.
|
|
241
|
+
*
|
|
242
|
+
* @category layers
|
|
243
|
+
* @since 4.0.0
|
|
207
244
|
*/
|
|
208
245
|
export const layerHttpServices: Layer.Layer<
|
|
209
246
|
| HttpPlatform
|
|
@@ -216,11 +253,16 @@ export const layerHttpServices: Layer.Layer<
|
|
|
216
253
|
)
|
|
217
254
|
|
|
218
255
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
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
|
|
221
260
|
*/
|
|
222
261
|
export const layer = <R extends string>(
|
|
223
|
-
options: ServeOptions<R>
|
|
262
|
+
options: ServeOptions<R> & {
|
|
263
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
264
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
265
|
+
}
|
|
224
266
|
): Layer.Layer<
|
|
225
267
|
| Server.HttpServer
|
|
226
268
|
| HttpPlatform
|
|
@@ -229,8 +271,10 @@ export const layer = <R extends string>(
|
|
|
229
271
|
> => Layer.mergeAll(layerServer(options), layerHttpServices)
|
|
230
272
|
|
|
231
273
|
/**
|
|
232
|
-
*
|
|
233
|
-
*
|
|
274
|
+
* Layer that starts a Bun HTTP server on an ephemeral port for tests.
|
|
275
|
+
*
|
|
276
|
+
* @category layers
|
|
277
|
+
* @since 4.0.0
|
|
234
278
|
*/
|
|
235
279
|
export const layerTest: Layer.Layer<
|
|
236
280
|
Server.HttpServer | HttpPlatform | FileSystem.FileSystem | Etag.Generator | Path.Path | HttpClient
|
|
@@ -242,17 +286,24 @@ export const layerTest: Layer.Layer<
|
|
|
242
286
|
)
|
|
243
287
|
|
|
244
288
|
/**
|
|
245
|
-
*
|
|
246
|
-
*
|
|
289
|
+
* Creates the Bun HTTP server and support-services layer from configurable serve options.
|
|
290
|
+
*
|
|
291
|
+
* @category layers
|
|
292
|
+
* @since 4.0.0
|
|
247
293
|
*/
|
|
248
294
|
export const layerConfig = <R extends string>(
|
|
249
|
-
options: Config.Wrap<
|
|
295
|
+
options: Config.Wrap<
|
|
296
|
+
ServeOptions<R> & {
|
|
297
|
+
readonly disablePreemptiveShutdown?: boolean | undefined
|
|
298
|
+
readonly gracefulShutdownTimeout?: Duration.Input | undefined
|
|
299
|
+
}
|
|
300
|
+
>
|
|
250
301
|
): Layer.Layer<
|
|
251
302
|
Server.HttpServer | HttpPlatform | FileSystem.FileSystem | Etag.Generator | Path.Path,
|
|
252
303
|
ConfigError
|
|
253
304
|
> =>
|
|
254
305
|
Layer.mergeAll(
|
|
255
|
-
Layer.effect(Server.HttpServer)(Effect.flatMap(Config.unwrap(options)
|
|
306
|
+
Layer.effect(Server.HttpServer)(Effect.flatMap(Config.unwrap(options), make)),
|
|
256
307
|
layerHttpServices
|
|
257
308
|
)
|
|
258
309
|
|
|
@@ -279,7 +330,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
279
330
|
readonly url: string
|
|
280
331
|
private bunServer: BunServer<WebSocketContext>
|
|
281
332
|
public headersOverride?: Headers.Headers | undefined
|
|
282
|
-
private remoteAddressOverride?: string | undefined
|
|
333
|
+
private remoteAddressOverride?: Option.Option<string> | undefined
|
|
283
334
|
|
|
284
335
|
constructor(
|
|
285
336
|
source: Request,
|
|
@@ -287,7 +338,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
287
338
|
url: string,
|
|
288
339
|
bunServer: BunServer<WebSocketContext>,
|
|
289
340
|
headersOverride?: Headers.Headers,
|
|
290
|
-
remoteAddressOverride?: string
|
|
341
|
+
remoteAddressOverride?: Option.Option<string>
|
|
291
342
|
) {
|
|
292
343
|
super()
|
|
293
344
|
this[ServerRequest.TypeId] = ServerRequest.TypeId
|
|
@@ -310,7 +361,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
310
361
|
options: {
|
|
311
362
|
readonly url?: string | undefined
|
|
312
363
|
readonly headers?: Headers.Headers | undefined
|
|
313
|
-
readonly remoteAddress?: string | undefined
|
|
364
|
+
readonly remoteAddress?: Option.Option<string> | undefined
|
|
314
365
|
}
|
|
315
366
|
) {
|
|
316
367
|
return new BunServerRequest(
|
|
@@ -319,7 +370,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
319
370
|
options.url ?? this.url,
|
|
320
371
|
this.bunServer,
|
|
321
372
|
options.headers ?? this.headersOverride,
|
|
322
|
-
options.remoteAddress
|
|
373
|
+
"remoteAddress" in options ? options.remoteAddress : this.remoteAddressOverride
|
|
323
374
|
)
|
|
324
375
|
}
|
|
325
376
|
get method(): HttpMethod {
|
|
@@ -328,8 +379,8 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
328
379
|
get originalUrl() {
|
|
329
380
|
return this.source.url
|
|
330
381
|
}
|
|
331
|
-
get remoteAddress(): string
|
|
332
|
-
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)
|
|
333
384
|
}
|
|
334
385
|
get headers(): Headers.Headers {
|
|
335
386
|
this.headersOverride ??= Headers.fromInput(this.source.headers)
|
|
@@ -347,7 +398,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
347
398
|
get stream(): Stream.Stream<Uint8Array, Error.HttpServerError> {
|
|
348
399
|
return this.source.body
|
|
349
400
|
? BunStream.fromReadableStream({
|
|
350
|
-
evaluate: () => this.source.body
|
|
401
|
+
evaluate: () => this.source.body ?? emptyReadbleStream,
|
|
351
402
|
onError: (cause) =>
|
|
352
403
|
new Error.HttpServerError({
|
|
353
404
|
reason: new Error.RequestParseError({
|
|
@@ -386,10 +437,10 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
386
437
|
return this.textEffect
|
|
387
438
|
}
|
|
388
439
|
|
|
389
|
-
get json(): Effect.Effect<
|
|
440
|
+
get json(): Effect.Effect<Schema.Json, Error.HttpServerError> {
|
|
390
441
|
return Effect.flatMap(this.text, (_) =>
|
|
391
442
|
Effect.try({
|
|
392
|
-
try: () => JSON.parse(_) as
|
|
443
|
+
try: () => JSON.parse(_) as Schema.Json,
|
|
393
444
|
catch: (cause) =>
|
|
394
445
|
new Error.HttpServerError({
|
|
395
446
|
reason: new Error.RequestParseError({
|
|
@@ -456,6 +507,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
456
507
|
})
|
|
457
508
|
})
|
|
458
509
|
))
|
|
510
|
+
this.textEffect = Effect.map(this.arrayBufferEffect, (_) => new TextDecoder().decode(_))
|
|
459
511
|
return this.arrayBufferEffect
|
|
460
512
|
}
|
|
461
513
|
|
|
@@ -463,7 +515,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
463
515
|
return Effect.callback<Socket.Socket, Error.HttpServerError>((resume) => {
|
|
464
516
|
const deferred = Deferred.makeUnsafe<ServerWebSocket<WebSocketContext>>()
|
|
465
517
|
const closeDeferred = Deferred.makeUnsafe<void, Socket.SocketError>()
|
|
466
|
-
const semaphore =
|
|
518
|
+
const semaphore = Semaphore.makeUnsafe(1)
|
|
467
519
|
|
|
468
520
|
const success = this.bunServer.upgrade(this.source, {
|
|
469
521
|
data: {
|
|
@@ -523,14 +575,7 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
523
575
|
semaphore.withPermits(1)
|
|
524
576
|
)
|
|
525
577
|
|
|
526
|
-
|
|
527
|
-
const run = <R, E, _>(handler: (_: Uint8Array) => Effect.Effect<_, E, R> | void, opts?: {
|
|
528
|
-
readonly onOpen?: Effect.Effect<void> | undefined
|
|
529
|
-
}) => runRaw((data) => typeof data === "string" ? handler(encoder.encode(data)) : handler(data), opts)
|
|
530
|
-
|
|
531
|
-
return Socket.Socket.of({
|
|
532
|
-
[Socket.TypeId]: Socket.TypeId as typeof Socket.TypeId,
|
|
533
|
-
run,
|
|
578
|
+
return Socket.make({
|
|
534
579
|
runRaw,
|
|
535
580
|
writer
|
|
536
581
|
})
|
|
@@ -539,6 +584,13 @@ class BunServerRequest extends Inspectable.Class implements ServerRequest.HttpSe
|
|
|
539
584
|
}
|
|
540
585
|
}
|
|
541
586
|
|
|
587
|
+
const emptyReadbleStream = new ReadableStream({
|
|
588
|
+
start(controller) {
|
|
589
|
+
controller.enqueue(new Uint8Array())
|
|
590
|
+
controller.close()
|
|
591
|
+
}
|
|
592
|
+
})
|
|
593
|
+
|
|
542
594
|
const removeHost = (url: string) => {
|
|
543
595
|
if (url[0] === "/") {
|
|
544
596
|
return url
|