@effect/platform-node 0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49

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.
Files changed (181) hide show
  1. package/Http/Platform/package.json +6 -0
  2. package/Http/Server/package.json +6 -0
  3. package/Http/ServerRequest/package.json +6 -0
  4. package/LICENSE +21 -0
  5. package/NodeCommandExecutor/package.json +6 -0
  6. package/NodeContext/package.json +6 -0
  7. package/NodeFileSystem/package.json +6 -0
  8. package/NodeHttpClient/package.json +6 -0
  9. package/NodeHttpServer/package.json +6 -0
  10. package/NodeKeyValueStore/package.json +6 -0
  11. package/NodePath/package.json +6 -0
  12. package/NodeRuntime/package.json +6 -0
  13. package/NodeSink/package.json +6 -0
  14. package/NodeStream/package.json +6 -0
  15. package/NodeTerminal/package.json +6 -0
  16. package/NodeWorker/package.json +6 -0
  17. package/NodeWorkerRunner/package.json +6 -0
  18. package/README.md +64 -0
  19. package/dist/cjs/Http/Platform.js +43 -0
  20. package/dist/cjs/Http/Platform.js.map +1 -0
  21. package/dist/cjs/Http/Server.js +58 -0
  22. package/dist/cjs/Http/Server.js.map +1 -0
  23. package/dist/cjs/Http/ServerRequest.js +38 -0
  24. package/dist/cjs/Http/ServerRequest.js.map +1 -0
  25. package/dist/cjs/NodeCommandExecutor.js +42 -0
  26. package/dist/cjs/NodeCommandExecutor.js.map +1 -0
  27. package/dist/cjs/NodeContext.js +48 -0
  28. package/dist/cjs/NodeContext.js.map +1 -0
  29. package/dist/cjs/NodeFileSystem.js +42 -0
  30. package/dist/cjs/NodeFileSystem.js.map +1 -0
  31. package/dist/cjs/NodeHttpClient.js +73 -0
  32. package/dist/cjs/NodeHttpClient.js.map +1 -0
  33. package/dist/cjs/NodeHttpServer.js +40 -0
  34. package/dist/cjs/NodeHttpServer.js.map +1 -0
  35. package/dist/cjs/NodeKeyValueStore.js +42 -0
  36. package/dist/cjs/NodeKeyValueStore.js.map +1 -0
  37. package/dist/cjs/NodePath.js +52 -0
  38. package/dist/cjs/NodePath.js.map +1 -0
  39. package/dist/cjs/NodeRuntime.js +42 -0
  40. package/dist/cjs/NodeRuntime.js.map +1 -0
  41. package/dist/cjs/NodeSink.js +17 -0
  42. package/dist/cjs/NodeSink.js.map +1 -0
  43. package/dist/cjs/NodeStream.js +17 -0
  44. package/dist/cjs/NodeStream.js.map +1 -0
  45. package/dist/cjs/NodeTerminal.js +47 -0
  46. package/dist/cjs/NodeTerminal.js.map +1 -0
  47. package/dist/cjs/NodeWorker.js +63 -0
  48. package/dist/cjs/NodeWorker.js.map +1 -0
  49. package/dist/cjs/NodeWorkerRunner.js +48 -0
  50. package/dist/cjs/NodeWorkerRunner.js.map +1 -0
  51. package/dist/cjs/index.js +58 -0
  52. package/dist/cjs/index.js.map +1 -0
  53. package/dist/cjs/internal/http/client.js +216 -0
  54. package/dist/cjs/internal/http/client.js.map +1 -0
  55. package/dist/cjs/internal/http/incomingMessage.js +91 -0
  56. package/dist/cjs/internal/http/incomingMessage.js.map +1 -0
  57. package/dist/cjs/internal/http/platform.js +77 -0
  58. package/dist/cjs/internal/http/platform.js.map +1 -0
  59. package/dist/cjs/internal/http/server.js +270 -0
  60. package/dist/cjs/internal/http/server.js.map +1 -0
  61. package/dist/cjs/internal/worker.js +89 -0
  62. package/dist/cjs/internal/worker.js.map +1 -0
  63. package/dist/cjs/internal/workerRunner.js +85 -0
  64. package/dist/cjs/internal/workerRunner.js.map +1 -0
  65. package/dist/dts/Http/Platform.d.ts +19 -0
  66. package/dist/dts/Http/Platform.d.ts.map +1 -0
  67. package/dist/dts/Http/Server.d.ts +50 -0
  68. package/dist/dts/Http/Server.d.ts.map +1 -0
  69. package/dist/dts/Http/ServerRequest.d.ts +12 -0
  70. package/dist/dts/Http/ServerRequest.d.ts.map +1 -0
  71. package/dist/dts/NodeCommandExecutor.d.ts +9 -0
  72. package/dist/dts/NodeCommandExecutor.d.ts.map +1 -0
  73. package/dist/dts/NodeContext.d.ts +17 -0
  74. package/dist/dts/NodeContext.d.ts.map +1 -0
  75. package/dist/dts/NodeFileSystem.d.ts +8 -0
  76. package/dist/dts/NodeFileSystem.d.ts.map +1 -0
  77. package/dist/dts/NodeHttpClient.d.ts +67 -0
  78. package/dist/dts/NodeHttpClient.d.ts.map +1 -0
  79. package/dist/dts/NodeHttpServer.d.ts +37 -0
  80. package/dist/dts/NodeHttpServer.d.ts.map +1 -0
  81. package/dist/dts/NodeKeyValueStore.d.ts +9 -0
  82. package/dist/dts/NodeKeyValueStore.d.ts.map +1 -0
  83. package/dist/dts/NodePath.d.ts +21 -0
  84. package/dist/dts/NodePath.d.ts.map +1 -0
  85. package/dist/dts/NodeRuntime.d.ts +7 -0
  86. package/dist/dts/NodeRuntime.d.ts.map +1 -0
  87. package/dist/dts/NodeSink.d.ts +8 -0
  88. package/dist/dts/NodeSink.d.ts.map +1 -0
  89. package/dist/dts/NodeStream.d.ts +8 -0
  90. package/dist/dts/NodeStream.d.ts.map +1 -0
  91. package/dist/dts/NodeTerminal.d.ts +15 -0
  92. package/dist/dts/NodeTerminal.d.ts.map +1 -0
  93. package/dist/dts/NodeWorker.d.ts +42 -0
  94. package/dist/dts/NodeWorker.d.ts.map +1 -0
  95. package/dist/dts/NodeWorkerRunner.d.ts +24 -0
  96. package/dist/dts/NodeWorkerRunner.d.ts.map +1 -0
  97. package/dist/dts/index.d.ts +53 -0
  98. package/dist/dts/index.d.ts.map +1 -0
  99. package/dist/dts/internal/http/client.d.ts +2 -0
  100. package/dist/dts/internal/http/client.d.ts.map +1 -0
  101. package/dist/dts/internal/http/incomingMessage.d.ts +2 -0
  102. package/dist/dts/internal/http/incomingMessage.d.ts.map +1 -0
  103. package/dist/dts/internal/http/platform.d.ts +2 -0
  104. package/dist/dts/internal/http/platform.d.ts.map +1 -0
  105. package/dist/dts/internal/http/server.d.ts +2 -0
  106. package/dist/dts/internal/http/server.d.ts.map +1 -0
  107. package/dist/dts/internal/worker.d.ts +2 -0
  108. package/dist/dts/internal/worker.d.ts.map +1 -0
  109. package/dist/dts/internal/workerRunner.d.ts +2 -0
  110. package/dist/dts/internal/workerRunner.d.ts.map +1 -0
  111. package/dist/esm/Http/Platform.js +12 -0
  112. package/dist/esm/Http/Platform.js.map +1 -0
  113. package/dist/esm/Http/Server.js +27 -0
  114. package/dist/esm/Http/Server.js.map +1 -0
  115. package/dist/esm/Http/ServerRequest.js +7 -0
  116. package/dist/esm/Http/ServerRequest.js.map +1 -0
  117. package/dist/esm/NodeCommandExecutor.js +10 -0
  118. package/dist/esm/NodeCommandExecutor.js.map +1 -0
  119. package/dist/esm/NodeContext.js +16 -0
  120. package/dist/esm/NodeContext.js.map +1 -0
  121. package/dist/esm/NodeFileSystem.js +10 -0
  122. package/dist/esm/NodeFileSystem.js.map +1 -0
  123. package/dist/esm/NodeHttpClient.js +42 -0
  124. package/dist/esm/NodeHttpClient.js.map +1 -0
  125. package/dist/esm/NodeHttpServer.js +37 -0
  126. package/dist/esm/NodeHttpServer.js.map +1 -0
  127. package/dist/esm/NodeKeyValueStore.js +10 -0
  128. package/dist/esm/NodeKeyValueStore.js.map +1 -0
  129. package/dist/esm/NodePath.js +20 -0
  130. package/dist/esm/NodePath.js.map +1 -0
  131. package/dist/esm/NodeRuntime.js +10 -0
  132. package/dist/esm/NodeRuntime.js.map +1 -0
  133. package/dist/esm/NodeSink.js +8 -0
  134. package/dist/esm/NodeSink.js.map +1 -0
  135. package/dist/esm/NodeStream.js +8 -0
  136. package/dist/esm/NodeStream.js.map +1 -0
  137. package/dist/esm/NodeTerminal.js +15 -0
  138. package/dist/esm/NodeTerminal.js.map +1 -0
  139. package/dist/esm/NodeWorker.js +32 -0
  140. package/dist/esm/NodeWorker.js.map +1 -0
  141. package/dist/esm/NodeWorkerRunner.js +17 -0
  142. package/dist/esm/NodeWorkerRunner.js.map +1 -0
  143. package/dist/esm/index.js +53 -0
  144. package/dist/esm/index.js.map +1 -0
  145. package/dist/esm/internal/http/client.js +183 -0
  146. package/dist/esm/internal/http/client.js.map +1 -0
  147. package/dist/esm/internal/http/incomingMessage.js +59 -0
  148. package/dist/esm/internal/http/incomingMessage.js.map +1 -0
  149. package/dist/esm/internal/http/platform.js +41 -0
  150. package/dist/esm/internal/http/platform.js.map +1 -0
  151. package/dist/esm/internal/http/server.js +233 -0
  152. package/dist/esm/internal/http/server.js.map +1 -0
  153. package/dist/esm/internal/worker.js +58 -0
  154. package/dist/esm/internal/worker.js.map +1 -0
  155. package/dist/esm/internal/workerRunner.js +52 -0
  156. package/dist/esm/internal/workerRunner.js.map +1 -0
  157. package/dist/esm/package.json +4 -0
  158. package/package.json +162 -0
  159. package/src/Http/Platform.ts +21 -0
  160. package/src/Http/Server.ts +86 -0
  161. package/src/Http/ServerRequest.ts +12 -0
  162. package/src/NodeCommandExecutor.ts +13 -0
  163. package/src/NodeContext.ts +40 -0
  164. package/src/NodeFileSystem.ts +12 -0
  165. package/src/NodeHttpClient.ts +76 -0
  166. package/src/NodeHttpServer.ts +38 -0
  167. package/src/NodeKeyValueStore.ts +15 -0
  168. package/src/NodePath.ts +25 -0
  169. package/src/NodeRuntime.ts +11 -0
  170. package/src/NodeSink.ts +8 -0
  171. package/src/NodeStream.ts +8 -0
  172. package/src/NodeTerminal.ts +20 -0
  173. package/src/NodeWorker.ts +58 -0
  174. package/src/NodeWorkerRunner.ts +38 -0
  175. package/src/index.ts +64 -0
  176. package/src/internal/http/client.ts +258 -0
  177. package/src/internal/http/incomingMessage.ts +81 -0
  178. package/src/internal/http/platform.ts +46 -0
  179. package/src/internal/http/server.ts +375 -0
  180. package/src/internal/worker.ts +74 -0
  181. package/src/internal/workerRunner.ts +74 -0
@@ -0,0 +1,258 @@
1
+ import type * as Body from "@effect/platform/Http/Body"
2
+ import * as Client from "@effect/platform/Http/Client"
3
+ import * as Error from "@effect/platform/Http/ClientError"
4
+ import type * as ClientRequest from "@effect/platform/Http/ClientRequest"
5
+ import * as ClientResponse from "@effect/platform/Http/ClientResponse"
6
+ import * as UrlParams from "@effect/platform/Http/UrlParams"
7
+ import * as Context from "effect/Context"
8
+ import * as Effect from "effect/Effect"
9
+ import { pipe } from "effect/Function"
10
+ import * as Layer from "effect/Layer"
11
+ import type * as Scope from "effect/Scope"
12
+ import * as Stream from "effect/Stream"
13
+ import * as Http from "node:http"
14
+ import * as Https from "node:https"
15
+ import { Readable } from "node:stream"
16
+ import { pipeline } from "node:stream/promises"
17
+ import type * as NodeClient from "../../NodeHttpClient.js"
18
+ import * as NodeSink from "../../NodeSink.js"
19
+ import { IncomingMessageImpl } from "./incomingMessage.js"
20
+
21
+ /** @internal */
22
+ export const HttpAgentTypeId: NodeClient.HttpAgentTypeId = Symbol.for(
23
+ "@effect/platform-node/Http/NodeClient/HttpAgent"
24
+ ) as NodeClient.HttpAgentTypeId
25
+
26
+ /** @internal */
27
+ export const HttpAgent = Context.GenericTag<NodeClient.HttpAgent>("@effect/platform-node/Http/NodeClient/HttpAgent")
28
+
29
+ /** @internal */
30
+ export const makeAgent = (options?: Https.AgentOptions): Effect.Effect<NodeClient.HttpAgent, never, Scope.Scope> =>
31
+ Effect.map(
32
+ Effect.all([
33
+ Effect.acquireRelease(
34
+ Effect.sync(() => new Http.Agent(options)),
35
+ (agent) => Effect.sync(() => agent.destroy())
36
+ ),
37
+ Effect.acquireRelease(
38
+ Effect.sync(() => new Https.Agent(options)),
39
+ (agent) => Effect.sync(() => agent.destroy())
40
+ )
41
+ ]),
42
+ ([http, https]) => ({
43
+ [HttpAgentTypeId]: HttpAgentTypeId,
44
+ http,
45
+ https
46
+ })
47
+ )
48
+
49
+ /** @internal */
50
+ export const makeAgentLayer = (options?: Https.AgentOptions): Layer.Layer<NodeClient.HttpAgent> =>
51
+ Layer.scoped(HttpAgent, makeAgent(options))
52
+
53
+ /** @internal */
54
+ export const agentLayer = makeAgentLayer()
55
+
56
+ const fromAgent = (agent: NodeClient.HttpAgent): Client.Client.Default =>
57
+ Client.makeDefault((request) =>
58
+ Effect.flatMap(
59
+ UrlParams.makeUrl(request.url, request.urlParams, (_) =>
60
+ Error.RequestError({
61
+ request,
62
+ reason: "InvalidUrl",
63
+ error: _
64
+ })),
65
+ (url) =>
66
+ Effect.suspend(() => {
67
+ const controller = new AbortController()
68
+ const nodeRequest = url.protocol === "https:" ?
69
+ Https.request(url, {
70
+ agent: agent.https,
71
+ method: request.method,
72
+ headers: request.headers,
73
+ signal: controller.signal
74
+ }) :
75
+ Http.request(url, {
76
+ agent: agent.http,
77
+ method: request.method,
78
+ headers: request.headers,
79
+ signal: controller.signal
80
+ })
81
+ return pipe(
82
+ Effect.zipRight(sendBody(nodeRequest, request, request.body), waitForResponse(nodeRequest, request), {
83
+ concurrent: true
84
+ }),
85
+ Effect.onInterrupt(() => Effect.sync(() => controller.abort())),
86
+ Effect.map((_) => new ClientResponseImpl(request, _))
87
+ )
88
+ })
89
+ )
90
+ )
91
+
92
+ const sendBody = (
93
+ nodeRequest: Http.ClientRequest,
94
+ request: ClientRequest.ClientRequest,
95
+ body: Body.Body
96
+ ): Effect.Effect<void, Error.RequestError> =>
97
+ Effect.suspend((): Effect.Effect<void, Error.RequestError> => {
98
+ switch (body._tag) {
99
+ case "Empty": {
100
+ nodeRequest.end()
101
+ return waitForFinish(nodeRequest, request)
102
+ }
103
+ case "Uint8Array":
104
+ case "Raw": {
105
+ nodeRequest.end(body.body)
106
+ return waitForFinish(nodeRequest, request)
107
+ }
108
+ case "FormData": {
109
+ const response = new Response(body.formData)
110
+
111
+ response.headers.forEach((value, key) => {
112
+ nodeRequest.setHeader(key, value)
113
+ })
114
+
115
+ return Effect.tryPromise({
116
+ try: () => pipeline(Readable.fromWeb(response.body! as any), nodeRequest),
117
+ catch: (_) =>
118
+ Error.RequestError({
119
+ request,
120
+ reason: "Transport",
121
+ error: _
122
+ })
123
+ })
124
+ }
125
+ case "Stream": {
126
+ return Stream.run(
127
+ Stream.mapError(body.stream, (_) =>
128
+ Error.RequestError({
129
+ request,
130
+ reason: "Encode",
131
+ error: _
132
+ })),
133
+ NodeSink.fromWritable(() => nodeRequest, (_) =>
134
+ Error.RequestError({
135
+ request,
136
+ reason: "Transport",
137
+ error: _
138
+ }))
139
+ )
140
+ }
141
+ }
142
+ })
143
+
144
+ const waitForResponse = (nodeRequest: Http.ClientRequest, request: ClientRequest.ClientRequest) =>
145
+ Effect.async<Http.IncomingMessage, Error.RequestError, never>((resume) => {
146
+ function onError(error: Error) {
147
+ resume(Effect.fail(Error.RequestError({
148
+ request,
149
+ reason: "Transport",
150
+ error
151
+ })))
152
+ }
153
+ nodeRequest.on("error", onError)
154
+
155
+ function onResponse(response: Http.IncomingMessage) {
156
+ nodeRequest.off("error", onError)
157
+ resume(Effect.succeed(response))
158
+ }
159
+ nodeRequest.on("upgrade", onResponse)
160
+ nodeRequest.on("response", onResponse)
161
+
162
+ return Effect.sync(() => {
163
+ nodeRequest.off("error", onError)
164
+ nodeRequest.off("upgrade", onResponse)
165
+ nodeRequest.off("response", onResponse)
166
+ })
167
+ })
168
+
169
+ const waitForFinish = (nodeRequest: Http.ClientRequest, request: ClientRequest.ClientRequest) =>
170
+ Effect.async<void, Error.RequestError, never>((resume) => {
171
+ function onError(error: Error) {
172
+ resume(Effect.fail(Error.RequestError({
173
+ request,
174
+ reason: "Transport",
175
+ error
176
+ })))
177
+ }
178
+ nodeRequest.once("error", onError)
179
+
180
+ function onFinish() {
181
+ nodeRequest.off("error", onError)
182
+ resume(Effect.unit)
183
+ }
184
+ nodeRequest.once("finish", onFinish)
185
+
186
+ return Effect.sync(() => {
187
+ nodeRequest.off("error", onError)
188
+ nodeRequest.off("finish", onFinish)
189
+ })
190
+ })
191
+
192
+ class ClientResponseImpl extends IncomingMessageImpl<Error.ResponseError> implements ClientResponse.ClientResponse {
193
+ readonly [ClientResponse.TypeId]: ClientResponse.TypeId
194
+
195
+ constructor(
196
+ readonly request: ClientRequest.ClientRequest,
197
+ source: Http.IncomingMessage
198
+ ) {
199
+ super(source, (_) =>
200
+ Error.ResponseError({
201
+ request,
202
+ response: this,
203
+ reason: "Decode",
204
+ error: _
205
+ }))
206
+ this[ClientResponse.TypeId] = ClientResponse.TypeId
207
+ }
208
+
209
+ get status() {
210
+ return this.source.statusCode!
211
+ }
212
+
213
+ get formData(): Effect.Effect<FormData, Error.ResponseError> {
214
+ return Effect.tryPromise({
215
+ try: () => {
216
+ const init: {
217
+ headers: HeadersInit
218
+ status?: number
219
+ statusText?: string
220
+ } = {
221
+ headers: new globalThis.Headers(this.source.headers as any)
222
+ }
223
+
224
+ if (this.source.statusCode) {
225
+ init.status = this.source.statusCode
226
+ }
227
+
228
+ if (this.source.statusMessage) {
229
+ init.statusText = this.source.statusMessage
230
+ }
231
+
232
+ return new Response(Readable.toWeb(this.source) as any, init).formData()
233
+ },
234
+ catch: this.onError
235
+ })
236
+ }
237
+
238
+ toString(): string {
239
+ return `ClientResponse(${this.status})`
240
+ }
241
+
242
+ toJSON(): unknown {
243
+ return {
244
+ _tag: "ClientResponse",
245
+ status: this.status,
246
+ headers: this.headers
247
+ }
248
+ }
249
+ }
250
+
251
+ /** @internal */
252
+ export const make = Effect.map(HttpAgent, fromAgent)
253
+
254
+ /** @internal */
255
+ export const layerWithoutAgent = Layer.effect(Client.Client, make)
256
+
257
+ /** @internal */
258
+ export const layer = Layer.provide(layerWithoutAgent, agentLayer)
@@ -0,0 +1,81 @@
1
+ import * as Headers from "@effect/platform/Http/Headers"
2
+ import * as IncomingMessage from "@effect/platform/Http/IncomingMessage"
3
+ import * as UrlParams from "@effect/platform/Http/UrlParams"
4
+ import * as Effect from "effect/Effect"
5
+ import * as FiberRef from "effect/FiberRef"
6
+ import * as Option from "effect/Option"
7
+ import type * as Stream from "effect/Stream"
8
+ import type * as Http from "node:http"
9
+ import * as NodeStream from "../../NodeStream.js"
10
+
11
+ /** @internal */
12
+ export class IncomingMessageImpl<E> implements IncomingMessage.IncomingMessage<E> {
13
+ readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId
14
+
15
+ constructor(
16
+ readonly source: Http.IncomingMessage,
17
+ readonly onError: (error: unknown) => E,
18
+ readonly remoteAddressOverride?: string
19
+ ) {
20
+ this[IncomingMessage.TypeId] = IncomingMessage.TypeId
21
+ }
22
+
23
+ get headers() {
24
+ return Headers.fromInput(this.source.headers as any)
25
+ }
26
+
27
+ get remoteAddress() {
28
+ return Option.fromNullable(this.remoteAddressOverride ?? this.source.socket.remoteAddress)
29
+ }
30
+
31
+ private textEffect: Effect.Effect<string, E> | undefined
32
+ get text(): Effect.Effect<string, E> {
33
+ if (this.textEffect) {
34
+ return this.textEffect
35
+ }
36
+ this.textEffect = Effect.runSync(Effect.cached(
37
+ Effect.flatMap(
38
+ FiberRef.get(IncomingMessage.maxBodySize),
39
+ (maxBodySize) =>
40
+ NodeStream.toString(() => this.source, {
41
+ onFailure: this.onError,
42
+ maxBytes: Option.getOrUndefined(maxBodySize)
43
+ })
44
+ )
45
+ ))
46
+ return this.textEffect
47
+ }
48
+
49
+ get json(): Effect.Effect<unknown, E> {
50
+ return Effect.tryMap(this.text, {
51
+ try: (_) => _ === "" ? null : JSON.parse(_) as unknown,
52
+ catch: this.onError
53
+ })
54
+ }
55
+
56
+ get urlParamsBody(): Effect.Effect<UrlParams.UrlParams, E> {
57
+ return Effect.flatMap(this.text, (_) =>
58
+ Effect.try({
59
+ try: () => UrlParams.fromInput(new URLSearchParams(_)),
60
+ catch: this.onError
61
+ }))
62
+ }
63
+
64
+ get stream(): Stream.Stream<Uint8Array, E> {
65
+ return NodeStream.fromReadable<E, Uint8Array>(
66
+ () => this.source,
67
+ this.onError
68
+ )
69
+ }
70
+
71
+ get arrayBuffer(): Effect.Effect<ArrayBuffer, E> {
72
+ return Effect.flatMap(
73
+ FiberRef.get(IncomingMessage.maxBodySize),
74
+ (maxBodySize) =>
75
+ NodeStream.toUint8Array(() => this.source, {
76
+ onFailure: this.onError,
77
+ maxBytes: Option.getOrUndefined(maxBodySize)
78
+ })
79
+ )
80
+ }
81
+ }
@@ -0,0 +1,46 @@
1
+ import * as EtagImpl from "@effect/platform-node-shared/Http/Etag"
2
+ import * as Headers from "@effect/platform/Http/Headers"
3
+ import * as Platform from "@effect/platform/Http/Platform"
4
+ import * as ServerResponse from "@effect/platform/Http/ServerResponse"
5
+ import { pipe } from "effect/Function"
6
+ import * as Layer from "effect/Layer"
7
+ import Mime from "mime"
8
+ import * as Fs from "node:fs"
9
+ import { Readable } from "node:stream"
10
+ import * as FileSystem from "../../NodeFileSystem.js"
11
+
12
+ /** @internal */
13
+ export const make = Platform.make({
14
+ fileResponse(path, status, statusText, headers, start, end, contentLength) {
15
+ const stream = Fs.createReadStream(path, { start, end })
16
+ return ServerResponse.raw(stream, {
17
+ headers: {
18
+ ...headers,
19
+ "content-type": headers["content-type"] ?? Mime.getType(path) ?? "application/octet-stream",
20
+ "content-length": contentLength.toString()
21
+ },
22
+ status,
23
+ statusText
24
+ })
25
+ },
26
+ fileWebResponse(file, status, statusText, headers, _options) {
27
+ return ServerResponse.raw(Readable.fromWeb(file.stream() as any), {
28
+ headers: Headers.merge(
29
+ headers,
30
+ Headers.unsafeFromRecord({
31
+ "content-type": headers["content-type"] ?? Mime.getType(file.name) ?? "application/octet-stream",
32
+ "content-length": file.size.toString()
33
+ })
34
+ ),
35
+ status,
36
+ statusText
37
+ })
38
+ }
39
+ })
40
+
41
+ /** @internal */
42
+ export const layer = pipe(
43
+ Layer.effect(Platform.Platform, make),
44
+ Layer.provide(FileSystem.layer),
45
+ Layer.provide(EtagImpl.layer)
46
+ )