1/**
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
11 */
12import * as NodeHttpCompression from "@effect/platform-node-shared/NodeHttpCompression"
13import type * as Effect from "effect/Effect"
14import type { FileSystem } from "effect/FileSystem"
15import * as Etag from "effect/http/Etag"
16import * as Platform from "effect/http/HttpPlatform"
17import * as Response from "effect/http/HttpServerResponse"
18import * as Layer from "effect/Layer"
19import * as BunFileSystem from "./BunFileSystem.ts"
20
21// Bun's CompressionStream supports an extended format set covering brotli and
22// zstd
23const compression = NodeHttpCompression.make(Platform.makeCompressionWeb({
24 algorithms: ["gzip", "deflate", "br", "zstd"],
25 transform: (algorithm) => Platform.compressionTransformWeb(algorithm === "br" ? "brotli" : algorithm)
26}))
27
28/**
29 * @category constructors
30 * @since 4.0.0
31 */
32const make: Effect.Effect<
33 Platform.HttpPlatform["Service"],
34 never,
35 FileSystem | Etag.Generator
36> = Platform.make({
37 platform: "bun",
38 compression,
39 fileResponse(path, status, statusText, headers, start, end, contentLength) {
40 let file = Bun.file(path)
41 if (start > 0 || end !== undefined) {
42 file = file.slice(start, end)
43 }
44 return Response.raw(file, {
45 headers: { ...headers, "content-length": contentLength.toString() },
46 status,
47 statusText
48 })
49 },
50 fileWebResponse(file, status, statusText, headers, options) {
51 const start = options?.offset ?? 0
52 const end = options?.bytesToRead !== undefined ? start + options.bytesToRead : undefined
53 const body = start > 0 || end !== undefined
54 ? (file as File).slice(start, end, file.type)
55 : file
56 return Response.raw(body, { headers, status, statusText })
57 }
58})
59
60/**
61 * Layer that provides the Bun `HttpPlatform`, including file responses backed by `Bun.file`.
62 *
63 * @category layers
64 * @since 4.0.0
65 */
66export const layer = Layer.effect(Platform.HttpPlatform)(make).pipe(
67 Layer.provide(BunFileSystem.layer),
68 Layer.provide(Etag.layer)
69)