@effect/platform 0.44.6 → 0.45.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.
Files changed (32) hide show
  1. package/dist/cjs/Http/Client.js +11 -1
  2. package/dist/cjs/Http/Client.js.map +1 -1
  3. package/dist/cjs/Http/ClientResponse.js +60 -2
  4. package/dist/cjs/Http/ClientResponse.js.map +1 -1
  5. package/dist/cjs/Http/IncomingMessage.js +28 -1
  6. package/dist/cjs/Http/IncomingMessage.js.map +1 -1
  7. package/dist/cjs/internal/http/client.js +12 -7
  8. package/dist/cjs/internal/http/client.js.map +1 -1
  9. package/dist/cjs/internal/http/clientResponse.js +31 -1
  10. package/dist/cjs/internal/http/clientResponse.js.map +1 -1
  11. package/dist/dts/Http/Client.d.ts +18 -4
  12. package/dist/dts/Http/Client.d.ts.map +1 -1
  13. package/dist/dts/Http/ClientResponse.d.ts +66 -1
  14. package/dist/dts/Http/ClientResponse.d.ts.map +1 -1
  15. package/dist/dts/Http/IncomingMessage.d.ts +15 -0
  16. package/dist/dts/Http/IncomingMessage.d.ts.map +1 -1
  17. package/dist/esm/Http/Client.js +10 -0
  18. package/dist/esm/Http/Client.js.map +1 -1
  19. package/dist/esm/Http/ClientResponse.js +56 -1
  20. package/dist/esm/Http/ClientResponse.js.map +1 -1
  21. package/dist/esm/Http/IncomingMessage.js +24 -0
  22. package/dist/esm/Http/IncomingMessage.js.map +1 -1
  23. package/dist/esm/internal/http/client.js +11 -7
  24. package/dist/esm/internal/http/client.js.map +1 -1
  25. package/dist/esm/internal/http/clientResponse.js +22 -0
  26. package/dist/esm/internal/http/clientResponse.js.map +1 -1
  27. package/package.json +3 -3
  28. package/src/Http/Client.ts +37 -4
  29. package/src/Http/ClientResponse.ts +104 -1
  30. package/src/Http/IncomingMessage.ts +31 -0
  31. package/src/internal/http/client.ts +64 -39
  32. package/src/internal/http/clientResponse.ts +53 -0
@@ -4,10 +4,13 @@
4
4
  import type * as ParseResult from "@effect/schema/ParseResult"
5
5
  import type * as Schema from "@effect/schema/Schema"
6
6
  import type * as Effect from "effect/Effect"
7
+ import type * as Scope from "effect/Scope"
8
+ import type * as Stream from "effect/Stream"
7
9
  import * as internal from "../internal/http/clientResponse.js"
8
10
  import type * as Error from "./ClientError.js"
9
11
  import type * as ClientRequest from "./ClientRequest.js"
10
12
  import type * as IncomingMessage from "./IncomingMessage.js"
13
+ import type * as UrlParams from "./UrlParams.js"
11
14
 
12
15
  export {
13
16
  /**
@@ -15,6 +18,11 @@ export {
15
18
  * @category schema
16
19
  */
17
20
  schemaBodyJson,
21
+ /**
22
+ * @since 1.0.0
23
+ * @category schema
24
+ */
25
+ schemaBodyJsonEffect,
18
26
  /**
19
27
  * @since 1.0.0
20
28
  * @category schema
@@ -24,7 +32,17 @@ export {
24
32
  * @since 1.0.0
25
33
  * @category schema
26
34
  */
27
- schemaHeaders
35
+ schemaBodyUrlParamsEffect,
36
+ /**
37
+ * @since 1.0.0
38
+ * @category schema
39
+ */
40
+ schemaHeaders,
41
+ /**
42
+ * @since 1.0.0
43
+ * @category schema
44
+ */
45
+ schemaHeadersEffect
28
46
  } from "./IncomingMessage.js"
29
47
 
30
48
  /**
@@ -84,3 +102,88 @@ export const schemaNoBody: <
84
102
  A
85
103
  >(schema: Schema.Schema<A, I, R>) => (self: ClientResponse) => Effect.Effect<A, ParseResult.ParseError, R> =
86
104
  internal.schemaNoBody
105
+
106
+ /**
107
+ * @since 1.0.0
108
+ * @category accessors
109
+ */
110
+ export const arrayBuffer: <E, R>(
111
+ effect: Effect.Effect<ClientResponse, E, R>
112
+ ) => Effect.Effect<ArrayBuffer, Error.ResponseError | E, Exclude<R, Scope.Scope>> = internal.arrayBuffer
113
+
114
+ /**
115
+ * @since 1.0.0
116
+ * @category accessors
117
+ */
118
+ export const formData: <E, R>(
119
+ effect: Effect.Effect<ClientResponse, E, R>
120
+ ) => Effect.Effect<FormData, Error.ResponseError | E, Exclude<R, Scope.Scope>> = internal.formData
121
+
122
+ /**
123
+ * @since 1.0.0
124
+ * @category accessors
125
+ */
126
+ export const json: <E, R>(
127
+ effect: Effect.Effect<ClientResponse, E, R>
128
+ ) => Effect.Effect<unknown, Error.ResponseError | E, Exclude<R, Scope.Scope>> = internal.json
129
+
130
+ /**
131
+ * @since 1.0.0
132
+ * @category accessors
133
+ */
134
+ export const stream: <E, R>(
135
+ effect: Effect.Effect<ClientResponse, E, R>
136
+ ) => Stream.Stream<Uint8Array, Error.ResponseError | E, Exclude<R, Scope.Scope>> = internal.stream
137
+
138
+ /**
139
+ * @since 1.0.0
140
+ * @category accessors
141
+ */
142
+ export const text: <E, R>(
143
+ effect: Effect.Effect<ClientResponse, E, R>
144
+ ) => Effect.Effect<string, Error.ResponseError | E, Exclude<R, Scope.Scope>> = internal.text
145
+
146
+ /**
147
+ * @since 1.0.0
148
+ * @category accessors
149
+ */
150
+ export const urlParamsBody: <E, R>(
151
+ effect: Effect.Effect<ClientResponse, E, R>
152
+ ) => Effect.Effect<UrlParams.UrlParams, Error.ResponseError | E, Exclude<R, Scope.Scope>> = internal.urlParamsBody
153
+
154
+ /**
155
+ * @since 1.0.0
156
+ * @category schema
157
+ */
158
+ export const schemaJsonEffect: <
159
+ R,
160
+ I extends {
161
+ readonly status?: number | undefined
162
+ readonly headers?: Readonly<Record<string, string>> | undefined
163
+ readonly body?: unknown
164
+ },
165
+ A
166
+ >(
167
+ schema: Schema.Schema<A, I, R>
168
+ ) => <E, R2>(
169
+ effect: Effect.Effect<ClientResponse, E, R2>
170
+ ) => Effect.Effect<
171
+ A,
172
+ Error.ResponseError | E | ParseResult.ParseError,
173
+ Exclude<R, Scope.Scope> | Exclude<R2, Scope.Scope>
174
+ > = internal.schemaJsonEffect
175
+
176
+ /**
177
+ * @since 1.0.0
178
+ * @category schema
179
+ */
180
+ export const schemaNoBodyEffect: <
181
+ R,
182
+ I extends { readonly status?: number | undefined; readonly headers?: Readonly<Record<string, string>> | undefined },
183
+ A
184
+ >(
185
+ schema: Schema.Schema<A, I, R>
186
+ ) => <E, R2>(
187
+ effect: Effect.Effect<ClientResponse, E, R2>
188
+ ) => Effect.Effect<A, E | ParseResult.ParseError, Exclude<R, Scope.Scope> | Exclude<R2, Scope.Scope>> =
189
+ internal.schemaNoBodyEffect
@@ -52,6 +52,15 @@ export const schemaBodyJson = <A, I, R>(schema: Schema.Schema<A, I, R>) => {
52
52
  Effect.flatMap(self.json, parse)
53
53
  }
54
54
 
55
+ /**
56
+ * @since 1.0.0
57
+ * @category schema
58
+ */
59
+ export const schemaBodyJsonEffect = <A, I, R>(schema: Schema.Schema<A, I, R>) => {
60
+ const decode = schemaBodyJson(schema)
61
+ return <E, E2, R2>(effect: Effect.Effect<IncomingMessage<E>, E2, R2>) => Effect.scoped(Effect.flatMap(effect, decode))
62
+ }
63
+
55
64
  /**
56
65
  * @since 1.0.0
57
66
  * @category schema
@@ -64,6 +73,17 @@ export const schemaBodyUrlParams = <R, I extends Readonly<Record<string, string>
64
73
  Effect.flatMap(self.urlParamsBody, (_) => parse(Object.fromEntries(_)))
65
74
  }
66
75
 
76
+ /**
77
+ * @since 1.0.0
78
+ * @category schema
79
+ */
80
+ export const schemaBodyUrlParamsEffect = <R, I extends Readonly<Record<string, string>>, A>(
81
+ schema: Schema.Schema<A, I, R>
82
+ ) => {
83
+ const decode = schemaBodyUrlParams(schema)
84
+ return <E, E2, R2>(effect: Effect.Effect<IncomingMessage<E>, E2, R2>) => Effect.scoped(Effect.flatMap(effect, decode))
85
+ }
86
+
67
87
  /**
68
88
  * @since 1.0.0
69
89
  * @category schema
@@ -73,6 +93,17 @@ export const schemaHeaders = <R, I extends Readonly<Record<string, string>>, A>(
73
93
  return <E>(self: IncomingMessage<E>): Effect.Effect<A, ParseResult.ParseError, R> => parse(self.headers)
74
94
  }
75
95
 
96
+ /**
97
+ * @since 1.0.0
98
+ * @category schema
99
+ */
100
+ export const schemaHeadersEffect = <R, I extends Readonly<Record<string, string>>, A>(
101
+ schema: Schema.Schema<A, I, R>
102
+ ) => {
103
+ const decode = schemaHeaders(schema)
104
+ return <E, E2, R2>(effect: Effect.Effect<IncomingMessage<E>, E2, R2>) => Effect.scoped(Effect.flatMap(effect, decode))
105
+ }
106
+
76
107
  const SpanSchema = Schema.struct({
77
108
  traceId: Schema.string,
78
109
  spanId: Schema.string,
@@ -2,11 +2,12 @@ import type * as ParseResult from "@effect/schema/ParseResult"
2
2
  import * as Schema from "@effect/schema/Schema"
3
3
  import * as Context from "effect/Context"
4
4
  import * as Effect from "effect/Effect"
5
- import { dual } from "effect/Function"
5
+ import { dual, pipe } from "effect/Function"
6
6
  import * as Layer from "effect/Layer"
7
7
  import { pipeArguments } from "effect/Pipeable"
8
8
  import type * as Predicate from "effect/Predicate"
9
9
  import type * as Schedule from "effect/Schedule"
10
+ import type * as Scope from "effect/Scope"
10
11
  import * as Stream from "effect/Stream"
11
12
  import type * as Body from "../../Http/Body.js"
12
13
  import type * as Client from "../../Http/Client.js"
@@ -68,7 +69,7 @@ const addB3Headers = (req: ClientRequest.ClientRequest) =>
68
69
  export const makeDefault = (
69
70
  f: (
70
71
  request: ClientRequest.ClientRequest
71
- ) => Effect.Effect<ClientResponse.ClientResponse, Error.HttpClientError>
72
+ ) => Effect.Effect<ClientResponse.ClientResponse, Error.HttpClientError, Scope.Scope>
72
73
  ): Client.Client.Default => make(Effect.flatMap(f), addB3Headers)
73
74
 
74
75
  /** @internal */
@@ -91,25 +92,31 @@ export const fetch = (options?: RequestInit): Client.Client.Default =>
91
92
  const fetch = fetch_._tag === "Some" ? fetch_.value : globalThis.fetch
92
93
  const headers = new Headers(request.headers)
93
94
  const send = (body: BodyInit | undefined) =>
94
- Effect.map(
95
- Effect.tryPromise({
96
- try: (signal) =>
97
- fetch(url, {
98
- ...options,
99
- method: request.method,
100
- headers,
101
- body,
102
- duplex: request.body._tag === "Stream" ? "half" : undefined,
103
- signal
104
- } as any),
105
- catch: (_) =>
106
- internalError.requestError({
107
- request,
108
- reason: "Transport",
109
- error: _
110
- })
111
- }),
112
- (_) => internalResponse.fromWeb(request, _)
95
+ pipe(
96
+ Effect.acquireRelease(
97
+ Effect.sync(() => new AbortController()),
98
+ (controller) => Effect.sync(() => controller.abort())
99
+ ),
100
+ Effect.flatMap((controller) =>
101
+ Effect.tryPromise({
102
+ try: () =>
103
+ fetch(url, {
104
+ ...options,
105
+ method: request.method,
106
+ headers,
107
+ body,
108
+ duplex: request.body._tag === "Stream" ? "half" : undefined,
109
+ signal: controller.signal
110
+ } as any),
111
+ catch: (_) =>
112
+ internalError.requestError({
113
+ request,
114
+ reason: "Transport",
115
+ error: _
116
+ })
117
+ })
118
+ ),
119
+ Effect.map((_) => internalResponse.fromWeb(request, _))
113
120
  )
114
121
  if (Method.hasBody(request.method)) {
115
122
  return send(convertBody(request.body))
@@ -449,6 +456,22 @@ export const mapEffect = dual<
449
456
  ) => Client.Client<R | R2, E | E2, B>
450
457
  >(2, (self, f) => transformResponse(self, Effect.flatMap(f)))
451
458
 
459
+ /** @internal */
460
+ export const scoped = <R, E, A>(
461
+ self: Client.Client<R, E, A>
462
+ ): Client.Client<Exclude<R, Scope.Scope>, E, A> => transformResponse(self, Effect.scoped)
463
+
464
+ /** @internal */
465
+ export const mapEffectScoped = dual<
466
+ <A, R2, E2, B>(
467
+ f: (a: A) => Effect.Effect<B, E2, R2>
468
+ ) => <R, E>(self: Client.Client<R, E, A>) => Client.Client<Exclude<R | R2, Scope.Scope>, E | E2, B>,
469
+ <R, E, A, R2, E2, B>(
470
+ self: Client.Client<R, E, A>,
471
+ f: (a: A) => Effect.Effect<B, E2, R2>
472
+ ) => Client.Client<Exclude<R | R2, Scope.Scope>, E | E2, B>
473
+ >(2, (self, f) => scoped(mapEffect(self, f)))
474
+
452
475
  /** @internal */
453
476
  export const mapRequest = dual<
454
477
  (
@@ -532,7 +555,7 @@ export const schemaFunction = dual<
532
555
  request: ClientRequest.ClientRequest
533
556
  ) => (
534
557
  a: SA
535
- ) => Effect.Effect<A, E | ParseResult.ParseError | Error.RequestError, SR | R>,
558
+ ) => Effect.Effect<A, E | ParseResult.ParseError | Error.RequestError, Exclude<SR | R, Scope.Scope>>,
536
559
  <R, E, A, SA, SI, SR>(
537
560
  self: Client.Client<R, E, A>,
538
561
  schema: Schema.Schema<SA, SI, SR>
@@ -540,27 +563,29 @@ export const schemaFunction = dual<
540
563
  request: ClientRequest.ClientRequest
541
564
  ) => (
542
565
  a: SA
543
- ) => Effect.Effect<A, E | ParseResult.ParseError | Error.RequestError, SR | R>
566
+ ) => Effect.Effect<A, E | ParseResult.ParseError | Error.RequestError, Exclude<SR | R, Scope.Scope>>
544
567
  >(2, (self, schema) => {
545
568
  const encode = Schema.encode(schema)
546
569
  return (request) => (a) =>
547
- Effect.flatMap(
548
- Effect.tryMap(encode(a), {
549
- try: (body) => new TextEncoder().encode(JSON.stringify(body)),
550
- catch: (error) =>
551
- internalError.requestError({
552
- request,
553
- reason: "Encode",
554
- error
555
- })
556
- }),
557
- (body) =>
558
- self(
559
- internalRequest.setBody(
560
- request,
561
- internalBody.uint8Array(body, "application/json")
570
+ Effect.scoped(
571
+ Effect.flatMap(
572
+ Effect.tryMap(encode(a), {
573
+ try: (body) => new TextEncoder().encode(JSON.stringify(body)),
574
+ catch: (error) =>
575
+ internalError.requestError({
576
+ request,
577
+ reason: "Encode",
578
+ error
579
+ })
580
+ }),
581
+ (body) =>
582
+ self(
583
+ internalRequest.setBody(
584
+ request,
585
+ internalBody.uint8Array(body, "application/json")
586
+ )
562
587
  )
563
- )
588
+ )
564
589
  )
565
590
  })
566
591
 
@@ -170,3 +170,56 @@ export const schemaNoBody = <
170
170
  headers: self.headers
171
171
  })
172
172
  }
173
+
174
+ /** @internal */
175
+ export const arrayBuffer = <E, R>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R>) =>
176
+ Effect.scoped(Effect.flatMap(effect, (_) => _.arrayBuffer))
177
+
178
+ /** @internal */
179
+ export const text = <E, R>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R>) =>
180
+ Effect.scoped(Effect.flatMap(effect, (_) => _.text))
181
+
182
+ /** @internal */
183
+ export const json = <E, R>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R>) =>
184
+ Effect.scoped(Effect.flatMap(effect, (_) => _.json))
185
+
186
+ /** @internal */
187
+ export const urlParamsBody = <E, R>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R>) =>
188
+ Effect.scoped(Effect.flatMap(effect, (_) => _.urlParamsBody))
189
+
190
+ /** @internal */
191
+ export const formData = <E, R>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R>) =>
192
+ Effect.scoped(Effect.flatMap(effect, (_) => _.formData))
193
+
194
+ /** @internal */
195
+ export const stream = <E, R>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R>) =>
196
+ Stream.unwrapScoped(Effect.map(effect, (_) => _.stream))
197
+
198
+ /** @internal */
199
+ export const schemaJsonEffect = <
200
+ R,
201
+ I extends {
202
+ readonly status?: number | undefined
203
+ readonly headers?: Readonly<Record<string, string>> | undefined
204
+ readonly body?: unknown | undefined
205
+ },
206
+ A
207
+ >(schema: Schema.Schema<A, I, R>) => {
208
+ const decode = schemaJson(schema)
209
+ return <E, R2>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R2>) =>
210
+ Effect.scoped(Effect.flatMap(effect, decode))
211
+ }
212
+
213
+ /** @internal */
214
+ export const schemaNoBodyEffect = <
215
+ R,
216
+ I extends {
217
+ readonly status?: number | undefined
218
+ readonly headers?: Readonly<Record<string, string>> | undefined
219
+ },
220
+ A
221
+ >(schema: Schema.Schema<A, I, R>) => {
222
+ const decode = schemaNoBody(schema)
223
+ return <E, R2>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R2>) =>
224
+ Effect.scoped(Effect.flatMap(effect, decode))
225
+ }