effect 4.0.0-beta.27 → 4.0.0-beta.29
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/Brand.d.ts +1 -1
- package/dist/Brand.d.ts.map +1 -1
- package/dist/Brand.js +1 -1
- package/dist/Brand.js.map +1 -1
- package/dist/ConfigProvider.d.ts +1 -1
- package/dist/Cron.d.ts +1 -1
- package/dist/Data.d.ts +1 -1
- package/dist/Data.d.ts.map +1 -1
- package/dist/Data.js.map +1 -1
- package/dist/Effect.d.ts +300 -184
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +99 -61
- package/dist/Effect.js.map +1 -1
- package/dist/Encoding.d.ts +1 -1
- package/dist/Exit.d.ts +24 -12
- package/dist/Exit.d.ts.map +1 -1
- package/dist/Exit.js +8 -4
- package/dist/Exit.js.map +1 -1
- package/dist/Fiber.d.ts +1 -0
- package/dist/Fiber.d.ts.map +1 -1
- package/dist/Fiber.js.map +1 -1
- package/dist/Function.d.ts +1 -9
- package/dist/Function.d.ts.map +1 -1
- package/dist/Function.js +2 -10
- package/dist/Function.js.map +1 -1
- package/dist/Graph.d.ts +1 -1
- package/dist/Newtype.d.ts +291 -0
- package/dist/Newtype.d.ts.map +1 -0
- package/dist/Newtype.js +161 -0
- package/dist/Newtype.js.map +1 -0
- package/dist/PlatformError.d.ts +2 -2
- package/dist/References.d.ts +6 -1
- package/dist/References.d.ts.map +1 -1
- package/dist/References.js +6 -1
- package/dist/References.js.map +1 -1
- package/dist/RequestResolver.d.ts +19 -19
- package/dist/RequestResolver.js +10 -10
- package/dist/RequestResolver.js.map +1 -1
- package/dist/Schedule.d.ts +142 -80
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js +58 -32
- package/dist/Schedule.js.map +1 -1
- package/dist/Scheduler.d.ts +9 -0
- package/dist/Scheduler.d.ts.map +1 -1
- package/dist/Scheduler.js +11 -0
- package/dist/Scheduler.js.map +1 -1
- package/dist/Schema.d.ts +1 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +3 -1
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +1 -1
- package/dist/SchemaAST.js.map +1 -1
- package/dist/Stdio.d.ts +6 -2
- package/dist/Stdio.d.ts.map +1 -1
- package/dist/Stdio.js +2 -2
- package/dist/Stdio.js.map +1 -1
- package/dist/Stream.d.ts +8 -4
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +8 -4
- package/dist/Stream.js.map +1 -1
- package/dist/Types.d.ts +1 -22
- package/dist/Types.d.ts.map +1 -1
- package/dist/index.d.ts +71 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +71 -3
- package/dist/index.js.map +1 -1
- package/dist/internal/effect.js +3 -1
- package/dist/internal/effect.js.map +1 -1
- package/dist/unstable/ai/LanguageModel.d.ts +12 -28
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +4 -18
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/ai/McpSchema.d.ts +20 -1
- package/dist/unstable/ai/McpSchema.d.ts.map +1 -1
- package/dist/unstable/ai/McpSchema.js +8 -0
- package/dist/unstable/ai/McpSchema.js.map +1 -1
- package/dist/unstable/ai/McpServer.d.ts +65 -12
- package/dist/unstable/ai/McpServer.d.ts.map +1 -1
- package/dist/unstable/ai/McpServer.js +159 -45
- package/dist/unstable/ai/McpServer.js.map +1 -1
- package/dist/unstable/ai/Toolkit.d.ts +1 -1
- package/dist/unstable/ai/Toolkit.d.ts.map +1 -1
- package/dist/unstable/ai/Toolkit.js +4 -11
- package/dist/unstable/ai/Toolkit.js.map +1 -1
- package/dist/unstable/ai/internal/codec-transformer.js +0 -5
- package/dist/unstable/ai/internal/codec-transformer.js.map +1 -1
- package/dist/unstable/cli/Prompt.js +35 -8
- package/dist/unstable/cli/Prompt.js.map +1 -1
- package/dist/unstable/cluster/Message.d.ts +5 -5
- package/dist/unstable/cluster/Reply.d.ts +3 -3
- package/dist/unstable/encoding/Msgpack.d.ts +1 -1
- package/dist/unstable/encoding/Ndjson.d.ts +1 -1
- package/dist/unstable/encoding/Sse.d.ts +1 -1
- package/dist/unstable/eventlog/EventJournal.d.ts +1 -1
- package/dist/unstable/eventlog/EventLogRemote.d.ts +1 -1
- package/dist/unstable/http/Cookies.d.ts +45 -1
- package/dist/unstable/http/Cookies.d.ts.map +1 -1
- package/dist/unstable/http/Cookies.js +22 -0
- package/dist/unstable/http/Cookies.js.map +1 -1
- package/dist/unstable/http/HttpBody.d.ts +1 -1
- package/dist/unstable/http/HttpClient.d.ts.map +1 -1
- package/dist/unstable/http/HttpClient.js +3 -7
- package/dist/unstable/http/HttpClient.js.map +1 -1
- package/dist/unstable/http/HttpClientError.d.ts +7 -7
- package/dist/unstable/http/HttpClientRequest.d.ts +5 -0
- package/dist/unstable/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/unstable/http/HttpClientRequest.js +21 -17
- package/dist/unstable/http/HttpClientRequest.js.map +1 -1
- package/dist/unstable/http/HttpEffect.d.ts +7 -0
- package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
- package/dist/unstable/http/HttpEffect.js +6 -0
- package/dist/unstable/http/HttpEffect.js.map +1 -1
- package/dist/unstable/http/HttpServerError.d.ts +6 -6
- package/dist/unstable/http/HttpServerRequest.d.ts +11 -0
- package/dist/unstable/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerRequest.js +291 -1
- package/dist/unstable/http/HttpServerRequest.js.map +1 -1
- package/dist/unstable/http/HttpServerResponse.d.ts +47 -1
- package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerResponse.js +227 -0
- package/dist/unstable/http/HttpServerResponse.js.map +1 -1
- package/dist/unstable/http/HttpStaticServer.d.ts +69 -0
- package/dist/unstable/http/HttpStaticServer.d.ts.map +1 -0
- package/dist/unstable/http/HttpStaticServer.js +353 -0
- package/dist/unstable/http/HttpStaticServer.js.map +1 -0
- package/dist/unstable/http/Multipart.d.ts +1 -1
- package/dist/unstable/http/UrlParams.d.ts +1 -1
- package/dist/unstable/http/index.d.ts +4 -0
- package/dist/unstable/http/index.d.ts.map +1 -1
- package/dist/unstable/http/index.js +4 -0
- package/dist/unstable/http/index.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiGroup.d.ts +1 -0
- package/dist/unstable/httpapi/HttpApiGroup.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiGroup.js.map +1 -1
- package/dist/unstable/persistence/KeyValueStore.d.ts +1 -1
- package/dist/unstable/reactivity/Atom.d.ts +7 -2
- package/dist/unstable/reactivity/Atom.d.ts.map +1 -1
- package/dist/unstable/reactivity/Atom.js +33 -15
- package/dist/unstable/reactivity/Atom.js.map +1 -1
- package/dist/unstable/reactivity/AtomHttpApi.d.ts +4 -6
- package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomHttpApi.js +39 -9
- package/dist/unstable/reactivity/AtomHttpApi.js.map +1 -1
- package/dist/unstable/reactivity/AtomRegistry.js +26 -2
- package/dist/unstable/reactivity/AtomRegistry.js.map +1 -1
- package/dist/unstable/reactivity/AtomRpc.d.ts +8 -8
- package/dist/unstable/reactivity/AtomRpc.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomRpc.js +46 -20
- package/dist/unstable/reactivity/AtomRpc.js.map +1 -1
- package/dist/unstable/rpc/Rpc.d.ts +1 -1
- package/dist/unstable/rpc/Rpc.d.ts.map +1 -1
- package/dist/unstable/rpc/Rpc.js.map +1 -1
- package/dist/unstable/rpc/RpcMiddleware.d.ts +5 -5
- package/dist/unstable/rpc/RpcMiddleware.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcMiddleware.js.map +1 -1
- package/dist/unstable/rpc/RpcServer.js +2 -2
- package/dist/unstable/rpc/RpcServer.js.map +1 -1
- package/dist/unstable/rpc/Utils.js +1 -1
- package/dist/unstable/rpc/Utils.js.map +1 -1
- package/dist/unstable/socket/SocketServer.d.ts +3 -3
- package/dist/unstable/sql/Migrator.d.ts +1 -1
- package/dist/unstable/sql/SqlResolver.js +2 -2
- package/dist/unstable/sql/SqlResolver.js.map +1 -1
- package/dist/unstable/workflow/Workflow.d.ts +1 -1
- package/package.json +1 -1
- package/src/Brand.ts +1 -1
- package/src/Data.ts +1 -2
- package/src/Effect.ts +300 -184
- package/src/Exit.ts +24 -12
- package/src/Fiber.ts +1 -0
- package/src/Function.ts +2 -10
- package/src/Newtype.ts +308 -0
- package/src/References.ts +6 -1
- package/src/RequestResolver.ts +20 -20
- package/src/Schedule.ts +142 -80
- package/src/Scheduler.ts +12 -0
- package/src/Schema.ts +4 -2
- package/src/SchemaAST.ts +1 -4
- package/src/Stdio.ts +8 -4
- package/src/Stream.ts +8 -4
- package/src/Types.ts +1 -23
- package/src/index.ts +72 -3
- package/src/internal/effect.ts +3 -0
- package/src/unstable/ai/LanguageModel.ts +16 -37
- package/src/unstable/ai/McpSchema.ts +14 -0
- package/src/unstable/ai/McpServer.ts +224 -53
- package/src/unstable/ai/Toolkit.ts +5 -14
- package/src/unstable/ai/internal/codec-transformer.ts +0 -7
- package/src/unstable/cli/Prompt.ts +31 -9
- package/src/unstable/http/Cookies.ts +84 -0
- package/src/unstable/http/HttpClient.ts +5 -6
- package/src/unstable/http/HttpClientRequest.ts +21 -17
- package/src/unstable/http/HttpEffect.ts +8 -0
- package/src/unstable/http/HttpServerRequest.ts +388 -1
- package/src/unstable/http/HttpServerResponse.ts +328 -1
- package/src/unstable/http/HttpStaticServer.ts +456 -0
- package/src/unstable/http/index.ts +5 -0
- package/src/unstable/httpapi/HttpApiGroup.ts +1 -0
- package/src/unstable/reactivity/Atom.ts +62 -35
- package/src/unstable/reactivity/AtomHttpApi.ts +45 -11
- package/src/unstable/reactivity/AtomRegistry.ts +30 -2
- package/src/unstable/reactivity/AtomRpc.ts +48 -17
- package/src/unstable/rpc/Rpc.ts +1 -3
- package/src/unstable/rpc/RpcMiddleware.ts +12 -6
- package/src/unstable/rpc/RpcServer.ts +2 -2
- package/src/unstable/rpc/Utils.ts +1 -1
- package/src/unstable/sql/SqlResolver.ts +2 -2
|
@@ -17,6 +17,8 @@ import * as Stream from "../../Stream.ts"
|
|
|
17
17
|
import * as Socket from "../socket/Socket.ts"
|
|
18
18
|
import * as Cookies from "./Cookies.ts"
|
|
19
19
|
import * as Headers from "./Headers.ts"
|
|
20
|
+
import * as HttpBody from "./HttpBody.ts"
|
|
21
|
+
import * as HttpClientRequest from "./HttpClientRequest.ts"
|
|
20
22
|
import * as HttpIncomingMessage from "./HttpIncomingMessage.ts"
|
|
21
23
|
import { hasBody, type HttpMethod } from "./HttpMethod.ts"
|
|
22
24
|
import { HttpServerError, type RequestError, RequestParseError } from "./HttpServerError.ts"
|
|
@@ -177,7 +179,8 @@ export const schemaBodyJson = <A, I, RD, RE>(
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
const isMultipart = (request: HttpServerRequest) =>
|
|
180
|
-
request.headers["content-type"]?.toLowerCase().includes("multipart/form-data")
|
|
182
|
+
request.headers["content-type"]?.toLowerCase().includes("multipart/form-data") === true ||
|
|
183
|
+
getFormDataBody(request) !== undefined
|
|
181
184
|
|
|
182
185
|
/**
|
|
183
186
|
* @since 4.0.0
|
|
@@ -276,6 +279,15 @@ export const schemaBodyFormJson = <A, I, RD, RE>(
|
|
|
276
279
|
}
|
|
277
280
|
}
|
|
278
281
|
|
|
282
|
+
/**
|
|
283
|
+
* @since 4.0.0
|
|
284
|
+
* @category conversions
|
|
285
|
+
*/
|
|
286
|
+
export const fromClientRequest = (request: HttpClientRequest.HttpClientRequest): HttpServerRequest => {
|
|
287
|
+
const url = HttpClientRequest.toUrl(request)?.toString() ?? request.url
|
|
288
|
+
return new ClientRequestImpl(request, url)
|
|
289
|
+
}
|
|
290
|
+
|
|
279
291
|
/**
|
|
280
292
|
* @since 4.0.0
|
|
281
293
|
* @category conversions
|
|
@@ -283,6 +295,40 @@ export const schemaBodyFormJson = <A, I, RD, RE>(
|
|
|
283
295
|
export const fromWeb = (request: globalThis.Request): HttpServerRequest =>
|
|
284
296
|
new ServerRequestImpl(request, removeHost(request.url))
|
|
285
297
|
|
|
298
|
+
/**
|
|
299
|
+
* @since 4.0.0
|
|
300
|
+
* @category conversions
|
|
301
|
+
*/
|
|
302
|
+
export const toClientRequest = (request: HttpServerRequest): HttpClientRequest.HttpClientRequest =>
|
|
303
|
+
HttpClientRequest.setUrl(
|
|
304
|
+
HttpClientRequest.makeWith(
|
|
305
|
+
request.method,
|
|
306
|
+
"",
|
|
307
|
+
UrlParams.empty,
|
|
308
|
+
undefined,
|
|
309
|
+
request.headers,
|
|
310
|
+
toClientBody(request)
|
|
311
|
+
),
|
|
312
|
+
toURL(request) ?? request.url
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
const toClientBody = (request: HttpServerRequest): HttpBody.HttpBody =>
|
|
316
|
+
hasBody(request.method)
|
|
317
|
+
? HttpBody.stream(
|
|
318
|
+
request.stream,
|
|
319
|
+
request.headers["content-type"],
|
|
320
|
+
parseContentLength(request.headers["content-length"])
|
|
321
|
+
)
|
|
322
|
+
: HttpBody.empty
|
|
323
|
+
|
|
324
|
+
const parseContentLength = (contentLength: string | undefined): number | undefined => {
|
|
325
|
+
if (contentLength === undefined) {
|
|
326
|
+
return undefined
|
|
327
|
+
}
|
|
328
|
+
const parsed = Number.parseInt(contentLength, 10)
|
|
329
|
+
return Number.isNaN(parsed) ? undefined : parsed
|
|
330
|
+
}
|
|
331
|
+
|
|
286
332
|
const removeHost = (url: string) => {
|
|
287
333
|
if (url[0] === "/") {
|
|
288
334
|
return url
|
|
@@ -486,6 +532,347 @@ class ServerRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
|
486
532
|
}
|
|
487
533
|
}
|
|
488
534
|
|
|
535
|
+
class ClientRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
536
|
+
readonly [TypeId]: typeof TypeId
|
|
537
|
+
readonly [HttpIncomingMessage.TypeId]: typeof HttpIncomingMessage.TypeId
|
|
538
|
+
readonly source: HttpClientRequest.HttpClientRequest
|
|
539
|
+
public originalUrl: string
|
|
540
|
+
public headersOverride?: Headers.Headers | undefined
|
|
541
|
+
private remoteAddressOverride?: string | undefined
|
|
542
|
+
private urlOverride?: string | undefined
|
|
543
|
+
|
|
544
|
+
constructor(
|
|
545
|
+
source: HttpClientRequest.HttpClientRequest,
|
|
546
|
+
originalUrl: string,
|
|
547
|
+
urlOverride?: string,
|
|
548
|
+
headersOverride?: Headers.Headers,
|
|
549
|
+
remoteAddressOverride?: string
|
|
550
|
+
) {
|
|
551
|
+
super()
|
|
552
|
+
this[TypeId] = TypeId
|
|
553
|
+
this[HttpIncomingMessage.TypeId] = HttpIncomingMessage.TypeId
|
|
554
|
+
this.source = source
|
|
555
|
+
this.originalUrl = originalUrl
|
|
556
|
+
this.urlOverride = urlOverride
|
|
557
|
+
this.headersOverride = headersOverride
|
|
558
|
+
this.remoteAddressOverride = remoteAddressOverride
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
toJSON(): unknown {
|
|
562
|
+
return HttpIncomingMessage.inspect(this, {
|
|
563
|
+
_id: "HttpServerRequest",
|
|
564
|
+
method: this.method,
|
|
565
|
+
url: this.originalUrl
|
|
566
|
+
})
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
modify(
|
|
570
|
+
options: {
|
|
571
|
+
readonly url?: string | undefined
|
|
572
|
+
readonly headers?: Headers.Headers | undefined
|
|
573
|
+
readonly remoteAddress?: string | undefined
|
|
574
|
+
}
|
|
575
|
+
) {
|
|
576
|
+
return new ClientRequestImpl(
|
|
577
|
+
this.source,
|
|
578
|
+
this.originalUrl,
|
|
579
|
+
options.url ?? this.url,
|
|
580
|
+
options.headers ?? this.headersOverride,
|
|
581
|
+
options.remoteAddress ?? this.remoteAddressOverride
|
|
582
|
+
)
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
get method(): HttpMethod {
|
|
586
|
+
return this.source.method
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
get url(): string {
|
|
590
|
+
return this.urlOverride ?? removeHost(this.originalUrl)
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
get remoteAddress(): string | undefined {
|
|
594
|
+
return this.remoteAddressOverride ? this.remoteAddressOverride : undefined
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
get headers(): Headers.Headers {
|
|
598
|
+
return this.headersOverride ??= this.source.headers
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
private cachedCookies: ReadonlyRecord<string, string> | undefined
|
|
602
|
+
get cookies() {
|
|
603
|
+
if (this.cachedCookies) {
|
|
604
|
+
return this.cachedCookies
|
|
605
|
+
}
|
|
606
|
+
return this.cachedCookies = Cookies.parseHeader(this.headers.cookie ?? "")
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
get stream(): Stream.Stream<Uint8Array, HttpServerError> {
|
|
610
|
+
const body = this.source.body
|
|
611
|
+
switch (body._tag) {
|
|
612
|
+
case "Empty": {
|
|
613
|
+
return Stream.empty
|
|
614
|
+
}
|
|
615
|
+
case "Uint8Array": {
|
|
616
|
+
return Stream.succeed(body.body)
|
|
617
|
+
}
|
|
618
|
+
case "Stream": {
|
|
619
|
+
return Stream.mapError(body.stream, (cause) => requestParseError(this, undefined, cause))
|
|
620
|
+
}
|
|
621
|
+
case "FormData": {
|
|
622
|
+
return streamFromReadable(this, new Response(body.formData).body)
|
|
623
|
+
}
|
|
624
|
+
case "Raw": {
|
|
625
|
+
return rawBodyStream(this, body.body)
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
private bytesEffect: Effect.Effect<Uint8Array, HttpServerError> | undefined
|
|
631
|
+
private get bytes(): Effect.Effect<Uint8Array, HttpServerError> {
|
|
632
|
+
if (this.bytesEffect) {
|
|
633
|
+
return this.bytesEffect
|
|
634
|
+
}
|
|
635
|
+
const body = this.source.body
|
|
636
|
+
let effect: Effect.Effect<Uint8Array, HttpServerError>
|
|
637
|
+
switch (body._tag) {
|
|
638
|
+
case "Empty": {
|
|
639
|
+
effect = Effect.succeed(new Uint8Array(0))
|
|
640
|
+
break
|
|
641
|
+
}
|
|
642
|
+
case "Uint8Array": {
|
|
643
|
+
effect = Effect.succeed(body.body)
|
|
644
|
+
break
|
|
645
|
+
}
|
|
646
|
+
case "FormData": {
|
|
647
|
+
effect = bytesFromBodyInit(this, body.formData)
|
|
648
|
+
break
|
|
649
|
+
}
|
|
650
|
+
case "Stream": {
|
|
651
|
+
effect = Stream.mkUint8Array(this.stream)
|
|
652
|
+
break
|
|
653
|
+
}
|
|
654
|
+
case "Raw": {
|
|
655
|
+
effect = rawBodyBytes(this, body.body)
|
|
656
|
+
break
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
this.bytesEffect = Effect.runSync(Effect.cached(effect))
|
|
660
|
+
return this.bytesEffect
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
get text(): Effect.Effect<string, HttpServerError> {
|
|
664
|
+
return Effect.map(this.bytes, (bytes) => textDecoder.decode(bytes))
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
get json(): Effect.Effect<unknown, HttpServerError> {
|
|
668
|
+
return Effect.flatMap(this.text, (text) =>
|
|
669
|
+
Effect.try({
|
|
670
|
+
try: () => text === "" ? null : JSON.parse(text) as unknown,
|
|
671
|
+
catch: (cause) => requestParseError(this, undefined, cause)
|
|
672
|
+
}))
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
get urlParamsBody(): Effect.Effect<UrlParams.UrlParams, HttpServerError> {
|
|
676
|
+
return Effect.flatMap(this.text, (_) =>
|
|
677
|
+
Effect.try({
|
|
678
|
+
try: () => UrlParams.fromInput(new URLSearchParams(_)),
|
|
679
|
+
catch: (cause) => requestParseError(this, undefined, cause)
|
|
680
|
+
}))
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
private multipartEffect:
|
|
684
|
+
| Effect.Effect<
|
|
685
|
+
Multipart.Persisted,
|
|
686
|
+
Multipart.MultipartError,
|
|
687
|
+
Scope.Scope | FileSystem.FileSystem | Path.Path
|
|
688
|
+
>
|
|
689
|
+
| undefined
|
|
690
|
+
get multipart(): Effect.Effect<
|
|
691
|
+
Multipart.Persisted,
|
|
692
|
+
Multipart.MultipartError,
|
|
693
|
+
Scope.Scope | FileSystem.FileSystem | Path.Path
|
|
694
|
+
> {
|
|
695
|
+
if (this.multipartEffect) {
|
|
696
|
+
return this.multipartEffect
|
|
697
|
+
}
|
|
698
|
+
this.multipartEffect = Effect.runSync(Effect.cached(
|
|
699
|
+
Multipart.toPersisted(this.multipartStream)
|
|
700
|
+
))
|
|
701
|
+
return this.multipartEffect
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
get multipartStream(): Stream.Stream<Multipart.Part, Multipart.MultipartError> {
|
|
705
|
+
const formData = this.source.body._tag === "FormData" && this.source.body.formData
|
|
706
|
+
if (formData) {
|
|
707
|
+
return Stream.fromIterable(formDataToParts(formData))
|
|
708
|
+
}
|
|
709
|
+
return Stream.pipeThroughChannel(
|
|
710
|
+
Stream.mapError(this.stream, (cause) => Multipart.MultipartError.fromReason("InternalError", cause)),
|
|
711
|
+
Multipart.makeChannel(this.headers)
|
|
712
|
+
)
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
get arrayBuffer(): Effect.Effect<ArrayBuffer, HttpServerError> {
|
|
716
|
+
return Effect.map(this.bytes, (bytes) => bytes.slice().buffer)
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
get upgrade(): Effect.Effect<Socket.Socket, HttpServerError> {
|
|
720
|
+
return Effect.fail(requestParseError(this, "Not an upgradeable ServerRequest"))
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const getFormDataBody = (request: HttpServerRequest): FormData | undefined => {
|
|
725
|
+
if (!HttpClientRequest.isHttpClientRequest(request.source)) {
|
|
726
|
+
return undefined
|
|
727
|
+
}
|
|
728
|
+
const body = request.source.body
|
|
729
|
+
if (body._tag === "FormData") {
|
|
730
|
+
return body.formData
|
|
731
|
+
}
|
|
732
|
+
if (body._tag === "Raw" && isFormData(body.body)) {
|
|
733
|
+
return body.body
|
|
734
|
+
}
|
|
735
|
+
return undefined
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const rawBodyStream = (request: HttpServerRequest, body: unknown): Stream.Stream<Uint8Array, HttpServerError> => {
|
|
739
|
+
if (body instanceof Request) {
|
|
740
|
+
return streamFromReadable(request, body.body)
|
|
741
|
+
}
|
|
742
|
+
if (isFormData(body)) {
|
|
743
|
+
return streamFromReadable(request, new Response(body).body)
|
|
744
|
+
}
|
|
745
|
+
if (isReadableStream(body)) {
|
|
746
|
+
return streamFromReadable(request, body)
|
|
747
|
+
}
|
|
748
|
+
return Stream.fail(requestParseError(request, "Unsupported body type"))
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const rawBodyBytes = (request: HttpServerRequest, body: unknown): Effect.Effect<Uint8Array, HttpServerError> => {
|
|
752
|
+
if (body instanceof Blob) {
|
|
753
|
+
return bytesFromBodyInit(request, body)
|
|
754
|
+
}
|
|
755
|
+
if (body instanceof Request) {
|
|
756
|
+
return Effect.tryPromise({
|
|
757
|
+
try: () => body.arrayBuffer().then((buffer) => new Uint8Array(buffer)),
|
|
758
|
+
catch: (cause) => requestParseError(request, undefined, cause)
|
|
759
|
+
})
|
|
760
|
+
}
|
|
761
|
+
return Effect.fail(requestParseError(request, "Unsupported body type"))
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
const bytesFromBodyInit = (request: HttpServerRequest, body: BodyInit): Effect.Effect<Uint8Array, HttpServerError> =>
|
|
765
|
+
Effect.tryPromise({
|
|
766
|
+
try: () => new Response(body).arrayBuffer().then((buffer) => new Uint8Array(buffer)),
|
|
767
|
+
catch: (cause) => requestParseError(request, undefined, cause)
|
|
768
|
+
})
|
|
769
|
+
|
|
770
|
+
const streamFromReadable = (
|
|
771
|
+
request: HttpServerRequest,
|
|
772
|
+
body: ReadableStream<Uint8Array> | null | undefined
|
|
773
|
+
): Stream.Stream<Uint8Array, HttpServerError> =>
|
|
774
|
+
body
|
|
775
|
+
? Stream.fromReadableStream({
|
|
776
|
+
evaluate: () => body,
|
|
777
|
+
onError: (cause) => requestParseError(request, undefined, cause)
|
|
778
|
+
})
|
|
779
|
+
: Stream.empty
|
|
780
|
+
|
|
781
|
+
const requestParseError = (
|
|
782
|
+
request: HttpServerRequest,
|
|
783
|
+
description?: string,
|
|
784
|
+
cause?: unknown
|
|
785
|
+
) =>
|
|
786
|
+
new HttpServerError({
|
|
787
|
+
reason: new RequestParseError({
|
|
788
|
+
request,
|
|
789
|
+
...(description === undefined ? undefined : { description }),
|
|
790
|
+
...(cause === undefined ? undefined : { cause })
|
|
791
|
+
})
|
|
792
|
+
})
|
|
793
|
+
|
|
794
|
+
const formDataToParts = (formData: FormData): Array<Multipart.Part> => {
|
|
795
|
+
const parts: Array<Multipart.Part> = []
|
|
796
|
+
for (const [key, value] of formData.entries()) {
|
|
797
|
+
parts.push(typeof value === "string" ? new MultipartFieldPart(key, value) : new MultipartFilePart(key, value))
|
|
798
|
+
}
|
|
799
|
+
return parts
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
class MultipartFieldPart extends Inspectable.Class implements Multipart.Field {
|
|
803
|
+
readonly [Multipart.TypeId]: typeof Multipart.TypeId
|
|
804
|
+
readonly _tag = "Field"
|
|
805
|
+
readonly contentType = "text/plain"
|
|
806
|
+
readonly key: string
|
|
807
|
+
readonly value: string
|
|
808
|
+
|
|
809
|
+
constructor(
|
|
810
|
+
key: string,
|
|
811
|
+
value: string
|
|
812
|
+
) {
|
|
813
|
+
super()
|
|
814
|
+
this[Multipart.TypeId] = Multipart.TypeId
|
|
815
|
+
this.key = key
|
|
816
|
+
this.value = value
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
toJSON(): unknown {
|
|
820
|
+
return {
|
|
821
|
+
_id: "@effect/platform/Multipart/Part",
|
|
822
|
+
_tag: "Field",
|
|
823
|
+
key: this.key,
|
|
824
|
+
contentType: this.contentType,
|
|
825
|
+
value: this.value
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
class MultipartFilePart extends Inspectable.Class implements Multipart.File {
|
|
831
|
+
readonly [Multipart.TypeId]: typeof Multipart.TypeId
|
|
832
|
+
readonly _tag = "File"
|
|
833
|
+
readonly key: string
|
|
834
|
+
readonly name: string
|
|
835
|
+
readonly contentType: string
|
|
836
|
+
readonly content: Stream.Stream<Uint8Array, Multipart.MultipartError>
|
|
837
|
+
readonly contentEffect: Effect.Effect<Uint8Array, Multipart.MultipartError>
|
|
838
|
+
|
|
839
|
+
constructor(
|
|
840
|
+
key: string,
|
|
841
|
+
file: File
|
|
842
|
+
) {
|
|
843
|
+
super()
|
|
844
|
+
this[Multipart.TypeId] = Multipart.TypeId
|
|
845
|
+
this.key = key
|
|
846
|
+
this.name = file.name
|
|
847
|
+
this.contentType = file.type
|
|
848
|
+
this.content = Stream.fromReadableStream({
|
|
849
|
+
evaluate: () => file.stream() as ReadableStream<Uint8Array>,
|
|
850
|
+
onError: (cause) => Multipart.MultipartError.fromReason("InternalError", cause)
|
|
851
|
+
})
|
|
852
|
+
this.contentEffect = Effect.tryPromise({
|
|
853
|
+
try: () => file.arrayBuffer().then((buffer) => new Uint8Array(buffer)),
|
|
854
|
+
catch: (cause) => Multipart.MultipartError.fromReason("InternalError", cause)
|
|
855
|
+
})
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
toJSON(): unknown {
|
|
859
|
+
return {
|
|
860
|
+
_id: "@effect/platform/Multipart/Part",
|
|
861
|
+
_tag: "File",
|
|
862
|
+
key: this.key,
|
|
863
|
+
name: this.name,
|
|
864
|
+
contentType: this.contentType
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const isReadableStream = (u: unknown): u is ReadableStream<Uint8Array> =>
|
|
870
|
+
typeof ReadableStream !== "undefined" && u instanceof ReadableStream
|
|
871
|
+
|
|
872
|
+
const isFormData = (u: unknown): u is FormData => typeof FormData !== "undefined" && u instanceof FormData
|
|
873
|
+
|
|
874
|
+
const textDecoder = new TextDecoder()
|
|
875
|
+
|
|
489
876
|
/**
|
|
490
877
|
* @since 4.0.0
|
|
491
878
|
* @category conversions
|