@effect/platform 0.84.11 → 0.85.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/README.md +4 -7
- package/dist/cjs/HttpApi.js +1 -1
- package/dist/cjs/HttpApi.js.map +1 -1
- package/dist/cjs/HttpApiBuilder.js +15 -8
- package/dist/cjs/HttpApiBuilder.js.map +1 -1
- package/dist/cjs/HttpApiEndpoint.js.map +1 -1
- package/dist/cjs/HttpApiSchema.js +28 -1
- package/dist/cjs/HttpApiSchema.js.map +1 -1
- package/dist/cjs/Multipart.js +5 -1
- package/dist/cjs/Multipart.js.map +1 -1
- package/dist/cjs/internal/multipart.js +24 -1
- package/dist/cjs/internal/multipart.js.map +1 -1
- package/dist/dts/HttpApi.d.ts.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts +2 -2
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/HttpApiEndpoint.d.ts +26 -6
- package/dist/dts/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/dts/HttpApiSchema.d.ts +31 -0
- package/dist/dts/HttpApiSchema.d.ts.map +1 -1
- package/dist/dts/Multipart.d.ts +5 -0
- package/dist/dts/Multipart.d.ts.map +1 -1
- package/dist/esm/HttpApi.js +1 -1
- package/dist/esm/HttpApi.js.map +1 -1
- package/dist/esm/HttpApiBuilder.js +16 -9
- package/dist/esm/HttpApiBuilder.js.map +1 -1
- package/dist/esm/HttpApiEndpoint.js.map +1 -1
- package/dist/esm/HttpApiSchema.js +25 -0
- package/dist/esm/HttpApiSchema.js.map +1 -1
- package/dist/esm/Multipart.js +4 -0
- package/dist/esm/Multipart.js.map +1 -1
- package/dist/esm/internal/multipart.js +23 -0
- package/dist/esm/internal/multipart.js.map +1 -1
- package/package.json +1 -1
- package/src/HttpApi.ts +3 -1
- package/src/HttpApiBuilder.ts +19 -13
- package/src/HttpApiEndpoint.ts +38 -7
- package/src/HttpApiSchema.ts +51 -0
- package/src/Multipart.ts +12 -0
- package/src/internal/multipart.ts +32 -0
package/src/HttpApiEndpoint.ts
CHANGED
|
@@ -8,12 +8,15 @@ import * as Option from "effect/Option"
|
|
|
8
8
|
import { type Pipeable, pipeArguments } from "effect/Pipeable"
|
|
9
9
|
import * as Predicate from "effect/Predicate"
|
|
10
10
|
import * as Schema from "effect/Schema"
|
|
11
|
+
import type * as Stream from "effect/Stream"
|
|
11
12
|
import type * as Types from "effect/Types"
|
|
12
13
|
import type * as HttpApiMiddleware from "./HttpApiMiddleware.js"
|
|
13
14
|
import * as HttpApiSchema from "./HttpApiSchema.js"
|
|
14
15
|
import type { HttpMethod } from "./HttpMethod.js"
|
|
15
16
|
import * as HttpRouter from "./HttpRouter.js"
|
|
17
|
+
import type { HttpServerRequest } from "./HttpServerRequest.js"
|
|
16
18
|
import type { HttpServerResponse } from "./HttpServerResponse.js"
|
|
19
|
+
import type * as Multipart from "./Multipart.js"
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* @since 1.0.0
|
|
@@ -402,8 +405,34 @@ export declare namespace HttpApiEndpoint {
|
|
|
402
405
|
> ?
|
|
403
406
|
& ([_Path] extends [never] ? {} : { readonly path: _Path })
|
|
404
407
|
& ([_UrlParams] extends [never] ? {} : { readonly urlParams: _UrlParams })
|
|
405
|
-
& ([_Payload] extends [never] ? {}
|
|
408
|
+
& ([_Payload] extends [never] ? {}
|
|
409
|
+
: _Payload extends Brand<HttpApiSchema.MultipartStreamTypeId> ?
|
|
410
|
+
{ readonly payload: Stream.Stream<Multipart.Part, Multipart.MultipartError> }
|
|
411
|
+
: { readonly payload: _Payload })
|
|
406
412
|
& ([_Headers] extends [never] ? {} : { readonly headers: _Headers })
|
|
413
|
+
& { readonly request: HttpServerRequest }
|
|
414
|
+
: {}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* @since 1.0.0
|
|
418
|
+
* @category models
|
|
419
|
+
*/
|
|
420
|
+
export type RequestRaw<Endpoint extends Any> = Endpoint extends HttpApiEndpoint<
|
|
421
|
+
infer _Name,
|
|
422
|
+
infer _Method,
|
|
423
|
+
infer _Path,
|
|
424
|
+
infer _UrlParams,
|
|
425
|
+
infer _Payload,
|
|
426
|
+
infer _Headers,
|
|
427
|
+
infer _Success,
|
|
428
|
+
infer _Error,
|
|
429
|
+
infer _R,
|
|
430
|
+
infer _RE
|
|
431
|
+
> ?
|
|
432
|
+
& ([_Path] extends [never] ? {} : { readonly path: _Path })
|
|
433
|
+
& ([_UrlParams] extends [never] ? {} : { readonly urlParams: _UrlParams })
|
|
434
|
+
& ([_Headers] extends [never] ? {} : { readonly headers: _Headers })
|
|
435
|
+
& { readonly request: HttpServerRequest }
|
|
407
436
|
: {}
|
|
408
437
|
|
|
409
438
|
/**
|
|
@@ -416,7 +445,9 @@ export declare namespace HttpApiEndpoint {
|
|
|
416
445
|
& ([Headers] extends [never] ? {} : { readonly headers: Headers })
|
|
417
446
|
& ([Payload] extends [never] ? {}
|
|
418
447
|
: Payload extends infer P ?
|
|
419
|
-
P extends Brand<HttpApiSchema.MultipartTypeId>
|
|
448
|
+
P extends Brand<HttpApiSchema.MultipartTypeId> | Brand<HttpApiSchema.MultipartStreamTypeId>
|
|
449
|
+
? { readonly payload: FormData }
|
|
450
|
+
: { readonly payload: P }
|
|
420
451
|
: { readonly payload: Payload })
|
|
421
452
|
) extends infer Req ? keyof Req extends never ? (void | { readonly withResponse?: WithResponse }) :
|
|
422
453
|
Req & { readonly withResponse?: WithResponse } :
|
|
@@ -464,15 +495,15 @@ export declare namespace HttpApiEndpoint {
|
|
|
464
495
|
*/
|
|
465
496
|
export type Handler<Endpoint extends Any, E, R> = (
|
|
466
497
|
request: Types.Simplify<Request<Endpoint>>
|
|
467
|
-
) => Effect<Success<Endpoint
|
|
498
|
+
) => Effect<Success<Endpoint> | HttpServerResponse, Error<Endpoint> | E, R>
|
|
468
499
|
|
|
469
500
|
/**
|
|
470
501
|
* @since 1.0.0
|
|
471
502
|
* @category models
|
|
472
503
|
*/
|
|
473
|
-
export type
|
|
474
|
-
request: Types.Simplify<
|
|
475
|
-
) => Effect<HttpServerResponse, Error<Endpoint> | E, R>
|
|
504
|
+
export type HandlerRaw<Endpoint extends Any, E, R> = (
|
|
505
|
+
request: Types.Simplify<RequestRaw<Endpoint>>
|
|
506
|
+
) => Effect<Success<Endpoint> | HttpServerResponse, Error<Endpoint> | E, R>
|
|
476
507
|
|
|
477
508
|
/**
|
|
478
509
|
* @since 1.0.0
|
|
@@ -500,7 +531,7 @@ export declare namespace HttpApiEndpoint {
|
|
|
500
531
|
* @since 1.0.0
|
|
501
532
|
* @category models
|
|
502
533
|
*/
|
|
503
|
-
export type
|
|
534
|
+
export type HandlerRawWithName<Endpoints extends Any, Name extends string, E, R> = HandlerRaw<
|
|
504
535
|
WithName<Endpoints, Name>,
|
|
505
536
|
E,
|
|
506
537
|
R
|
package/src/HttpApiSchema.ts
CHANGED
|
@@ -20,6 +20,14 @@ export const AnnotationMultipart: unique symbol = Symbol.for(
|
|
|
20
20
|
"@effect/platform/HttpApiSchema/AnnotationMultipart"
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @since 1.0.0
|
|
25
|
+
* @category annotations
|
|
26
|
+
*/
|
|
27
|
+
export const AnnotationMultipartStream: unique symbol = Symbol.for(
|
|
28
|
+
"@effect/platform/HttpApiSchema/AnnotationMultipartStream"
|
|
29
|
+
)
|
|
30
|
+
|
|
23
31
|
/**
|
|
24
32
|
* @since 1.0.0
|
|
25
33
|
* @category annotations
|
|
@@ -69,6 +77,9 @@ export const extractAnnotations = (ast: AST.Annotations): AST.Annotations => {
|
|
|
69
77
|
if (AnnotationMultipart in ast) {
|
|
70
78
|
result[AnnotationMultipart] = ast[AnnotationMultipart]
|
|
71
79
|
}
|
|
80
|
+
if (AnnotationMultipartStream in ast) {
|
|
81
|
+
result[AnnotationMultipartStream] = ast[AnnotationMultipartStream]
|
|
82
|
+
}
|
|
72
83
|
return result
|
|
73
84
|
}
|
|
74
85
|
|
|
@@ -102,6 +113,13 @@ export const getEmptyDecodeable = (ast: AST.AST): boolean =>
|
|
|
102
113
|
*/
|
|
103
114
|
export const getMultipart = (ast: AST.AST): boolean => getAnnotation<boolean>(ast, AnnotationMultipart) ?? false
|
|
104
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @since 1.0.0
|
|
118
|
+
* @category annotations
|
|
119
|
+
*/
|
|
120
|
+
export const getMultipartStream = (ast: AST.AST): boolean =>
|
|
121
|
+
getAnnotation<boolean>(ast, AnnotationMultipartStream) ?? false
|
|
122
|
+
|
|
105
123
|
const encodingJson: Encoding = {
|
|
106
124
|
kind: "Json",
|
|
107
125
|
contentType: "application/json"
|
|
@@ -411,6 +429,39 @@ export const Multipart = <S extends Schema.Schema.Any>(self: S): Multipart<S> =>
|
|
|
411
429
|
[AnnotationMultipart]: true
|
|
412
430
|
}) as any
|
|
413
431
|
|
|
432
|
+
/**
|
|
433
|
+
* @since 1.0.0
|
|
434
|
+
* @category multipart
|
|
435
|
+
*/
|
|
436
|
+
export const MultipartStreamTypeId: unique symbol = Symbol.for("@effect/platform/HttpApiSchema/MultipartStream")
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @since 1.0.0
|
|
440
|
+
* @category multipart
|
|
441
|
+
*/
|
|
442
|
+
export type MultipartStreamTypeId = typeof MultipartStreamTypeId
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* @since 1.0.0
|
|
446
|
+
* @category multipart
|
|
447
|
+
*/
|
|
448
|
+
export interface MultipartStream<S extends Schema.Schema.Any> extends
|
|
449
|
+
Schema.Schema<
|
|
450
|
+
Schema.Schema.Type<S> & Brand<MultipartStreamTypeId>,
|
|
451
|
+
Schema.Schema.Encoded<S>,
|
|
452
|
+
Schema.Schema.Context<S>
|
|
453
|
+
>
|
|
454
|
+
{}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* @since 1.0.0
|
|
458
|
+
* @category multipart
|
|
459
|
+
*/
|
|
460
|
+
export const MultipartStream = <S extends Schema.Schema.Any>(self: S): MultipartStream<S> =>
|
|
461
|
+
self.annotations({
|
|
462
|
+
[AnnotationMultipartStream]: true
|
|
463
|
+
}) as any
|
|
464
|
+
|
|
414
465
|
const defaultContentType = (encoding: Encoding["kind"]) => {
|
|
415
466
|
switch (encoding) {
|
|
416
467
|
case "Json": {
|
package/src/Multipart.ts
CHANGED
|
@@ -83,6 +83,7 @@ export interface File extends Part.Proto {
|
|
|
83
83
|
readonly name: string
|
|
84
84
|
readonly contentType: string
|
|
85
85
|
readonly content: Stream.Stream<Uint8Array, MultipartError>
|
|
86
|
+
readonly contentEffect: Effect.Effect<Uint8Array, MultipartError>
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
/**
|
|
@@ -310,3 +311,14 @@ export const toPersisted: (
|
|
|
310
311
|
stream: Stream.Stream<Part, MultipartError>,
|
|
311
312
|
writeFile?: (path: string, file: File) => Effect.Effect<void, MultipartError, FileSystem.FileSystem>
|
|
312
313
|
) => Effect.Effect<Persisted, MultipartError, FileSystem.FileSystem | Path.Path | Scope.Scope> = internal.toPersisted
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @since 1.0.0
|
|
317
|
+
*/
|
|
318
|
+
export const collectUint8Array: Channel.Channel<
|
|
319
|
+
never,
|
|
320
|
+
Chunk.Chunk<Uint8Array>,
|
|
321
|
+
unknown,
|
|
322
|
+
unknown,
|
|
323
|
+
Uint8Array
|
|
324
|
+
> = internal.collectUint8Array
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Cause } from "effect/Cause"
|
|
1
2
|
import * as Channel from "effect/Channel"
|
|
2
3
|
import * as Chunk from "effect/Chunk"
|
|
3
4
|
import * as Effect from "effect/Effect"
|
|
@@ -355,6 +356,7 @@ class FileImpl extends PartBase implements Multipart.File {
|
|
|
355
356
|
readonly name: string
|
|
356
357
|
readonly contentType: string
|
|
357
358
|
readonly content: Stream.Stream<Uint8Array, Multipart.MultipartError>
|
|
359
|
+
readonly contentEffect: Effect.Effect<Uint8Array, Multipart.MultipartError>
|
|
358
360
|
|
|
359
361
|
constructor(
|
|
360
362
|
info: MP.PartInfo,
|
|
@@ -365,6 +367,11 @@ class FileImpl extends PartBase implements Multipart.File {
|
|
|
365
367
|
this.name = info.filename ?? info.name
|
|
366
368
|
this.contentType = info.contentType
|
|
367
369
|
this.content = Stream.fromChannel(channel)
|
|
370
|
+
this.contentEffect = channel.pipe(
|
|
371
|
+
Channel.pipeTo(collectUint8Array),
|
|
372
|
+
Channel.run,
|
|
373
|
+
Effect.mapError((cause) => new MultipartError({ reason: "InternalError", cause }))
|
|
374
|
+
)
|
|
368
375
|
}
|
|
369
376
|
|
|
370
377
|
toJSON(): unknown {
|
|
@@ -388,6 +395,31 @@ const defaultWriteFile = (path: string, file: Multipart.File) =>
|
|
|
388
395
|
)
|
|
389
396
|
)
|
|
390
397
|
|
|
398
|
+
/** @internal */
|
|
399
|
+
export const collectUint8Array = Channel.suspend(() => {
|
|
400
|
+
let accumulator = new Uint8Array(0)
|
|
401
|
+
const loop: Channel.Channel<
|
|
402
|
+
never,
|
|
403
|
+
Chunk.Chunk<Uint8Array>,
|
|
404
|
+
unknown,
|
|
405
|
+
unknown,
|
|
406
|
+
Uint8Array
|
|
407
|
+
> = Channel.readWithCause({
|
|
408
|
+
onInput(chunk: Chunk.Chunk<Uint8Array>) {
|
|
409
|
+
for (const element of chunk) {
|
|
410
|
+
const newAccumulator = new Uint8Array(accumulator.length + element.length)
|
|
411
|
+
newAccumulator.set(accumulator, 0)
|
|
412
|
+
newAccumulator.set(element, accumulator.length)
|
|
413
|
+
accumulator = newAccumulator
|
|
414
|
+
}
|
|
415
|
+
return loop
|
|
416
|
+
},
|
|
417
|
+
onFailure: (cause: Cause<unknown>) => Channel.failCause(cause),
|
|
418
|
+
onDone: () => Channel.succeed(accumulator)
|
|
419
|
+
})
|
|
420
|
+
return loop
|
|
421
|
+
})
|
|
422
|
+
|
|
391
423
|
/** @internal */
|
|
392
424
|
export const toPersisted = (
|
|
393
425
|
stream: Stream.Stream<Multipart.Part, Multipart.MultipartError>,
|