@effect/platform 0.31.1 → 0.32.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 (61) hide show
  1. package/dist/cjs/Http/App.js +43 -1
  2. package/dist/cjs/Http/App.js.map +1 -1
  3. package/dist/cjs/Http/Client.js +16 -1
  4. package/dist/cjs/Http/Client.js.map +1 -1
  5. package/dist/cjs/Http/IncomingMessage.js +3 -3
  6. package/dist/cjs/Http/IncomingMessage.js.map +1 -1
  7. package/dist/cjs/Http/ServerRequest.js +6 -1
  8. package/dist/cjs/Http/ServerRequest.js.map +1 -1
  9. package/dist/cjs/Http/ServerResponse.js +6 -1
  10. package/dist/cjs/Http/ServerResponse.js.map +1 -1
  11. package/dist/cjs/internal/http/client.js +10 -3
  12. package/dist/cjs/internal/http/client.js.map +1 -1
  13. package/dist/cjs/internal/http/router.js +2 -1
  14. package/dist/cjs/internal/http/router.js.map +1 -1
  15. package/dist/cjs/internal/http/serverRequest.js +112 -1
  16. package/dist/cjs/internal/http/serverRequest.js.map +1 -1
  17. package/dist/cjs/internal/http/serverResponse.js +49 -1
  18. package/dist/cjs/internal/http/serverResponse.js.map +1 -1
  19. package/dist/cjs/internal/worker.js +1 -1
  20. package/dist/cjs/internal/worker.js.map +1 -1
  21. package/dist/dts/Http/App.d.ts +22 -2
  22. package/dist/dts/Http/App.d.ts.map +1 -1
  23. package/dist/dts/Http/Client.d.ts +28 -0
  24. package/dist/dts/Http/Client.d.ts.map +1 -1
  25. package/dist/dts/Http/ServerRequest.d.ts +5 -0
  26. package/dist/dts/Http/ServerRequest.d.ts.map +1 -1
  27. package/dist/dts/Http/ServerResponse.d.ts +5 -0
  28. package/dist/dts/Http/ServerResponse.d.ts.map +1 -1
  29. package/dist/dts/Terminal.d.ts +1 -1
  30. package/dist/dts/internal/http/router.d.ts.map +1 -1
  31. package/dist/esm/Http/App.js +40 -0
  32. package/dist/esm/Http/App.js.map +1 -1
  33. package/dist/esm/Http/Client.js +15 -0
  34. package/dist/esm/Http/Client.js.map +1 -1
  35. package/dist/esm/Http/IncomingMessage.js +3 -3
  36. package/dist/esm/Http/IncomingMessage.js.map +1 -1
  37. package/dist/esm/Http/ServerRequest.js +5 -0
  38. package/dist/esm/Http/ServerRequest.js.map +1 -1
  39. package/dist/esm/Http/ServerResponse.js +5 -0
  40. package/dist/esm/Http/ServerResponse.js.map +1 -1
  41. package/dist/esm/internal/http/client.js +9 -2
  42. package/dist/esm/internal/http/client.js.map +1 -1
  43. package/dist/esm/internal/http/router.js +2 -1
  44. package/dist/esm/internal/http/router.js.map +1 -1
  45. package/dist/esm/internal/http/serverRequest.js +110 -0
  46. package/dist/esm/internal/http/serverRequest.js.map +1 -1
  47. package/dist/esm/internal/http/serverResponse.js +47 -0
  48. package/dist/esm/internal/http/serverResponse.js.map +1 -1
  49. package/dist/esm/internal/worker.js +1 -1
  50. package/dist/esm/internal/worker.js.map +1 -1
  51. package/package.json +3 -3
  52. package/src/Http/App.ts +50 -2
  53. package/src/Http/Client.ts +39 -0
  54. package/src/Http/IncomingMessage.ts +3 -3
  55. package/src/Http/ServerRequest.ts +6 -0
  56. package/src/Http/ServerResponse.ts +6 -0
  57. package/src/internal/http/client.ts +194 -85
  58. package/src/internal/http/router.ts +2 -1
  59. package/src/internal/http/serverRequest.ts +159 -0
  60. package/src/internal/http/serverResponse.ts +44 -1
  61. package/src/internal/worker.ts +1 -8
@@ -1,10 +1,18 @@
1
1
  import type * as Schema from "@effect/schema/Schema"
2
2
  import * as Context from "effect/Context"
3
3
  import * as Effect from "effect/Effect"
4
+ import * as Option from "effect/Option"
5
+ import type * as Scope from "effect/Scope"
6
+ import * as Stream from "effect/Stream"
7
+ import type * as FileSystem from "../../FileSystem.js"
4
8
  import * as FormData from "../../Http/FormData.js"
9
+ import * as Headers from "../../Http/Headers.js"
5
10
  import * as IncomingMessage from "../../Http/IncomingMessage.js"
11
+ import type { Method } from "../../Http/Method.js"
6
12
  import * as Error from "../../Http/ServerError.js"
7
13
  import type * as ServerRequest from "../../Http/ServerRequest.js"
14
+ import * as UrlParams from "../../Http/UrlParams.js"
15
+ import type * as Path from "../../Path.js"
8
16
 
9
17
  /** @internal */
10
18
  export const TypeId: ServerRequest.TypeId = Symbol.for("@effect/platform/Http/ServerRequest") as ServerRequest.TypeId
@@ -63,3 +71,154 @@ export const schemaFormDataJson = <I, A>(schema: Schema.Schema<I, A>) => {
63
71
  )
64
72
  ))
65
73
  }
74
+
75
+ /** @internal */
76
+ export const fromWeb = (request: globalThis.Request): ServerRequest.ServerRequest =>
77
+ new ServerRequestImpl(request, request.url)
78
+
79
+ class ServerRequestImpl implements ServerRequest.ServerRequest {
80
+ readonly [TypeId]: ServerRequest.TypeId
81
+ readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId
82
+ constructor(
83
+ readonly source: Request,
84
+ readonly url: string,
85
+ public headersOverride?: Headers.Headers,
86
+ private remoteAddressOverride?: string
87
+ ) {
88
+ this[TypeId] = TypeId
89
+ this[IncomingMessage.TypeId] = IncomingMessage.TypeId
90
+ }
91
+ modify(
92
+ options: {
93
+ readonly url?: string | undefined
94
+ readonly headers?: Headers.Headers | undefined
95
+ readonly remoteAddress?: string | undefined
96
+ }
97
+ ) {
98
+ return new ServerRequestImpl(
99
+ this.source,
100
+ options.url ?? this.url,
101
+ options.headers ?? this.headersOverride,
102
+ options.remoteAddress ?? this.remoteAddressOverride
103
+ )
104
+ }
105
+ get method(): Method {
106
+ return this.source.method.toUpperCase() as Method
107
+ }
108
+ get originalUrl() {
109
+ return this.source.url
110
+ }
111
+ get remoteAddress(): Option.Option<string> {
112
+ return this.remoteAddressOverride ? Option.some(this.remoteAddressOverride) : Option.none()
113
+ }
114
+ get headers(): Headers.Headers {
115
+ this.headersOverride ??= Headers.fromInput(this.source.headers)
116
+ return this.headersOverride
117
+ }
118
+
119
+ get stream(): Stream.Stream<never, Error.RequestError, Uint8Array> {
120
+ return this.source.body
121
+ ? Stream.fromReadableStream(() => this.source.body as any, (_) =>
122
+ Error.RequestError({
123
+ request: this,
124
+ reason: "Decode",
125
+ error: _
126
+ }))
127
+ : Stream.fail(Error.RequestError({
128
+ request: this,
129
+ reason: "Decode",
130
+ error: "can not create stream from empty body"
131
+ }))
132
+ }
133
+
134
+ private textEffect: Effect.Effect<never, Error.RequestError, string> | undefined
135
+ get text(): Effect.Effect<never, Error.RequestError, string> {
136
+ if (this.textEffect) {
137
+ return this.textEffect
138
+ }
139
+ this.textEffect = Effect.runSync(Effect.cached(
140
+ Effect.tryPromise({
141
+ try: () => this.source.text(),
142
+ catch: (error) =>
143
+ Error.RequestError({
144
+ request: this,
145
+ reason: "Decode",
146
+ error
147
+ })
148
+ })
149
+ ))
150
+ return this.textEffect
151
+ }
152
+
153
+ get json(): Effect.Effect<never, Error.RequestError, unknown> {
154
+ return Effect.tryMap(this.text, {
155
+ try: (_) => JSON.parse(_) as unknown,
156
+ catch: (error) =>
157
+ Error.RequestError({
158
+ request: this,
159
+ reason: "Decode",
160
+ error
161
+ })
162
+ })
163
+ }
164
+
165
+ get urlParamsBody(): Effect.Effect<never, Error.RequestError, UrlParams.UrlParams> {
166
+ return Effect.flatMap(this.text, (_) =>
167
+ Effect.try({
168
+ try: () => UrlParams.fromInput(new URLSearchParams(_)),
169
+ catch: (error) =>
170
+ Error.RequestError({
171
+ request: this,
172
+ reason: "Decode",
173
+ error
174
+ })
175
+ }))
176
+ }
177
+
178
+ private formDataEffect:
179
+ | Effect.Effect<
180
+ Scope.Scope | FileSystem.FileSystem | Path.Path,
181
+ FormData.FormDataError,
182
+ FormData.PersistedFormData
183
+ >
184
+ | undefined
185
+ get formData(): Effect.Effect<
186
+ Scope.Scope | FileSystem.FileSystem | Path.Path,
187
+ FormData.FormDataError,
188
+ FormData.PersistedFormData
189
+ > {
190
+ if (this.formDataEffect) {
191
+ return this.formDataEffect
192
+ }
193
+ this.formDataEffect = Effect.runSync(Effect.cached(
194
+ FormData.formData(this.formDataStream)
195
+ ))
196
+ return this.formDataEffect
197
+ }
198
+
199
+ get formDataStream(): Stream.Stream<never, FormData.FormDataError, FormData.Part> {
200
+ return Stream.pipeThroughChannel(
201
+ Stream.mapError(this.stream, (error) => FormData.FormDataError("InternalError", error)),
202
+ FormData.makeChannel(this.headers)
203
+ )
204
+ }
205
+
206
+ private arrayBufferEffect: Effect.Effect<never, Error.RequestError, ArrayBuffer> | undefined
207
+ get arrayBuffer(): Effect.Effect<never, Error.RequestError, ArrayBuffer> {
208
+ if (this.arrayBuffer) {
209
+ return this.arrayBuffer
210
+ }
211
+ this.arrayBufferEffect = Effect.runSync(Effect.cached(
212
+ Effect.tryPromise({
213
+ try: () => this.source.arrayBuffer(),
214
+ catch: (error) =>
215
+ Error.RequestError({
216
+ request: this,
217
+ reason: "Decode",
218
+ error
219
+ })
220
+ })
221
+ ))
222
+ return this.arrayBufferEffect
223
+ }
224
+ }
@@ -2,7 +2,7 @@ import type * as Schema from "@effect/schema/Schema"
2
2
  import * as Effect from "effect/Effect"
3
3
  import * as Effectable from "effect/Effectable"
4
4
  import { dual } from "effect/Function"
5
- import type * as Stream from "effect/Stream"
5
+ import * as Stream from "effect/Stream"
6
6
  import type * as PlatformError from "../../Error.js"
7
7
  import type * as FileSystem from "../../FileSystem.js"
8
8
  import type * as Body from "../../Http/Body.js"
@@ -259,3 +259,46 @@ export const setBody = dual<
259
259
  body
260
260
  )
261
261
  })
262
+
263
+ /** @internal */
264
+ export const toWeb = (response: ServerResponse.ServerResponse, withoutBody = false): Response => {
265
+ if (withoutBody) {
266
+ return new Response(undefined, {
267
+ status: response.status,
268
+ statusText: response.statusText,
269
+ headers: response.headers
270
+ })
271
+ }
272
+ const body = response.body
273
+ switch (body._tag) {
274
+ case "Empty": {
275
+ return new Response(undefined, {
276
+ status: response.status,
277
+ statusText: response.statusText,
278
+ headers: response.headers
279
+ })
280
+ }
281
+ case "Uint8Array":
282
+ case "Raw": {
283
+ return new Response(body.body as any, {
284
+ status: response.status,
285
+ statusText: response.statusText,
286
+ headers: response.headers
287
+ })
288
+ }
289
+ case "FormData": {
290
+ return new Response(body.formData as any, {
291
+ status: response.status,
292
+ statusText: response.statusText,
293
+ headers: response.headers
294
+ })
295
+ }
296
+ case "Stream": {
297
+ return new Response(Stream.toReadableStream(body.stream), {
298
+ status: response.status,
299
+ statusText: response.statusText,
300
+ headers: response.headers
301
+ })
302
+ }
303
+ }
304
+ }
@@ -283,11 +283,4 @@ export const makePoolLayer = <W>(managerLayer: Layer.Layer<never, never, Worker.
283
283
  <Tag, I, E, O>(
284
284
  tag: Context.Tag<Tag, Worker.WorkerPool<I, E, O>>,
285
285
  options: Worker.WorkerPool.Options<I, W>
286
- ) =>
287
- Layer.provide(
288
- managerLayer,
289
- Layer.scoped(
290
- tag,
291
- makePool<W>()(options)
292
- )
293
- )
286
+ ) => Layer.scoped(tag, makePool<W>()(options)).pipe(Layer.provide(managerLayer))