@effect/platform 0.11.4 → 0.12.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 (201) hide show
  1. package/Command.d.ts +3 -2
  2. package/Command.d.ts.map +1 -1
  3. package/Command.js.map +1 -1
  4. package/FileSystem.d.ts +16 -9
  5. package/FileSystem.d.ts.map +1 -1
  6. package/FileSystem.js.map +1 -1
  7. package/Http/App.d.ts +18 -0
  8. package/Http/App.d.ts.map +1 -0
  9. package/Http/App.js +6 -0
  10. package/Http/App.js.map +1 -0
  11. package/Http/Body.d.ts +37 -14
  12. package/Http/Body.d.ts.map +1 -1
  13. package/Http/Body.js +17 -5
  14. package/Http/Body.js.map +1 -1
  15. package/Http/Client.d.ts +8 -2
  16. package/Http/Client.d.ts.map +1 -1
  17. package/Http/Client.js +10 -4
  18. package/Http/Client.js.map +1 -1
  19. package/Http/ClientRequest.d.ts +44 -1
  20. package/Http/ClientRequest.d.ts.map +1 -1
  21. package/Http/ClientRequest.js +21 -3
  22. package/Http/ClientRequest.js.map +1 -1
  23. package/Http/ClientResponse.d.ts +13 -1
  24. package/Http/ClientResponse.d.ts.map +1 -1
  25. package/Http/ClientResponse.js +14 -2
  26. package/Http/ClientResponse.js.map +1 -1
  27. package/Http/FormData.d.ts +97 -4
  28. package/Http/FormData.d.ts.map +1 -1
  29. package/Http/FormData.js +77 -2
  30. package/Http/FormData.js.map +1 -1
  31. package/Http/Headers.d.ts +29 -3
  32. package/Http/Headers.d.ts.map +1 -1
  33. package/Http/Headers.js +13 -1
  34. package/Http/Headers.js.map +1 -1
  35. package/Http/IncomingMessage.d.ts +26 -5
  36. package/Http/IncomingMessage.d.ts.map +1 -1
  37. package/Http/IncomingMessage.js +38 -3
  38. package/Http/IncomingMessage.js.map +1 -1
  39. package/Http/Middleware.d.ts +56 -0
  40. package/Http/Middleware.d.ts.map +1 -0
  41. package/Http/Middleware.js +46 -0
  42. package/Http/Middleware.js.map +1 -0
  43. package/Http/Router.d.ts +221 -0
  44. package/Http/Router.d.ts.map +1 -0
  45. package/Http/Router.js +148 -0
  46. package/Http/Router.js.map +1 -0
  47. package/Http/Server.d.ts +85 -0
  48. package/Http/Server.d.ts.map +1 -0
  49. package/Http/Server.js +34 -0
  50. package/Http/Server.js.map +1 -0
  51. package/Http/ServerError.d.ts +96 -0
  52. package/Http/ServerError.d.ts.map +1 -0
  53. package/Http/ServerError.js +40 -0
  54. package/Http/ServerError.js.map +1 -0
  55. package/Http/ServerRequest.d.ts +82 -0
  56. package/Http/ServerRequest.d.ts.map +1 -0
  57. package/Http/ServerRequest.js +66 -0
  58. package/Http/ServerRequest.js.map +1 -0
  59. package/Http/ServerResponse.d.ts +168 -0
  60. package/Http/ServerResponse.d.ts.map +1 -0
  61. package/Http/ServerResponse.js +116 -0
  62. package/Http/ServerResponse.js.map +1 -0
  63. package/Http/UrlParams.d.ts +20 -5
  64. package/Http/UrlParams.d.ts.map +1 -1
  65. package/Http/UrlParams.js.map +1 -1
  66. package/HttpServer.d.ts +44 -0
  67. package/HttpServer.d.ts.map +1 -0
  68. package/HttpServer.js +29 -0
  69. package/HttpServer.js.map +1 -0
  70. package/internal/command.js +9 -2
  71. package/internal/command.js.map +1 -1
  72. package/internal/fileSystem.js +15 -11
  73. package/internal/fileSystem.js.map +1 -1
  74. package/internal/http/body.js +28 -28
  75. package/internal/http/body.js.map +1 -1
  76. package/internal/http/client.d.ts.map +1 -1
  77. package/internal/http/client.js +41 -27
  78. package/internal/http/client.js.map +1 -1
  79. package/internal/http/clientRequest.js +22 -6
  80. package/internal/http/clientRequest.js.map +1 -1
  81. package/internal/http/clientResponse.js +15 -12
  82. package/internal/http/clientResponse.js.map +1 -1
  83. package/internal/http/formData.d.ts +8 -0
  84. package/internal/http/formData.d.ts.map +1 -0
  85. package/internal/http/formData.js +88 -0
  86. package/internal/http/formData.js.map +1 -0
  87. package/internal/http/middleware.d.ts +2 -0
  88. package/internal/http/middleware.d.ts.map +1 -0
  89. package/internal/http/middleware.js +43 -0
  90. package/internal/http/middleware.js.map +1 -0
  91. package/internal/http/router.d.ts +2 -0
  92. package/internal/http/router.d.ts.map +1 -0
  93. package/internal/http/router.js +187 -0
  94. package/internal/http/router.js.map +1 -0
  95. package/internal/http/server.d.ts +2 -0
  96. package/internal/http/server.d.ts.map +1 -0
  97. package/internal/http/server.js +30 -0
  98. package/internal/http/server.js.map +1 -0
  99. package/internal/http/serverError.d.ts +2 -0
  100. package/internal/http/serverError.d.ts.map +1 -0
  101. package/internal/http/serverError.js +30 -0
  102. package/internal/http/serverError.js.map +1 -0
  103. package/internal/http/serverRequest.d.ts +2 -0
  104. package/internal/http/serverRequest.d.ts.map +1 -0
  105. package/internal/http/serverRequest.js +57 -0
  106. package/internal/http/serverRequest.js.map +1 -0
  107. package/internal/http/serverResponse.d.ts +2 -0
  108. package/internal/http/serverResponse.d.ts.map +1 -0
  109. package/internal/http/serverResponse.js +109 -0
  110. package/internal/http/serverResponse.js.map +1 -0
  111. package/mjs/Command.mjs.map +1 -1
  112. package/mjs/FileSystem.mjs.map +1 -1
  113. package/mjs/Http/App.mjs +2 -0
  114. package/mjs/Http/App.mjs.map +1 -0
  115. package/mjs/Http/Body.mjs +12 -2
  116. package/mjs/Http/Body.mjs.map +1 -1
  117. package/mjs/Http/Client.mjs +6 -1
  118. package/mjs/Http/Client.mjs.map +1 -1
  119. package/mjs/Http/ClientRequest.mjs +16 -1
  120. package/mjs/Http/ClientRequest.mjs.map +1 -1
  121. package/mjs/Http/ClientResponse.mjs +11 -1
  122. package/mjs/Http/ClientResponse.mjs.map +1 -1
  123. package/mjs/Http/FormData.mjs +62 -1
  124. package/mjs/Http/FormData.mjs.map +1 -1
  125. package/mjs/Http/Headers.mjs +10 -0
  126. package/mjs/Http/Headers.mjs.map +1 -1
  127. package/mjs/Http/IncomingMessage.mjs +32 -1
  128. package/mjs/Http/IncomingMessage.mjs.map +1 -1
  129. package/mjs/Http/Middleware.mjs +32 -0
  130. package/mjs/Http/Middleware.mjs.map +1 -0
  131. package/mjs/Http/Router.mjs +117 -0
  132. package/mjs/Http/Router.mjs.map +1 -0
  133. package/mjs/Http/Server.mjs +22 -0
  134. package/mjs/Http/Server.mjs.map +1 -0
  135. package/mjs/Http/ServerError.mjs +27 -0
  136. package/mjs/Http/ServerError.mjs.map +1 -0
  137. package/mjs/Http/ServerRequest.mjs +48 -0
  138. package/mjs/Http/ServerRequest.mjs.map +1 -0
  139. package/mjs/Http/ServerResponse.mjs +90 -0
  140. package/mjs/Http/ServerResponse.mjs.map +1 -0
  141. package/mjs/Http/UrlParams.mjs.map +1 -1
  142. package/mjs/HttpServer.mjs +24 -0
  143. package/mjs/HttpServer.mjs.map +1 -0
  144. package/mjs/internal/command.mjs +9 -2
  145. package/mjs/internal/command.mjs.map +1 -1
  146. package/mjs/internal/fileSystem.mjs +15 -11
  147. package/mjs/internal/fileSystem.mjs.map +1 -1
  148. package/mjs/internal/http/body.mjs +23 -25
  149. package/mjs/internal/http/body.mjs.map +1 -1
  150. package/mjs/internal/http/client.mjs +37 -24
  151. package/mjs/internal/http/client.mjs.map +1 -1
  152. package/mjs/internal/http/clientRequest.mjs +16 -4
  153. package/mjs/internal/http/clientRequest.mjs.map +1 -1
  154. package/mjs/internal/http/clientResponse.mjs +15 -12
  155. package/mjs/internal/http/clientResponse.mjs.map +1 -1
  156. package/mjs/internal/http/formData.mjs +67 -0
  157. package/mjs/internal/http/formData.mjs.map +1 -0
  158. package/mjs/internal/http/middleware.mjs +29 -0
  159. package/mjs/internal/http/middleware.mjs.map +1 -0
  160. package/mjs/internal/http/router.mjs +155 -0
  161. package/mjs/internal/http/router.mjs.map +1 -0
  162. package/mjs/internal/http/server.mjs +17 -0
  163. package/mjs/internal/http/server.mjs.map +1 -0
  164. package/mjs/internal/http/serverError.mjs +17 -0
  165. package/mjs/internal/http/serverError.mjs.map +1 -0
  166. package/mjs/internal/http/serverRequest.mjs +41 -0
  167. package/mjs/internal/http/serverRequest.mjs.map +1 -0
  168. package/mjs/internal/http/serverResponse.mjs +82 -0
  169. package/mjs/internal/http/serverResponse.mjs.map +1 -0
  170. package/package.json +2 -1
  171. package/src/Command.ts +3 -2
  172. package/src/FileSystem.ts +20 -25
  173. package/src/Http/App.ts +19 -0
  174. package/src/Http/Body.ts +41 -14
  175. package/src/Http/Client.ts +13 -2
  176. package/src/Http/ClientRequest.ts +52 -2
  177. package/src/Http/ClientResponse.ts +13 -1
  178. package/src/Http/FormData.ts +121 -5
  179. package/src/Http/Headers.ts +37 -3
  180. package/src/Http/IncomingMessage.ts +46 -3
  181. package/src/Http/Middleware.ts +69 -0
  182. package/src/Http/Router.ts +342 -0
  183. package/src/Http/Server.ts +134 -0
  184. package/src/Http/ServerError.ts +111 -0
  185. package/src/Http/ServerRequest.ts +120 -0
  186. package/src/Http/ServerResponse.ts +202 -0
  187. package/src/Http/UrlParams.ts +20 -5
  188. package/src/HttpServer.ts +44 -0
  189. package/src/internal/command.ts +9 -2
  190. package/src/internal/fileSystem.ts +10 -7
  191. package/src/internal/http/body.ts +65 -39
  192. package/src/internal/http/client.ts +96 -76
  193. package/src/internal/http/clientRequest.ts +64 -4
  194. package/src/internal/http/clientResponse.ts +21 -13
  195. package/src/internal/http/formData.ts +140 -0
  196. package/src/internal/http/middleware.ts +72 -0
  197. package/src/internal/http/router.ts +298 -0
  198. package/src/internal/http/server.ts +80 -0
  199. package/src/internal/http/serverError.ts +26 -0
  200. package/src/internal/http/serverRequest.ts +71 -0
  201. package/src/internal/http/serverResponse.ts +255 -0
@@ -1,5 +1,6 @@
1
1
  import * as Context from "@effect/data/Context"
2
2
  import { dual } from "@effect/data/Function"
3
+ import { pipeArguments } from "@effect/data/Pipeable"
3
4
  import type * as Predicate from "@effect/data/Predicate"
4
5
  import * as Effect from "@effect/io/Effect"
5
6
  import * as Layer from "@effect/io/Layer"
@@ -8,6 +9,7 @@ import type * as Body from "@effect/platform/Http/Body"
8
9
  import type * as Client from "@effect/platform/Http/Client"
9
10
  import type * as Error from "@effect/platform/Http/ClientError"
10
11
  import type * as ClientRequest from "@effect/platform/Http/ClientRequest"
12
+ import type * as ClientResponse from "@effect/platform/Http/ClientResponse"
11
13
  import * as Method from "@effect/platform/Http/Method"
12
14
  import * as UrlParams from "@effect/platform/Http/UrlParams"
13
15
  import * as internalBody from "@effect/platform/internal/http/body"
@@ -21,65 +23,84 @@ import * as Stream from "@effect/stream/Stream"
21
23
  /** @internal */
22
24
  export const tag = Context.Tag<Client.Client.Default>("@effect/platform/Http/Client")
23
25
 
26
+ const clientProto = {
27
+ pipe() {
28
+ return pipeArguments(this, arguments)
29
+ }
30
+ }
31
+
32
+ const setProto = <R, E, A>(
33
+ f: (request: ClientRequest.ClientRequest.NonEffectBody) => Effect.Effect<R, E, A>
34
+ ) => {
35
+ Object.setPrototypeOf(f, clientProto)
36
+ return f as Client.Client<R, E, A>
37
+ }
38
+
39
+ /** @internal */
40
+ export const make = (
41
+ f: (
42
+ request: ClientRequest.ClientRequest.NonEffectBody
43
+ ) => Effect.Effect<never, Error.HttpClientError, ClientResponse.ClientResponse>
44
+ ): Client.Client.Default => {
45
+ function client(request: ClientRequest.ClientRequest) {
46
+ return Effect.flatMap(
47
+ internalRequest.resolveBody(request),
48
+ (request) => f(request)
49
+ )
50
+ }
51
+ return setProto(client)
52
+ }
53
+
24
54
  /** @internal */
25
55
  export const fetch = (
26
56
  options: RequestInit = {}
27
57
  ): Client.Client.Default =>
28
- (request) =>
29
- Effect.flatMap(
30
- UrlParams.makeUrl(request.url, request.urlParams, (_) =>
31
- internalError.requestError({
32
- request,
33
- reason: "InvalidUrl",
34
- error: _
35
- })),
36
- (url) =>
37
- Effect.suspend(() => {
38
- const headers = new Headers([...request.headers] as any)
39
- const send = (body: BodyInit | undefined) =>
40
- Effect.map(
41
- Effect.tryPromise({
42
- try: (signal) =>
43
- globalThis.fetch(url, {
44
- ...options,
45
- method: request.method,
46
- headers,
47
- body,
48
- signal
49
- }),
50
- catch: (_) =>
51
- internalError.requestError({
52
- request,
53
- reason: "Transport",
54
- error: _
55
- })
56
- }),
57
- (_) => internalResponse.fromWeb(request, _)
58
- )
59
- if (Method.hasBody(request.method)) {
60
- return request.body._tag === "BytesEffect" ?
61
- Effect.flatMap(
62
- Effect.mapError(request.body.body, (error) =>
63
- internalError.requestError({
64
- reason: "Encode",
65
- request,
66
- error
67
- })),
68
- (body) => send(body)
69
- ) :
70
- send(convertBody(request.body))
71
- }
72
- return send(undefined)
73
- })
58
+ make((request) =>
59
+ Effect.flatMap(
60
+ UrlParams.makeUrl(request.url, request.urlParams, (_) =>
61
+ internalError.requestError({
62
+ request,
63
+ reason: "InvalidUrl",
64
+ error: _
65
+ })),
66
+ (url) =>
67
+ Effect.suspend(() => {
68
+ const headers = new Headers([...request.headers] as any)
69
+ const send = (body: BodyInit | undefined) =>
70
+ Effect.map(
71
+ Effect.tryPromise({
72
+ try: (signal) =>
73
+ globalThis.fetch(url, {
74
+ ...options,
75
+ method: request.method,
76
+ headers,
77
+ body,
78
+ signal
79
+ }),
80
+ catch: (_) =>
81
+ internalError.requestError({
82
+ request,
83
+ reason: "Transport",
84
+ error: _
85
+ })
86
+ }),
87
+ (_) => internalResponse.fromWeb(request, _)
88
+ )
89
+ if (Method.hasBody(request.method)) {
90
+ return send(convertBody(request.body))
91
+ }
92
+ return send(undefined)
93
+ })
94
+ )
74
95
  )
75
96
 
76
- const convertBody = (body: Exclude<Body.Body, Body.BytesEffect>): BodyInit | undefined => {
97
+ const convertBody = (body: Body.NonEffect): BodyInit | undefined => {
77
98
  switch (body._tag) {
78
99
  case "Empty":
79
100
  return undefined
80
101
  case "Raw":
81
102
  return body.body as any
82
- case "Bytes":
103
+ case "Uint8Array":
83
104
  return body.body
84
105
  case "FormData":
85
106
  return body.formData
@@ -93,7 +114,7 @@ export const fetchOk = (
93
114
  ): Client.Client.Default => filterStatusOk(fetch(options))
94
115
 
95
116
  /** @internal */
96
- export const fetchLayer = Layer.succeed(tag, fetch())
117
+ export const layer = Layer.succeed(tag, fetch())
97
118
 
98
119
  /** @internal */
99
120
  export const catchTag: {
@@ -115,7 +136,7 @@ export const catchTag: {
115
136
  tag: K,
116
137
  f: (e: Extract<E, { _tag: K }>) => Effect.Effect<R1, E1, A1>
117
138
  ): Client.Client<R1 | R, E1 | Exclude<E, { _tag: K }>, A1 | A> =>
118
- (request) => Effect.catchTag(self(request), tag, f)
139
+ setProto((request) => Effect.catchTag(self(request), tag, f))
119
140
  )
120
141
 
121
142
  /** @internal */
@@ -225,8 +246,7 @@ export const catchTags: {
225
246
  ) => Effect.Effect<any, any, infer A> ? A
226
247
  : never
227
248
  }[keyof Cases]
228
- > =>
229
- (request) => Effect.catchTags(self(request), cases)
249
+ > => setProto((request) => Effect.catchTags(self(request), cases))
230
250
  )
231
251
 
232
252
  /** @internal */
@@ -243,8 +263,7 @@ export const catchAll: {
243
263
  <R, E, A, R2, E2, A2>(
244
264
  self: Client.Client<R, E, A>,
245
265
  f: (e: E) => Effect.Effect<R2, E2, A2>
246
- ): Client.Client<R | R2, E2, A2 | A> =>
247
- (request) => Effect.catchAll(self(request), f)
266
+ ): Client.Client<R | R2, E2, A2 | A> => setProto((request) => Effect.catchAll(self(request), f))
248
267
  )
249
268
 
250
269
  /** @internal */
@@ -257,7 +276,7 @@ export const filterOrElse = dual<
257
276
  f: Predicate.Predicate<A>,
258
277
  orElse: (a: A) => Effect.Effect<R2, E2, B>
259
278
  ) => Client.Client<R2 | R, E2 | E, A | B>
260
- >(3, (self, f, orElse) => (request) => Effect.filterOrElse(self(request), f, orElse))
279
+ >(3, (self, f, orElse) => setProto((request) => Effect.filterOrElse(self(request), f, orElse)))
261
280
 
262
281
  /** @internal */
263
282
  export const filterOrFail = dual<
@@ -269,7 +288,7 @@ export const filterOrFail = dual<
269
288
  f: Predicate.Predicate<A>,
270
289
  orFailWith: (a: A) => E2
271
290
  ) => Client.Client<R, E2 | E, A>
272
- >(3, (self, f, orFailWith) => (request) => Effect.filterOrFail(self(request), f, orFailWith))
291
+ >(3, (self, f, orFailWith) => setProto((request) => Effect.filterOrFail(self(request), f, orFailWith)))
273
292
 
274
293
  /** @internal */
275
294
  export const filterStatus = dual<
@@ -282,17 +301,19 @@ export const filterStatus = dual<
282
301
  ) => Client.Client.WithResponse<R, E | Error.ResponseError>
283
302
  >(
284
303
  2,
285
- (self, f) => (request) =>
286
- Effect.filterOrFail(
287
- self(request),
288
- (response) => f(response.status),
289
- (response) =>
290
- internalError.responseError({
291
- request,
292
- response,
293
- reason: "StatusCode",
294
- error: "non 2xx status code"
295
- })
304
+ (self, f) =>
305
+ setProto((request) =>
306
+ Effect.filterOrFail(
307
+ self(request),
308
+ (response) => f(response.status),
309
+ (response) =>
310
+ internalError.responseError({
311
+ request,
312
+ response,
313
+ reason: "StatusCode",
314
+ error: "non 2xx status code"
315
+ })
316
+ )
296
317
  )
297
318
  )
298
319
 
@@ -310,7 +331,7 @@ export const map = dual<
310
331
  self: Client.Client<R, E, A>,
311
332
  f: (a: A) => B
312
333
  ) => Client.Client<R, E, B>
313
- >(2, (self, f) => (request) => Effect.map(self(request), f))
334
+ >(2, (self, f) => setProto((request) => Effect.map(self(request), f)))
314
335
 
315
336
  /** @internal */
316
337
  export const mapEffect = dual<
@@ -321,7 +342,7 @@ export const mapEffect = dual<
321
342
  self: Client.Client<R, E, A>,
322
343
  f: (a: A) => Effect.Effect<R2, E2, B>
323
344
  ) => Client.Client<R | R2, E | E2, B>
324
- >(2, (self, f) => (request) => Effect.flatMap(self(request), f))
345
+ >(2, (self, f) => setProto((request) => Effect.flatMap(self(request), f)))
325
346
 
326
347
  /** @internal */
327
348
  export const mapRequest = dual<
@@ -332,7 +353,7 @@ export const mapRequest = dual<
332
353
  self: Client.Client<R, E, A>,
333
354
  f: (a: ClientRequest.ClientRequest) => ClientRequest.ClientRequest
334
355
  ) => Client.Client<R, E, A>
335
- >(2, (self, f) => (request) => self(f(request)))
356
+ >(2, (self, f) => setProto((request) => self(f(request))))
336
357
 
337
358
  /** @internal */
338
359
  export const mapRequestEffect = dual<
@@ -343,7 +364,7 @@ export const mapRequestEffect = dual<
343
364
  self: Client.Client<R, E, A>,
344
365
  f: (a: ClientRequest.ClientRequest) => Effect.Effect<R2, E2, ClientRequest.ClientRequest>
345
366
  ) => Client.Client<R | R2, E | E2, A>
346
- >(2, (self, f) => (request) => Effect.flatMap(f(request), self))
367
+ >(2, (self, f) => setProto((request) => Effect.flatMap(f(request), self)))
347
368
 
348
369
  /** @internal */
349
370
  export const retry: {
@@ -359,8 +380,7 @@ export const retry: {
359
380
  <R, E extends E0, E0, A, R1, B>(
360
381
  self: Client.Client<R, E, A>,
361
382
  policy: Schedule.Schedule<R1, E0, B>
362
- ): Client.Client<R | R1, E, A> =>
363
- (request) => Effect.retry(self(request), policy)
383
+ ): Client.Client<R | R1, E, A> => setProto((request) => Effect.retry(self(request), policy))
364
384
  )
365
385
 
366
386
  /** @internal */
@@ -394,7 +414,7 @@ export const schemaFunction = dual<
394
414
  (body) =>
395
415
  self(internalRequest.setBody(
396
416
  request,
397
- internalBody.bytes(body, "application/json")
417
+ internalBody.uint8Array(body, "application/json")
398
418
  ))
399
419
  )
400
420
  })
@@ -408,7 +428,7 @@ export const tap = dual<
408
428
  self: Client.Client<R, E, A>,
409
429
  f: (a: A) => Effect.Effect<R2, E2, _>
410
430
  ) => Client.Client<R | R2, E | E2, A>
411
- >(2, (self, f) => (request) => Effect.tap(self(request), f))
431
+ >(2, (self, f) => setProto((request) => Effect.tap(self(request), f)))
412
432
 
413
433
  /** @internal */
414
434
  export const tapRequest = dual<
@@ -419,4 +439,4 @@ export const tapRequest = dual<
419
439
  self: Client.Client<R, E, A>,
420
440
  f: (a: ClientRequest.ClientRequest) => Effect.Effect<R2, E2, _>
421
441
  ) => Client.Client<R | R2, E | E2, A>
422
- >(2, (self, f) => (request) => Effect.zipRight(f(request), self(request)))
442
+ >(2, (self, f) => setProto((request) => Effect.zipRight(f(request), self(request))))
@@ -1,5 +1,8 @@
1
1
  import { dual } from "@effect/data/Function"
2
2
  import { pipeArguments } from "@effect/data/Pipeable"
3
+ import * as Effect from "@effect/io/Effect"
4
+ import type * as PlatformError from "@effect/platform/Error"
5
+ import type * as FileSystem from "@effect/platform/FileSystem"
3
6
  import type * as Body from "@effect/platform/Http/Body"
4
7
  import type * as Error from "@effect/platform/Http/ClientError"
5
8
  import type * as ClientRequest from "@effect/platform/Http/ClientRequest"
@@ -7,6 +10,7 @@ import * as Headers from "@effect/platform/Http/Headers"
7
10
  import type { Method } from "@effect/platform/Http/Method"
8
11
  import * as UrlParams from "@effect/platform/Http/UrlParams"
9
12
  import * as internalBody from "@effect/platform/internal/http/body"
13
+ import * as internalError from "@effect/platform/internal/http/clientError"
10
14
  import type * as Schema from "@effect/schema/Schema"
11
15
  import type * as Stream from "@effect/stream/Stream"
12
16
 
@@ -14,14 +18,16 @@ import type * as Stream from "@effect/stream/Stream"
14
18
  export const TypeId: ClientRequest.TypeId = Symbol.for("@effect/platform/Http/ClientRequest") as ClientRequest.TypeId
15
19
 
16
20
  class ClientRequestImpl implements ClientRequest.ClientRequest {
17
- readonly [TypeId]: ClientRequest.TypeId = TypeId
21
+ readonly [TypeId]: ClientRequest.TypeId
18
22
  constructor(
19
23
  readonly method: Method,
20
24
  readonly url: string,
21
25
  readonly urlParams: UrlParams.UrlParams,
22
26
  readonly headers: Headers.Headers,
23
27
  readonly body: Body.Body
24
- ) {}
28
+ ) {
29
+ this[TypeId] = TypeId
30
+ }
25
31
  pipe() {
26
32
  return pipeArguments(this, arguments)
27
33
  }
@@ -293,12 +299,26 @@ export const setBody = dual<
293
299
  })
294
300
 
295
301
  /** @internal */
296
- export const binaryBody = dual<
302
+ export const uint8ArrayBody = dual<
297
303
  (body: Uint8Array, contentType?: string) => (self: ClientRequest.ClientRequest) => ClientRequest.ClientRequest,
298
304
  (self: ClientRequest.ClientRequest, body: Uint8Array, contentType?: string) => ClientRequest.ClientRequest
299
305
  >(
300
306
  (args) => isClientRequest(args[0]),
301
- (self, body, contentType = "application/octet-stream") => setBody(self, internalBody.bytes(body, contentType))
307
+ (self, body, contentType = "application/octet-stream") => setBody(self, internalBody.uint8Array(body, contentType))
308
+ )
309
+
310
+ /** @internal */
311
+ export const effectBody = dual<
312
+ (
313
+ body: Effect.Effect<never, unknown, Body.NonEffect>
314
+ ) => (self: ClientRequest.ClientRequest) => ClientRequest.ClientRequest,
315
+ (
316
+ self: ClientRequest.ClientRequest,
317
+ body: Effect.Effect<never, unknown, Body.NonEffect>
318
+ ) => ClientRequest.ClientRequest
319
+ >(
320
+ 2,
321
+ (self, body) => setBody(self, internalBody.effect(body))
302
322
  )
303
323
 
304
324
  /** @internal */
@@ -316,6 +336,30 @@ export const jsonBody = dual<
316
336
  (self: ClientRequest.ClientRequest, body: unknown) => ClientRequest.ClientRequest
317
337
  >(2, (self, body) => setBody(self, internalBody.json(body)))
318
338
 
339
+ /** @internal */
340
+ export const unsafeJsonBody = dual<
341
+ (body: unknown) => (self: ClientRequest.ClientRequest) => ClientRequest.ClientRequest,
342
+ (self: ClientRequest.ClientRequest, body: unknown) => ClientRequest.ClientRequest
343
+ >(2, (self, body) => setBody(self, internalBody.unsafeJson(body)))
344
+
345
+ /** @internal */
346
+ export const fileBody = dual<
347
+ (
348
+ path: string,
349
+ options?: FileSystem.StreamOptions & { readonly contentType?: string }
350
+ ) => (
351
+ self: ClientRequest.ClientRequest
352
+ ) => Effect.Effect<FileSystem.FileSystem, PlatformError.PlatformError, ClientRequest.ClientRequest>,
353
+ (
354
+ self: ClientRequest.ClientRequest,
355
+ path: string,
356
+ options?: FileSystem.StreamOptions & { readonly contentType?: string }
357
+ ) => Effect.Effect<FileSystem.FileSystem, PlatformError.PlatformError, ClientRequest.ClientRequest>
358
+ >(
359
+ (args) => isClientRequest(args[0]),
360
+ (self, path, options) => Effect.map(internalBody.file(path, options), (body) => setBody(self, body))
361
+ )
362
+
319
363
  /** @internal */
320
364
  export const schemaBody = <I, A>(schema: Schema.Schema<I, A>): {
321
365
  (body: A): (self: ClientRequest.ClientRequest) => ClientRequest.ClientRequest
@@ -369,3 +413,19 @@ export const streamBody = dual<
369
413
  (self, body, { contentLength, contentType = "application/octet-stream" } = {}) =>
370
414
  setBody(self, internalBody.stream(body, contentType, contentLength))
371
415
  )
416
+
417
+ /** @internal */
418
+ export const resolveBody = (
419
+ self: ClientRequest.ClientRequest
420
+ ): Effect.Effect<never, Error.RequestError, ClientRequest.ClientRequest.NonEffectBody> =>
421
+ self.body._tag === "Effect"
422
+ ? Effect.map(
423
+ Effect.mapError(self.body.effect, (error) =>
424
+ internalError.requestError({
425
+ reason: "Encode",
426
+ request: self,
427
+ error
428
+ })),
429
+ (body) => setBody(self, body) as ClientRequest.ClientRequest.NonEffectBody
430
+ )
431
+ : Effect.succeed(self as ClientRequest.ClientRequest.NonEffectBody)
@@ -2,9 +2,9 @@ import * as Effect from "@effect/io/Effect"
2
2
  import type * as Error from "@effect/platform/Http/ClientError"
3
3
  import type * as ClientRequest from "@effect/platform/Http/ClientRequest"
4
4
  import type * as ClientResponse from "@effect/platform/Http/ClientResponse"
5
- import type * as FormData from "@effect/platform/Http/FormData"
6
5
  import * as Headers from "@effect/platform/Http/Headers"
7
6
  import * as IncomingMessage from "@effect/platform/Http/IncomingMessage"
7
+ import * as UrlParams from "@effect/platform/Http/UrlParams"
8
8
  import * as internalError from "@effect/platform/internal/http/clientError"
9
9
  import * as Stream from "@effect/stream/Stream"
10
10
 
@@ -18,13 +18,16 @@ export const fromWeb = (
18
18
  ): ClientResponse.ClientResponse => new ClientResponseImpl(request, source)
19
19
 
20
20
  class ClientResponseImpl implements ClientResponse.ClientResponse {
21
- readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId = IncomingMessage.TypeId
22
- readonly [TypeId]: ClientResponse.TypeId = TypeId
21
+ readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId
22
+ readonly [TypeId]: ClientResponse.TypeId
23
23
 
24
24
  constructor(
25
25
  private readonly request: ClientRequest.ClientRequest,
26
26
  private readonly source: globalThis.Response
27
- ) {}
27
+ ) {
28
+ this[IncomingMessage.TypeId] = IncomingMessage.TypeId
29
+ this[TypeId] = TypeId
30
+ }
28
31
 
29
32
  get status(): number {
30
33
  return this.source.status
@@ -77,6 +80,20 @@ class ClientResponseImpl implements ClientResponse.ClientResponse {
77
80
  })
78
81
  }
79
82
 
83
+ get urlParams(): Effect.Effect<never, Error.ResponseError, UrlParams.UrlParams> {
84
+ return Effect.flatMap(this.text, (_) =>
85
+ Effect.try({
86
+ try: () => UrlParams.fromInput(new URLSearchParams(_)),
87
+ catch: (_) =>
88
+ internalError.responseError({
89
+ request: this.request,
90
+ response: this,
91
+ reason: "Decode",
92
+ error: _
93
+ })
94
+ }))
95
+ }
96
+
80
97
  get formData(): Effect.Effect<never, Error.ResponseError, FormData> {
81
98
  return Effect.tryPromise({
82
99
  try: () => this.source.formData(),
@@ -90,15 +107,6 @@ class ClientResponseImpl implements ClientResponse.ClientResponse {
90
107
  })
91
108
  }
92
109
 
93
- get formDataStream(): Stream.Stream<never, Error.ResponseError, FormData.Part> {
94
- return Stream.fail(internalError.responseError({
95
- request: this.request,
96
- response: this,
97
- reason: "Decode",
98
- error: "not implemented"
99
- }))
100
- }
101
-
102
110
  get arrayBuffer(): Effect.Effect<never, Error.ResponseError, ArrayBuffer> {
103
111
  return Effect.tryPromise({
104
112
  try: () => this.source.arrayBuffer(),
@@ -0,0 +1,140 @@
1
+ import * as Chunk from "@effect/data/Chunk"
2
+ import * as Data from "@effect/data/Data"
3
+ import { dual, pipe } from "@effect/data/Function"
4
+ import { globalValue } from "@effect/data/Global"
5
+ import * as Option from "@effect/data/Option"
6
+ import * as Predicate from "@effect/data/Predicate"
7
+ import * as ReadonlyArray from "@effect/data/ReadonlyArray"
8
+ import * as Effect from "@effect/io/Effect"
9
+ import * as FiberRef from "@effect/io/FiberRef"
10
+ import * as FileSystem from "@effect/platform/FileSystem"
11
+ import type * as FormData from "@effect/platform/Http/FormData"
12
+ import type * as ParseResult from "@effect/schema/ParseResult"
13
+ import * as Schema from "@effect/schema/Schema"
14
+
15
+ /** @internal */
16
+ export const TypeId: FormData.TypeId = Symbol.for("@effect/platform/Http/FormData") as FormData.TypeId
17
+
18
+ /** @internal */
19
+ export const ErrorTypeId: FormData.ErrorTypeId = Symbol.for(
20
+ "@effect/platform/Http/FormData/FormDataError"
21
+ ) as FormData.ErrorTypeId
22
+
23
+ /** @internal */
24
+ export const FormDataError = (reason: FormData.FormDataError["reason"], error: unknown): FormData.FormDataError =>
25
+ Data.struct({
26
+ [ErrorTypeId]: ErrorTypeId,
27
+ _tag: "FormDataError",
28
+ reason,
29
+ error
30
+ })
31
+
32
+ /** @internal */
33
+ export const maxFieldSize: FiberRef.FiberRef<FileSystem.Size> = globalValue(
34
+ "@effect/platform/Http/FormData/maxFieldSize",
35
+ () => FiberRef.unsafeMake(FileSystem.Size(1024 * 1024))
36
+ )
37
+
38
+ /** @internal */
39
+ export const withMaxFieldSize = dual<
40
+ (size: FileSystem.SizeInput) => <R, E, A>(effect: Effect.Effect<R, E, A>) => Effect.Effect<R, E, A>,
41
+ <R, E, A>(effect: Effect.Effect<R, E, A>, size: FileSystem.SizeInput) => Effect.Effect<R, E, A>
42
+ >(2, (effect, size) => Effect.locally(effect, maxFieldSize, FileSystem.Size(size)))
43
+
44
+ /** @internal */
45
+ export const maxFileSize: FiberRef.FiberRef<Option.Option<FileSystem.Size>> = globalValue(
46
+ "@effect/platform/Http/FormData/maxFileSize",
47
+ () => FiberRef.unsafeMake(Option.none<FileSystem.Size>())
48
+ )
49
+
50
+ /** @internal */
51
+ export const withMaxFileSize = dual<
52
+ (size: Option.Option<FileSystem.SizeInput>) => <R, E, A>(effect: Effect.Effect<R, E, A>) => Effect.Effect<R, E, A>,
53
+ <R, E, A>(effect: Effect.Effect<R, E, A>, size: Option.Option<FileSystem.SizeInput>) => Effect.Effect<R, E, A>
54
+ >(2, (effect, size) => Effect.locally(effect, maxFileSize, Option.map(size, FileSystem.Size)))
55
+
56
+ /** @internal */
57
+ export const fieldMimeTypes: FiberRef.FiberRef<Chunk.Chunk<string>> = globalValue(
58
+ "@effect/platform/Http/FormData/fieldMimeTypes",
59
+ () => FiberRef.unsafeMake(Chunk.make("application/json"))
60
+ )
61
+
62
+ /**
63
+ * @since 1.0.0
64
+ * @category fiber refs
65
+ */
66
+ export const withFieldMimeTypes = dual<
67
+ (mimeTypes: ReadonlyArray<string>) => <R, E, A>(effect: Effect.Effect<R, E, A>) => Effect.Effect<R, E, A>,
68
+ <R, E, A>(effect: Effect.Effect<R, E, A>, mimeTypes: ReadonlyArray<string>) => Effect.Effect<R, E, A>
69
+ >(2, (effect, mimeTypes) => Effect.locally(effect, fieldMimeTypes, Chunk.fromIterable(mimeTypes)))
70
+
71
+ /** @internal */
72
+ export const toRecord = (formData: globalThis.FormData): Record<string, Array<globalThis.File> | string> =>
73
+ ReadonlyArray.reduce(
74
+ formData.entries(),
75
+ {} as Record<string, Array<globalThis.File> | string>,
76
+ (acc, [key, value]) => {
77
+ if (Predicate.isString(value)) {
78
+ acc[key] = value
79
+ } else {
80
+ const existing = acc[key]
81
+ if (Array.isArray(existing)) {
82
+ existing.push(value)
83
+ } else {
84
+ acc[key] = [value]
85
+ }
86
+ }
87
+ return acc
88
+ }
89
+ )
90
+ /** @internal */
91
+ export const filesSchema: Schema.Schema<ReadonlyArray<File>, ReadonlyArray<File>> = Schema.array(
92
+ pipe(
93
+ Schema.instanceOf(Blob),
94
+ Schema.filter(
95
+ (blob): blob is File => "name" in blob
96
+ )
97
+ ) as any as Schema.Schema<File, File>
98
+ )
99
+
100
+ /** @internal */
101
+ export const schemaRecord = <I extends Readonly<Record<string, string | ReadonlyArray<globalThis.File>>>, A>(
102
+ schema: Schema.Schema<I, A>
103
+ ) => {
104
+ const parse = Schema.parse(schema)
105
+ return (formData: globalThis.FormData) => parse(toRecord(formData))
106
+ }
107
+
108
+ /** @internal */
109
+ export const schemaJson = <I, A>(schema: Schema.Schema<I, A>): {
110
+ (
111
+ field: string
112
+ ): (formData: globalThis.FormData) => Effect.Effect<never, FormData.FormDataError | ParseResult.ParseError, A>
113
+ (
114
+ formData: globalThis.FormData,
115
+ field: string
116
+ ): Effect.Effect<never, FormData.FormDataError | ParseResult.ParseError, A>
117
+ } => {
118
+ const parse = Schema.parse(schema)
119
+ return dual<
120
+ (
121
+ field: string
122
+ ) => (formData: globalThis.FormData) => Effect.Effect<never, FormData.FormDataError | ParseResult.ParseError, A>,
123
+ (
124
+ formData: globalThis.FormData,
125
+ field: string
126
+ ) => Effect.Effect<never, FormData.FormDataError | ParseResult.ParseError, A>
127
+ >(2, (formData, field) =>
128
+ pipe(
129
+ Effect.succeed(formData.get(field)),
130
+ Effect.filterOrFail(
131
+ (field) => Predicate.isString(field),
132
+ () => FormDataError("Parse", `schemaJson: field was not a string`)
133
+ ),
134
+ Effect.tryMap({
135
+ try: (field) => JSON.parse(field as string),
136
+ catch: (error) => FormDataError("Parse", `schemaJson: field was not valid json: ${error}`)
137
+ }),
138
+ Effect.flatMap(parse)
139
+ ))
140
+ }