@effect/platform 0.63.2 → 0.64.0
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/cjs/Cookies.js +0 -1
- package/dist/cjs/Cookies.js.map +1 -1
- package/dist/cjs/Etag.js +11 -1
- package/dist/cjs/Etag.js.map +1 -1
- package/dist/cjs/HttpApiBuilder.js +35 -1
- package/dist/cjs/HttpApiBuilder.js.map +1 -1
- package/dist/cjs/HttpPlatform.js +6 -1
- package/dist/cjs/HttpPlatform.js.map +1 -1
- package/dist/cjs/Socket.js +65 -34
- package/dist/cjs/Socket.js.map +1 -1
- package/dist/cjs/internal/etag.js +42 -1
- package/dist/cjs/internal/etag.js.map +1 -1
- package/dist/cjs/internal/httpPlatform.js +28 -4
- package/dist/cjs/internal/httpPlatform.js.map +1 -1
- package/dist/cjs/internal/httpServerResponse.js +5 -4
- package/dist/cjs/internal/httpServerResponse.js.map +1 -1
- package/dist/cjs/internal/multipart.js +1 -3
- package/dist/cjs/internal/multipart.js.map +1 -1
- package/dist/dts/Etag.d.ts +11 -0
- package/dist/dts/Etag.d.ts.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts +29 -1
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/HttpPlatform.d.ts +6 -0
- package/dist/dts/HttpPlatform.d.ts.map +1 -1
- package/dist/dts/Socket.d.ts +20 -3
- package/dist/dts/Socket.d.ts.map +1 -1
- package/dist/esm/Cookies.js +0 -1
- package/dist/esm/Cookies.js.map +1 -1
- package/dist/esm/Etag.js +10 -0
- package/dist/esm/Etag.js.map +1 -1
- package/dist/esm/HttpApiBuilder.js +33 -0
- package/dist/esm/HttpApiBuilder.js.map +1 -1
- package/dist/esm/HttpPlatform.js +5 -0
- package/dist/esm/HttpPlatform.js.map +1 -1
- package/dist/esm/Socket.js +62 -33
- package/dist/esm/Socket.js.map +1 -1
- package/dist/esm/internal/etag.js +41 -0
- package/dist/esm/internal/etag.js.map +1 -1
- package/dist/esm/internal/httpPlatform.js +28 -4
- package/dist/esm/internal/httpPlatform.js.map +1 -1
- package/dist/esm/internal/httpServerResponse.js +4 -3
- package/dist/esm/internal/httpServerResponse.js.map +1 -1
- package/dist/esm/internal/multipart.js +1 -3
- package/dist/esm/internal/multipart.js.map +1 -1
- package/package.json +2 -2
- package/src/Cookies.ts +1 -1
- package/src/Etag.ts +13 -0
- package/src/HttpApiBuilder.ts +46 -2
- package/src/HttpPlatform.ts +7 -0
- package/src/Socket.ts +113 -52
- package/src/internal/etag.ts +43 -0
- package/src/internal/httpPlatform.ts +32 -4
- package/src/internal/httpServerResponse.ts +6 -3
- package/src/internal/multipart.ts +1 -3
package/src/Socket.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import * as Cause from "effect/Cause"
|
|
5
4
|
import * as Channel from "effect/Channel"
|
|
6
5
|
import * as Chunk from "effect/Chunk"
|
|
7
6
|
import * as Context from "effect/Context"
|
|
@@ -12,6 +11,7 @@ import * as ExecutionStrategy from "effect/ExecutionStrategy"
|
|
|
12
11
|
import * as Exit from "effect/Exit"
|
|
13
12
|
import * as FiberRef from "effect/FiberRef"
|
|
14
13
|
import * as FiberSet from "effect/FiberSet"
|
|
14
|
+
import { dual } from "effect/Function"
|
|
15
15
|
import { globalValue } from "effect/GlobalValue"
|
|
16
16
|
import * as Layer from "effect/Layer"
|
|
17
17
|
import * as Predicate from "effect/Predicate"
|
|
@@ -32,6 +32,12 @@ export const TypeId: unique symbol = Symbol.for("@effect/platform/Socket")
|
|
|
32
32
|
*/
|
|
33
33
|
export type TypeId = typeof TypeId
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @since 1.0.0
|
|
37
|
+
* @category guards
|
|
38
|
+
*/
|
|
39
|
+
export const isSocket = (u: unknown): u is Socket => Predicate.hasProperty(u, TypeId)
|
|
40
|
+
|
|
35
41
|
/**
|
|
36
42
|
* @since 1.0.0
|
|
37
43
|
* @category tags
|
|
@@ -171,10 +177,11 @@ export class SocketCloseError extends TypeIdError(SocketErrorTypeId, "SocketErro
|
|
|
171
177
|
* @since 1.0.0
|
|
172
178
|
* @category combinators
|
|
173
179
|
*/
|
|
174
|
-
export const
|
|
175
|
-
self: Socket
|
|
180
|
+
export const toChannelMap = <IE, A>(
|
|
181
|
+
self: Socket,
|
|
182
|
+
f: (data: Uint8Array | string) => A
|
|
176
183
|
): Channel.Channel<
|
|
177
|
-
Chunk.Chunk<
|
|
184
|
+
Chunk.Chunk<A>,
|
|
178
185
|
Chunk.Chunk<Uint8Array | string | CloseEvent>,
|
|
179
186
|
SocketError | IE,
|
|
180
187
|
IE,
|
|
@@ -183,25 +190,27 @@ export const toChannel = <IE>(
|
|
|
183
190
|
> =>
|
|
184
191
|
Effect.scope.pipe(
|
|
185
192
|
Effect.bindTo("scope"),
|
|
193
|
+
Effect.let("state", () => ({ finished: false, buffer: [] as Array<A> })),
|
|
194
|
+
Effect.bind("semaphore", () => Effect.makeSemaphore(0)),
|
|
186
195
|
Effect.bind("writeScope", ({ scope }) => Scope.fork(scope, ExecutionStrategy.sequential)),
|
|
187
196
|
Effect.bind("write", ({ writeScope }) => Scope.extend(self.writer, writeScope)),
|
|
188
|
-
Effect.bind("
|
|
197
|
+
Effect.bind("deferred", () => Deferred.make<void, SocketError | IE>()),
|
|
189
198
|
Effect.let(
|
|
190
199
|
"input",
|
|
191
200
|
(
|
|
192
|
-
{
|
|
201
|
+
{ deferred, write, writeScope }
|
|
193
202
|
): AsyncProducer.AsyncInputProducer<IE, Chunk.Chunk<Uint8Array | string | CloseEvent>, unknown> => ({
|
|
194
203
|
awaitRead: () => Effect.void,
|
|
195
204
|
emit(chunk) {
|
|
196
205
|
return Effect.catchAllCause(
|
|
197
206
|
Effect.forEach(chunk, write, { discard: true }),
|
|
198
|
-
(cause) =>
|
|
207
|
+
(cause) => Deferred.failCause(deferred, cause)
|
|
199
208
|
)
|
|
200
209
|
},
|
|
201
210
|
error(error) {
|
|
202
211
|
return Effect.zipRight(
|
|
203
212
|
Scope.close(writeScope, Exit.void),
|
|
204
|
-
|
|
213
|
+
Deferred.failCause(deferred, error)
|
|
205
214
|
)
|
|
206
215
|
},
|
|
207
216
|
done() {
|
|
@@ -209,30 +218,95 @@ export const toChannel = <IE>(
|
|
|
209
218
|
}
|
|
210
219
|
})
|
|
211
220
|
),
|
|
212
|
-
Effect.tap(({
|
|
213
|
-
self.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Effect.
|
|
221
|
+
Effect.tap(({ deferred, scope, semaphore, state }) =>
|
|
222
|
+
self.runRaw((data) => {
|
|
223
|
+
state.buffer.push(f(data))
|
|
224
|
+
return semaphore.release(1)
|
|
225
|
+
}).pipe(
|
|
226
|
+
Effect.intoDeferred(deferred),
|
|
227
|
+
Effect.raceFirst(Deferred.await(deferred)),
|
|
228
|
+
Effect.ensuring(Effect.suspend(() => {
|
|
229
|
+
state.finished = true
|
|
230
|
+
return semaphore.release(1)
|
|
231
|
+
})),
|
|
232
|
+
Effect.forkIn(scope),
|
|
218
233
|
Effect.interruptible
|
|
219
234
|
)
|
|
220
235
|
),
|
|
221
|
-
Effect.map(({
|
|
222
|
-
const loop: Channel.Channel<Chunk.Chunk<
|
|
223
|
-
.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
Effect.map(({ deferred, input, semaphore, state }) => {
|
|
237
|
+
const loop: Channel.Channel<Chunk.Chunk<A>, unknown, SocketError | IE, unknown, void, unknown> = Channel.flatMap(
|
|
238
|
+
semaphore.take(1),
|
|
239
|
+
(_) => {
|
|
240
|
+
if (state.buffer.length === 0) {
|
|
241
|
+
return state.finished ? Deferred.await(deferred) : loop
|
|
242
|
+
}
|
|
243
|
+
const chunk = Chunk.unsafeFromArray(state.buffer)
|
|
244
|
+
state.buffer = []
|
|
245
|
+
return Channel.zipRight(Channel.write(chunk), state.finished ? Deferred.await(deferred) : loop)
|
|
246
|
+
}
|
|
247
|
+
)
|
|
231
248
|
return Channel.embedInput(loop, input)
|
|
232
249
|
}),
|
|
233
250
|
Channel.unwrapScoped
|
|
234
251
|
)
|
|
235
252
|
|
|
253
|
+
/**
|
|
254
|
+
* @since 1.0.0
|
|
255
|
+
* @category combinators
|
|
256
|
+
*/
|
|
257
|
+
export const toChannel = <IE>(
|
|
258
|
+
self: Socket
|
|
259
|
+
): Channel.Channel<
|
|
260
|
+
Chunk.Chunk<Uint8Array>,
|
|
261
|
+
Chunk.Chunk<Uint8Array | string | CloseEvent>,
|
|
262
|
+
SocketError | IE,
|
|
263
|
+
IE,
|
|
264
|
+
void,
|
|
265
|
+
unknown
|
|
266
|
+
> => {
|
|
267
|
+
const encoder = new TextEncoder()
|
|
268
|
+
return toChannelMap(self, (data) => typeof data === "string" ? encoder.encode(data) : data)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @since 1.0.0
|
|
273
|
+
* @category combinators
|
|
274
|
+
*/
|
|
275
|
+
export const toChannelString: {
|
|
276
|
+
(encoding?: string | undefined): <IE>(self: Socket) => Channel.Channel<
|
|
277
|
+
Chunk.Chunk<string>,
|
|
278
|
+
Chunk.Chunk<Uint8Array | string | CloseEvent>,
|
|
279
|
+
SocketError | IE,
|
|
280
|
+
IE,
|
|
281
|
+
void,
|
|
282
|
+
unknown
|
|
283
|
+
>
|
|
284
|
+
<IE>(
|
|
285
|
+
self: Socket,
|
|
286
|
+
encoding?: string | undefined
|
|
287
|
+
): Channel.Channel<
|
|
288
|
+
Chunk.Chunk<string>,
|
|
289
|
+
Chunk.Chunk<Uint8Array | string | CloseEvent>,
|
|
290
|
+
SocketError | IE,
|
|
291
|
+
IE,
|
|
292
|
+
void,
|
|
293
|
+
unknown
|
|
294
|
+
>
|
|
295
|
+
} = dual((args) => isSocket(args[0]), <IE>(
|
|
296
|
+
self: Socket,
|
|
297
|
+
encoding?: string | undefined
|
|
298
|
+
): Channel.Channel<
|
|
299
|
+
Chunk.Chunk<string>,
|
|
300
|
+
Chunk.Chunk<Uint8Array | string | CloseEvent>,
|
|
301
|
+
SocketError | IE,
|
|
302
|
+
IE,
|
|
303
|
+
void,
|
|
304
|
+
unknown
|
|
305
|
+
> => {
|
|
306
|
+
const decoder = new TextDecoder(encoding)
|
|
307
|
+
return toChannelMap(self, (data) => typeof data === "string" ? data : decoder.decode(data))
|
|
308
|
+
})
|
|
309
|
+
|
|
236
310
|
/**
|
|
237
311
|
* @since 1.0.0
|
|
238
312
|
* @category combinators
|
|
@@ -348,16 +422,12 @@ export const fromWebSocket = <R>(
|
|
|
348
422
|
Effect.map(
|
|
349
423
|
Queue.dropping<Uint8Array | string | CloseEvent>(fiber.getFiberRef(currentSendQueueCapacity)),
|
|
350
424
|
(sendQueue) => {
|
|
351
|
-
const acquireContext = fiber.getFiberRef(FiberRef.currentContext) as Context.Context<
|
|
425
|
+
const acquireContext = fiber.getFiberRef(FiberRef.currentContext) as Context.Context<R>
|
|
352
426
|
const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
|
|
353
427
|
const runRaw = <_, E, R>(handler: (_: string | Uint8Array) => Effect.Effect<_, E, R>) =>
|
|
354
|
-
|
|
355
|
-
Effect.bindTo("
|
|
356
|
-
Effect.bind("
|
|
357
|
-
acquire.pipe(
|
|
358
|
-
Effect.provide(Context.add(acquireContext, Scope.Scope, scope))
|
|
359
|
-
) as Effect.Effect<globalThis.WebSocket>),
|
|
360
|
-
Effect.bind("fiberSet", (_) => FiberSet.make<any, E | SocketError>()),
|
|
428
|
+
acquire.pipe(
|
|
429
|
+
Effect.bindTo("ws"),
|
|
430
|
+
Effect.bind("fiberSet", () => FiberSet.make<any, E | SocketError>()),
|
|
361
431
|
Effect.bind("run", ({ fiberSet, ws }) =>
|
|
362
432
|
Effect.provideService(FiberSet.runtime(fiberSet)<R>(), WebSocket, ws)),
|
|
363
433
|
Effect.tap(({ fiberSet, run, ws }) => {
|
|
@@ -392,19 +462,12 @@ export const fromWebSocket = <R>(
|
|
|
392
462
|
}
|
|
393
463
|
|
|
394
464
|
if (ws.readyState !== 1) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
return Effect.sync(() => {
|
|
402
|
-
ws.removeEventListener("open", onOpen)
|
|
403
|
-
})
|
|
404
|
-
}).pipe(
|
|
405
|
-
Effect.tap((_) => {
|
|
406
|
-
open = true
|
|
407
|
-
}),
|
|
465
|
+
const openDeferred = Deferred.unsafeMake<void>(fiber.id())
|
|
466
|
+
ws.onopen = () => {
|
|
467
|
+
open = true
|
|
468
|
+
Deferred.unsafeDone(openDeferred, Effect.void)
|
|
469
|
+
}
|
|
470
|
+
return Deferred.await(openDeferred).pipe(
|
|
408
471
|
Effect.timeoutFail({
|
|
409
472
|
duration: options?.openTimeout ?? 10000,
|
|
410
473
|
onTimeout: () =>
|
|
@@ -445,6 +508,7 @@ export const fromWebSocket = <R>(
|
|
|
445
508
|
(_) => Effect.void
|
|
446
509
|
)
|
|
447
510
|
),
|
|
511
|
+
Effect.mapInputContext((input: Context.Context<R | Scope.Scope>) => Context.merge(acquireContext, input)),
|
|
448
512
|
Effect.scoped,
|
|
449
513
|
Effect.interruptible
|
|
450
514
|
)
|
|
@@ -534,15 +598,11 @@ export const fromTransformStream = <R>(acquire: Effect.Effect<InputTransformStre
|
|
|
534
598
|
Effect.map(
|
|
535
599
|
Queue.dropping<Uint8Array | string | CloseEvent | typeof EOF>(fiber.getFiberRef(currentSendQueueCapacity)),
|
|
536
600
|
(sendQueue) => {
|
|
537
|
-
const acquireContext = fiber.getFiberRef(FiberRef.currentContext) as Context.Context<
|
|
601
|
+
const acquireContext = fiber.getFiberRef(FiberRef.currentContext) as Context.Context<R>
|
|
538
602
|
const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
|
|
539
603
|
const runRaw = <_, E, R>(handler: (_: string | Uint8Array) => Effect.Effect<_, E, R>) =>
|
|
540
|
-
|
|
541
|
-
Effect.bindTo("
|
|
542
|
-
Effect.bind("stream", ({ scope }) =>
|
|
543
|
-
acquire.pipe(
|
|
544
|
-
Effect.provide(Context.add(acquireContext, Scope.Scope, scope))
|
|
545
|
-
) as Effect.Effect<InputTransformStream>),
|
|
604
|
+
acquire.pipe(
|
|
605
|
+
Effect.bindTo("stream"),
|
|
546
606
|
Effect.bind("reader", ({ stream }) =>
|
|
547
607
|
Effect.acquireRelease(
|
|
548
608
|
Effect.sync(() => stream.readable.getReader()),
|
|
@@ -615,6 +675,7 @@ export const fromTransformStream = <R>(acquire: Effect.Effect<InputTransformStre
|
|
|
615
675
|
(_) => Effect.void
|
|
616
676
|
)
|
|
617
677
|
),
|
|
678
|
+
Effect.mapInputContext((input: Context.Context<R | Scope.Scope>) => Context.merge(acquireContext, input)),
|
|
618
679
|
Effect.scoped,
|
|
619
680
|
Effect.interruptible
|
|
620
681
|
)
|
package/src/internal/etag.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as Context from "effect/Context"
|
|
2
|
+
import * as Effect from "effect/Effect"
|
|
3
|
+
import * as Layer from "effect/Layer"
|
|
2
4
|
import type * as Etag from "../Etag.js"
|
|
5
|
+
import type * as FileSystem from "../FileSystem.js"
|
|
6
|
+
import type * as Body from "../HttpBody.js"
|
|
3
7
|
|
|
4
8
|
/** @internal */
|
|
5
9
|
export const GeneratorTypeId: Etag.GeneratorTypeId = Symbol.for(
|
|
@@ -18,3 +22,42 @@ export const toString = (self: Etag.Etag): string => {
|
|
|
18
22
|
return `"${self.value}"`
|
|
19
23
|
}
|
|
20
24
|
}
|
|
25
|
+
|
|
26
|
+
const fromFileInfo = (info: FileSystem.File.Info) => {
|
|
27
|
+
const mtime = info.mtime._tag === "Some"
|
|
28
|
+
? info.mtime.value.getTime().toString(16)
|
|
29
|
+
: "0"
|
|
30
|
+
return `${info.size.toString(16)}-${mtime}`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const fromFileWeb = (file: Body.HttpBody.FileLike) => {
|
|
34
|
+
return `${file.size.toString(16)}-${file.lastModified.toString(16)}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @internal */
|
|
38
|
+
export const layer = Layer.succeed(
|
|
39
|
+
tag,
|
|
40
|
+
tag.of({
|
|
41
|
+
[GeneratorTypeId]: GeneratorTypeId,
|
|
42
|
+
fromFileInfo(info) {
|
|
43
|
+
return Effect.sync(() => ({ _tag: "Strong", value: fromFileInfo(info) }))
|
|
44
|
+
},
|
|
45
|
+
fromFileWeb(file) {
|
|
46
|
+
return Effect.sync(() => ({ _tag: "Strong", value: fromFileWeb(file) }))
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
/** @internal */
|
|
52
|
+
export const layerWeak = Layer.succeed(
|
|
53
|
+
tag,
|
|
54
|
+
tag.of({
|
|
55
|
+
[GeneratorTypeId]: GeneratorTypeId,
|
|
56
|
+
fromFileInfo(info) {
|
|
57
|
+
return Effect.sync(() => ({ _tag: "Weak", value: fromFileInfo(info) }))
|
|
58
|
+
},
|
|
59
|
+
fromFileWeb(file) {
|
|
60
|
+
return Effect.sync(() => ({ _tag: "Weak", value: fromFileWeb(file) }))
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
)
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import * as Context from "effect/Context"
|
|
2
2
|
import * as Effect from "effect/Effect"
|
|
3
|
-
import { pipe } from "effect/Function"
|
|
3
|
+
import { identity, pipe } from "effect/Function"
|
|
4
|
+
import * as Layer from "effect/Layer"
|
|
5
|
+
import * as Stream from "effect/Stream"
|
|
4
6
|
import * as Etag from "../Etag.js"
|
|
5
7
|
import * as FileSystem from "../FileSystem.js"
|
|
6
8
|
import * as Headers from "../Headers.js"
|
|
7
9
|
import type * as Body from "../HttpBody.js"
|
|
8
10
|
import type * as Platform from "../HttpPlatform.js"
|
|
9
11
|
import type * as ServerResponse from "../HttpServerResponse.js"
|
|
12
|
+
import * as serverResponse from "./httpServerResponse.js"
|
|
10
13
|
|
|
11
14
|
/** @internal */
|
|
12
15
|
export const TypeId: Platform.TypeId = Symbol.for("@effect/platform/HttpPlatform") as Platform.TypeId
|
|
@@ -33,9 +36,9 @@ export const make = (impl: {
|
|
|
33
36
|
options?: FileSystem.StreamOptions
|
|
34
37
|
) => ServerResponse.HttpServerResponse
|
|
35
38
|
}): Effect.Effect<Platform.HttpPlatform, never, FileSystem.FileSystem | Etag.Generator> =>
|
|
36
|
-
Effect.gen(function*(
|
|
37
|
-
const fs = yield*
|
|
38
|
-
const etagGen = yield*
|
|
39
|
+
Effect.gen(function*() {
|
|
40
|
+
const fs = yield* FileSystem.FileSystem
|
|
41
|
+
const etagGen = yield* Etag.Generator
|
|
39
42
|
|
|
40
43
|
return tag.of({
|
|
41
44
|
[TypeId]: TypeId,
|
|
@@ -83,3 +86,28 @@ export const make = (impl: {
|
|
|
83
86
|
}
|
|
84
87
|
})
|
|
85
88
|
})
|
|
89
|
+
|
|
90
|
+
/** @internal */
|
|
91
|
+
export const layer = Layer.effect(
|
|
92
|
+
tag,
|
|
93
|
+
Effect.flatMap(FileSystem.FileSystem, (fs) =>
|
|
94
|
+
make({
|
|
95
|
+
fileResponse(path, status, statusText, headers, start, end, contentLength) {
|
|
96
|
+
return serverResponse.stream(
|
|
97
|
+
fs.stream(path, {
|
|
98
|
+
offset: start,
|
|
99
|
+
bytesToRead: end !== undefined ? end - start : undefined
|
|
100
|
+
}),
|
|
101
|
+
{ contentLength, headers, status, statusText }
|
|
102
|
+
)
|
|
103
|
+
},
|
|
104
|
+
fileWebResponse(file, status, statusText, headers, _options) {
|
|
105
|
+
return serverResponse.stream(
|
|
106
|
+
Stream.fromReadableStream(() => file.stream() as ReadableStream<Uint8Array>, identity),
|
|
107
|
+
{ headers, status, statusText }
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
}))
|
|
111
|
+
).pipe(
|
|
112
|
+
Layer.provide(Etag.layerWeak)
|
|
113
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ParseOptions } from "@effect/schema/AST"
|
|
2
2
|
import type * as Schema from "@effect/schema/Schema"
|
|
3
|
+
import * as Context from "effect/Context"
|
|
3
4
|
import * as Effect from "effect/Effect"
|
|
4
5
|
import * as Effectable from "effect/Effectable"
|
|
5
6
|
import { dual } from "effect/Function"
|
|
@@ -11,7 +12,7 @@ import type * as PlatformError from "../Error.js"
|
|
|
11
12
|
import type * as FileSystem from "../FileSystem.js"
|
|
12
13
|
import * as Headers from "../Headers.js"
|
|
13
14
|
import type * as Body from "../HttpBody.js"
|
|
14
|
-
import * as Platform from "../HttpPlatform.js"
|
|
15
|
+
import type * as Platform from "../HttpPlatform.js"
|
|
15
16
|
import type * as Respondable from "../HttpServerRespondable.js"
|
|
16
17
|
import type * as ServerResponse from "../HttpServerResponse.js"
|
|
17
18
|
import * as Template from "../Template.js"
|
|
@@ -214,13 +215,15 @@ export const schemaJson = <A, I, R>(
|
|
|
214
215
|
))
|
|
215
216
|
}
|
|
216
217
|
|
|
218
|
+
const httpPlatform = Context.GenericTag<Platform.HttpPlatform>("@effect/platform/HttpPlatform")
|
|
219
|
+
|
|
217
220
|
/** @internal */
|
|
218
221
|
export const file = (
|
|
219
222
|
path: string,
|
|
220
223
|
options?: (ServerResponse.Options & FileSystem.StreamOptions) | undefined
|
|
221
224
|
): Effect.Effect<ServerResponse.HttpServerResponse, PlatformError.PlatformError, Platform.HttpPlatform> =>
|
|
222
225
|
Effect.flatMap(
|
|
223
|
-
|
|
226
|
+
httpPlatform,
|
|
224
227
|
(platform) => platform.fileResponse(path, options)
|
|
225
228
|
)
|
|
226
229
|
|
|
@@ -230,7 +233,7 @@ export const fileWeb = (
|
|
|
230
233
|
options?: (ServerResponse.Options.WithContent & FileSystem.StreamOptions) | undefined
|
|
231
234
|
): Effect.Effect<ServerResponse.HttpServerResponse, never, Platform.HttpPlatform> =>
|
|
232
235
|
Effect.flatMap(
|
|
233
|
-
|
|
236
|
+
httpPlatform,
|
|
234
237
|
(platform) => platform.fileWebResponse(file, options)
|
|
235
238
|
)
|
|
236
239
|
|