@effect/platform 0.47.0 → 0.48.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/dist/cjs/Error.js +40 -4
- package/dist/cjs/Error.js.map +1 -1
- package/dist/cjs/Http/Body.js +8 -1
- package/dist/cjs/Http/Body.js.map +1 -1
- package/dist/cjs/Http/ClientError.js +21 -2
- package/dist/cjs/Http/ClientError.js.map +1 -1
- package/dist/cjs/Http/Headers.js +22 -1
- package/dist/cjs/Http/Headers.js.map +1 -1
- package/dist/cjs/Http/IncomingMessage.js +1 -1
- package/dist/cjs/Http/IncomingMessage.js.map +1 -1
- package/dist/cjs/Http/Multipart.js +21 -6
- package/dist/cjs/Http/Multipart.js.map +1 -1
- package/dist/cjs/Http/ServerError.js +30 -7
- package/dist/cjs/Http/ServerError.js.map +1 -1
- package/dist/cjs/Http/UrlParams.js +7 -2
- package/dist/cjs/Http/UrlParams.js.map +1 -1
- package/dist/cjs/PlatformLogger.js +1 -1
- package/dist/cjs/Socket.js +104 -22
- package/dist/cjs/Socket.js.map +1 -1
- package/dist/cjs/Transferable.js +1 -1
- package/dist/cjs/Transferable.js.map +1 -1
- package/dist/cjs/WorkerError.js.map +1 -1
- package/dist/cjs/internal/http/body.js +1 -1
- package/dist/cjs/internal/http/body.js.map +1 -1
- package/dist/cjs/internal/http/client.js +5 -5
- package/dist/cjs/internal/http/client.js.map +1 -1
- package/dist/cjs/internal/http/clientError.js +1 -36
- package/dist/cjs/internal/http/clientError.js.map +1 -1
- package/dist/cjs/internal/http/clientResponse.js +8 -8
- package/dist/cjs/internal/http/clientResponse.js.map +1 -1
- package/dist/cjs/internal/http/multipart.js +15 -11
- package/dist/cjs/internal/http/multipart.js.map +1 -1
- package/dist/cjs/internal/http/multiplex.js +1 -1
- package/dist/cjs/internal/http/multiplex.js.map +1 -1
- package/dist/cjs/internal/http/router.js +1 -1
- package/dist/cjs/internal/http/router.js.map +1 -1
- package/dist/cjs/internal/http/serverError.js +1 -15
- package/dist/cjs/internal/http/serverError.js.map +1 -1
- package/dist/cjs/internal/http/serverRequest.js +8 -8
- package/dist/cjs/internal/http/serverRequest.js.map +1 -1
- package/dist/dts/Error.d.ts +22 -0
- package/dist/dts/Error.d.ts.map +1 -1
- package/dist/dts/Http/Body.d.ts +9 -1
- package/dist/dts/Http/Body.d.ts.map +1 -1
- package/dist/dts/Http/ClientError.d.ts +21 -33
- package/dist/dts/Http/ClientError.d.ts.map +1 -1
- package/dist/dts/Http/Headers.d.ts +19 -0
- package/dist/dts/Http/Headers.d.ts.map +1 -1
- package/dist/dts/Http/Multipart.d.ts +21 -6
- package/dist/dts/Http/Multipart.d.ts.map +1 -1
- package/dist/dts/Http/ServerError.d.ts +33 -47
- package/dist/dts/Http/ServerError.d.ts.map +1 -1
- package/dist/dts/Http/ServerRequest.d.ts +3 -3
- package/dist/dts/Http/ServerRequest.d.ts.map +1 -1
- package/dist/dts/Http/UrlParams.d.ts +5 -0
- package/dist/dts/Http/UrlParams.d.ts.map +1 -1
- package/dist/dts/PlatformLogger.d.ts +1 -1
- package/dist/dts/Runtime.d.ts +4 -1
- package/dist/dts/Runtime.d.ts.map +1 -1
- package/dist/dts/Socket.d.ts +89 -13
- package/dist/dts/Socket.d.ts.map +1 -1
- package/dist/dts/Worker.d.ts +6 -6
- package/dist/dts/Worker.d.ts.map +1 -1
- package/dist/dts/WorkerError.d.ts +10 -5
- package/dist/dts/WorkerError.d.ts.map +1 -1
- package/dist/dts/WorkerRunner.d.ts +1 -1
- package/dist/dts/WorkerRunner.d.ts.map +1 -1
- package/dist/esm/Error.js +38 -3
- package/dist/esm/Error.js.map +1 -1
- package/dist/esm/Http/Body.js +6 -0
- package/dist/esm/Http/Body.js.map +1 -1
- package/dist/esm/Http/ClientError.js +19 -2
- package/dist/esm/Http/ClientError.js.map +1 -1
- package/dist/esm/Http/Headers.js +21 -1
- package/dist/esm/Http/Headers.js.map +1 -1
- package/dist/esm/Http/IncomingMessage.js +1 -1
- package/dist/esm/Http/IncomingMessage.js.map +1 -1
- package/dist/esm/Http/Multipart.js +20 -5
- package/dist/esm/Http/Multipart.js.map +1 -1
- package/dist/esm/Http/ServerError.js +26 -7
- package/dist/esm/Http/ServerError.js.map +1 -1
- package/dist/esm/Http/UrlParams.js +5 -0
- package/dist/esm/Http/UrlParams.js.map +1 -1
- package/dist/esm/PlatformLogger.js +1 -1
- package/dist/esm/Socket.js +98 -20
- package/dist/esm/Socket.js.map +1 -1
- package/dist/esm/Transferable.js +1 -1
- package/dist/esm/Transferable.js.map +1 -1
- package/dist/esm/WorkerError.js.map +1 -1
- package/dist/esm/internal/http/body.js +1 -1
- package/dist/esm/internal/http/body.js.map +1 -1
- package/dist/esm/internal/http/client.js +5 -5
- package/dist/esm/internal/http/client.js.map +1 -1
- package/dist/esm/internal/http/clientError.js +0 -10
- package/dist/esm/internal/http/clientError.js.map +1 -1
- package/dist/esm/internal/http/clientResponse.js +8 -8
- package/dist/esm/internal/http/clientResponse.js.map +1 -1
- package/dist/esm/internal/http/multipart.js +10 -9
- package/dist/esm/internal/http/multipart.js.map +1 -1
- package/dist/esm/internal/http/multiplex.js +1 -1
- package/dist/esm/internal/http/multiplex.js.map +1 -1
- package/dist/esm/internal/http/router.js +1 -1
- package/dist/esm/internal/http/router.js.map +1 -1
- package/dist/esm/internal/http/serverError.js +0 -14
- package/dist/esm/internal/http/serverError.js.map +1 -1
- package/dist/esm/internal/http/serverRequest.js +8 -8
- package/dist/esm/internal/http/serverRequest.js.map +1 -1
- package/package.json +3 -3
- package/src/Error.ts +61 -0
- package/src/Http/Body.ts +14 -1
- package/src/Http/ClientError.ts +21 -38
- package/src/Http/Headers.ts +29 -1
- package/src/Http/IncomingMessage.ts +1 -1
- package/src/Http/Multipart.ts +25 -7
- package/src/Http/ServerError.ts +25 -56
- package/src/Http/ServerRequest.ts +5 -5
- package/src/Http/UrlParams.ts +10 -0
- package/src/PlatformLogger.ts +1 -1
- package/src/Runtime.ts +4 -1
- package/src/Socket.ts +179 -39
- package/src/Transferable.ts +1 -1
- package/src/Worker.ts +6 -6
- package/src/WorkerError.ts +9 -7
- package/src/WorkerRunner.ts +8 -8
- package/src/internal/http/body.ts +4 -2
- package/src/internal/http/client.ts +5 -6
- package/src/internal/http/clientError.ts +0 -14
- package/src/internal/http/clientResponse.ts +15 -14
- package/src/internal/http/multipart.ts +16 -12
- package/src/internal/http/multiplex.ts +1 -1
- package/src/internal/http/router.ts +1 -1
- package/src/internal/http/serverError.ts +0 -20
- package/src/internal/http/serverRequest.ts +22 -18
package/src/Http/Multipart.ts
CHANGED
|
@@ -33,6 +33,12 @@ export type TypeId = typeof TypeId
|
|
|
33
33
|
*/
|
|
34
34
|
export type Part = Field | File
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* @since 1.0.0
|
|
38
|
+
* @category refinements
|
|
39
|
+
*/
|
|
40
|
+
export const isPart: (u: unknown) => u is Part = internal.isPart
|
|
41
|
+
|
|
36
42
|
/**
|
|
37
43
|
* @since 1.0.0
|
|
38
44
|
*/
|
|
@@ -58,6 +64,12 @@ export interface Field extends Part.Proto {
|
|
|
58
64
|
readonly value: string
|
|
59
65
|
}
|
|
60
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @since 1.0.0
|
|
69
|
+
* @category refinements
|
|
70
|
+
*/
|
|
71
|
+
export const isField: (u: unknown) => u is Field = internal.isField
|
|
72
|
+
|
|
61
73
|
/**
|
|
62
74
|
* @since 1.0.0
|
|
63
75
|
* @category models
|
|
@@ -70,6 +82,12 @@ export interface File extends Part.Proto {
|
|
|
70
82
|
readonly content: Stream.Stream<Uint8Array, MultipartError>
|
|
71
83
|
}
|
|
72
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @since 1.0.0
|
|
87
|
+
* @category refinements
|
|
88
|
+
*/
|
|
89
|
+
export const isFile: (u: unknown) => u is File = internal.isFile
|
|
90
|
+
|
|
73
91
|
/**
|
|
74
92
|
* @since 1.0.0
|
|
75
93
|
* @category models
|
|
@@ -82,6 +100,12 @@ export interface PersistedFile extends Part.Proto {
|
|
|
82
100
|
readonly path: string
|
|
83
101
|
}
|
|
84
102
|
|
|
103
|
+
/**
|
|
104
|
+
* @since 1.0.0
|
|
105
|
+
* @category refinements
|
|
106
|
+
*/
|
|
107
|
+
export const isPersistedFile: (u: unknown) => u is PersistedFile = internal.isPersistedFile
|
|
108
|
+
|
|
85
109
|
/**
|
|
86
110
|
* @since 1.0.0
|
|
87
111
|
* @category models
|
|
@@ -122,12 +146,6 @@ export const MultipartError: (
|
|
|
122
146
|
error: unknown
|
|
123
147
|
) => MultipartError = internal.MultipartError
|
|
124
148
|
|
|
125
|
-
/**
|
|
126
|
-
* @since 1.0.0
|
|
127
|
-
* @category refinements
|
|
128
|
-
*/
|
|
129
|
-
export const isField: (u: unknown) => u is Field = internal.isField
|
|
130
|
-
|
|
131
149
|
/**
|
|
132
150
|
* @since 1.0.0
|
|
133
151
|
* @category fiber refs
|
|
@@ -209,7 +227,7 @@ export const schemaJson: <A, I, R>(
|
|
|
209
227
|
* @since 1.0.0
|
|
210
228
|
* @category schema
|
|
211
229
|
*/
|
|
212
|
-
export const schemaPersisted: <R, I extends Persisted
|
|
230
|
+
export const schemaPersisted: <R, I extends Partial<Persisted>, A>(
|
|
213
231
|
schema: Schema.Schema<A, I, R>
|
|
214
232
|
) => (persisted: Persisted) => Effect.Effect<A, ParseResult.ParseError, R> = internal.schemaPersisted
|
|
215
233
|
|
package/src/Http/ServerError.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type * as Cause from "effect/Cause"
|
|
5
5
|
import type * as FiberId from "effect/FiberId"
|
|
6
|
+
import { RefailError, TypeIdError } from "../Error.js"
|
|
6
7
|
import * as internal from "../internal/http/serverError.js"
|
|
7
8
|
import type * as ServerRequest from "./ServerRequest.js"
|
|
8
9
|
import type * as ServerResponse from "./ServerResponse.js"
|
|
@@ -25,34 +26,21 @@ export type TypeId = typeof TypeId
|
|
|
25
26
|
*/
|
|
26
27
|
export type HttpServerError = RequestError | ResponseError | RouteNotFound | ServeError
|
|
27
28
|
|
|
28
|
-
/**
|
|
29
|
-
* @since 1.0.0
|
|
30
|
-
*/
|
|
31
|
-
export declare namespace HttpError {
|
|
32
|
-
/**
|
|
33
|
-
* @since 1.0.0
|
|
34
|
-
* @category models
|
|
35
|
-
*/
|
|
36
|
-
export interface Proto {
|
|
37
|
-
readonly [TypeId]: TypeId
|
|
38
|
-
readonly _tag: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @since 1.0.0
|
|
43
|
-
*/
|
|
44
|
-
export type ProvidedFields = TypeId | "_tag"
|
|
45
|
-
}
|
|
46
|
-
|
|
47
29
|
/**
|
|
48
30
|
* @since 1.0.0
|
|
49
31
|
* @category error
|
|
50
32
|
*/
|
|
51
|
-
export
|
|
52
|
-
readonly _tag: "RequestError"
|
|
33
|
+
export class RequestError extends RefailError(TypeId, "RequestError")<{
|
|
53
34
|
readonly request: ServerRequest.ServerRequest
|
|
54
35
|
readonly reason: "Transport" | "Decode"
|
|
55
|
-
|
|
36
|
+
}> {
|
|
37
|
+
get methodAndUrl() {
|
|
38
|
+
return `${this.request.method} ${this.request.url}`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get message() {
|
|
42
|
+
return `${this.reason} error (${this.methodAndUrl}): ${super.message}`
|
|
43
|
+
}
|
|
56
44
|
}
|
|
57
45
|
|
|
58
46
|
/**
|
|
@@ -65,57 +53,38 @@ export const isServerError: (u: unknown) => u is HttpServerError = internal.isSe
|
|
|
65
53
|
* @since 1.0.0
|
|
66
54
|
* @category error
|
|
67
55
|
*/
|
|
68
|
-
export
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @since 1.0.0
|
|
72
|
-
* @category error
|
|
73
|
-
*/
|
|
74
|
-
export interface RouteNotFound extends HttpError.Proto {
|
|
75
|
-
readonly _tag: "RouteNotFound"
|
|
56
|
+
export class RouteNotFound extends TypeIdError(TypeId, "RouteNotFound")<{
|
|
76
57
|
readonly request: ServerRequest.ServerRequest
|
|
58
|
+
}> {
|
|
59
|
+
get message() {
|
|
60
|
+
return `${this.request.method} ${this.request.url} not found`
|
|
61
|
+
}
|
|
77
62
|
}
|
|
78
63
|
|
|
79
64
|
/**
|
|
80
65
|
* @since 1.0.0
|
|
81
66
|
* @category error
|
|
82
67
|
*/
|
|
83
|
-
export
|
|
84
|
-
internal.routeNotFound
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @since 1.0.0
|
|
88
|
-
* @category error
|
|
89
|
-
*/
|
|
90
|
-
export interface ResponseError extends HttpError.Proto {
|
|
91
|
-
readonly _tag: "ResponseError"
|
|
68
|
+
export class ResponseError extends RefailError(TypeId, "ResponseError")<{
|
|
92
69
|
readonly request: ServerRequest.ServerRequest
|
|
93
70
|
readonly response: ServerResponse.ServerResponse
|
|
94
71
|
readonly reason: "Decode"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* @since 1.0.0
|
|
100
|
-
* @category error
|
|
101
|
-
*/
|
|
102
|
-
export const ResponseError: (props: Omit<ResponseError, HttpError.ProvidedFields>) => ResponseError =
|
|
103
|
-
internal.responseError
|
|
72
|
+
}> {
|
|
73
|
+
get methodAndUrl() {
|
|
74
|
+
return `${this.request.method} ${this.request.url}`
|
|
75
|
+
}
|
|
104
76
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*/
|
|
109
|
-
export interface ServeError extends HttpError.Proto {
|
|
110
|
-
readonly _tag: "ServeError"
|
|
111
|
-
readonly error: unknown
|
|
77
|
+
get message() {
|
|
78
|
+
return `${this.reason} error (${this.response.status} ${this.methodAndUrl}): ${super.message}`
|
|
79
|
+
}
|
|
112
80
|
}
|
|
113
81
|
|
|
114
82
|
/**
|
|
115
83
|
* @since 1.0.0
|
|
116
84
|
* @category error
|
|
117
85
|
*/
|
|
118
|
-
export
|
|
86
|
+
export class ServeError extends RefailError(TypeId, "ServeError")<{}> {
|
|
87
|
+
}
|
|
119
88
|
|
|
120
89
|
/**
|
|
121
90
|
* @since 1.0.0
|
|
@@ -96,7 +96,7 @@ export const upgrade: Effect.Effect<Socket.Socket, Error.RequestError, ServerReq
|
|
|
96
96
|
*/
|
|
97
97
|
export const upgradeChannel: <IE = never>() => Channel<
|
|
98
98
|
Chunk<Uint8Array>,
|
|
99
|
-
Chunk<Uint8Array>,
|
|
99
|
+
Chunk<Uint8Array | Socket.CloseEvent>,
|
|
100
100
|
Error.RequestError | IE | Socket.SocketError,
|
|
101
101
|
IE,
|
|
102
102
|
void,
|
|
@@ -124,12 +124,12 @@ export const schemaBodyJson: <A, I, R>(
|
|
|
124
124
|
* @since 1.0.0
|
|
125
125
|
* @category schema
|
|
126
126
|
*/
|
|
127
|
-
export const schemaBodyForm: <R, I extends Multipart.Persisted
|
|
127
|
+
export const schemaBodyForm: <R, I extends Partial<Multipart.Persisted>, A>(
|
|
128
128
|
schema: Schema.Schema<A, I, R>
|
|
129
129
|
) => Effect.Effect<
|
|
130
130
|
A,
|
|
131
|
-
Multipart.MultipartError |
|
|
132
|
-
ServerRequest | Scope.Scope | FileSystem.FileSystem | Path.Path
|
|
131
|
+
Multipart.MultipartError | ParseResult.ParseError | Error.RequestError,
|
|
132
|
+
R | ServerRequest | Scope.Scope | FileSystem.FileSystem | Path.Path
|
|
133
133
|
> = internal.schemaBodyForm
|
|
134
134
|
|
|
135
135
|
/**
|
|
@@ -144,7 +144,7 @@ export const schemaBodyUrlParams: <R, I extends Readonly<Record<string, string>>
|
|
|
144
144
|
* @since 1.0.0
|
|
145
145
|
* @category schema
|
|
146
146
|
*/
|
|
147
|
-
export const schemaBodyMultipart: <R, I extends Multipart.Persisted
|
|
147
|
+
export const schemaBodyMultipart: <R, I extends Partial<Multipart.Persisted>, A>(
|
|
148
148
|
schema: Schema.Schema<A, I, R>
|
|
149
149
|
) => Effect.Effect<
|
|
150
150
|
A,
|
package/src/Http/UrlParams.ts
CHANGED
|
@@ -31,6 +31,16 @@ export const fromInput = (input: Input): UrlParams => {
|
|
|
31
31
|
return ReadonlyArray.fromIterable(Object.entries(input))
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* @since 1.0.0
|
|
36
|
+
* @category schemas
|
|
37
|
+
*/
|
|
38
|
+
export const schema: Schema.Schema<UrlParams, ReadonlyArray<readonly [string, string]>> = Schema.array(
|
|
39
|
+
Schema.tuple(Schema.string, Schema.string)
|
|
40
|
+
).pipe(
|
|
41
|
+
Schema.identifier("UrlParams")
|
|
42
|
+
)
|
|
43
|
+
|
|
34
44
|
/**
|
|
35
45
|
* @since 1.0.0
|
|
36
46
|
* @category constructors
|
package/src/PlatformLogger.ts
CHANGED
|
@@ -19,7 +19,7 @@ import * as internal from "./internal/platformLogger.js"
|
|
|
19
19
|
* import { Effect, Layer, Logger } from "effect"
|
|
20
20
|
*
|
|
21
21
|
* const fileLogger = Logger.logfmtLogger.pipe(
|
|
22
|
-
* PlatformLogger.toFile("log.txt")
|
|
22
|
+
* PlatformLogger.toFile("/tmp/log.txt")
|
|
23
23
|
* )
|
|
24
24
|
* const LoggerLive = Logger.replaceScoped(Logger.defaultLogger, fileLogger).pipe(
|
|
25
25
|
* Layer.provide(NodeFileSystem.layer)
|
package/src/Runtime.ts
CHANGED
package/src/Socket.ts
CHANGED
|
@@ -5,27 +5,30 @@ import * as Cause from "effect/Cause"
|
|
|
5
5
|
import * as Channel from "effect/Channel"
|
|
6
6
|
import * as Chunk from "effect/Chunk"
|
|
7
7
|
import * as Context from "effect/Context"
|
|
8
|
-
import
|
|
8
|
+
import type { DurationInput } from "effect/Duration"
|
|
9
9
|
import * as Effect from "effect/Effect"
|
|
10
10
|
import * as Exit from "effect/Exit"
|
|
11
|
+
import * as Fiber from "effect/Fiber"
|
|
11
12
|
import * as FiberSet from "effect/FiberSet"
|
|
12
13
|
import * as Layer from "effect/Layer"
|
|
14
|
+
import * as Predicate from "effect/Predicate"
|
|
13
15
|
import * as Queue from "effect/Queue"
|
|
14
16
|
import * as Scope from "effect/Scope"
|
|
15
17
|
import type * as AsyncProducer from "effect/SingleProducerAsyncInput"
|
|
16
18
|
import IsoWebSocket from "isomorphic-ws"
|
|
19
|
+
import { RefailError, TypeIdError } from "./Error.js"
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* @since 1.0.0
|
|
20
23
|
* @category type ids
|
|
21
24
|
*/
|
|
22
|
-
export const
|
|
25
|
+
export const TypeId = Symbol.for("@effect/platform/Socket")
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* @since 1.0.0
|
|
26
29
|
* @category type ids
|
|
27
30
|
*/
|
|
28
|
-
export type
|
|
31
|
+
export type TypeId = typeof TypeId
|
|
29
32
|
|
|
30
33
|
/**
|
|
31
34
|
* @since 1.0.0
|
|
@@ -40,26 +43,117 @@ export const Socket: Context.Tag<Socket, Socket> = Context.GenericTag<Socket>(
|
|
|
40
43
|
* @category models
|
|
41
44
|
*/
|
|
42
45
|
export interface Socket {
|
|
43
|
-
readonly [
|
|
46
|
+
readonly [TypeId]: TypeId
|
|
44
47
|
readonly run: <R, E, _>(
|
|
45
48
|
handler: (_: Uint8Array) => Effect.Effect<_, E, R>
|
|
46
49
|
) => Effect.Effect<void, SocketError | E, R>
|
|
47
|
-
readonly writer: Effect.Effect<(chunk: Uint8Array) => Effect.Effect<void>, never, Scope.Scope>
|
|
50
|
+
readonly writer: Effect.Effect<(chunk: Uint8Array | CloseEvent) => Effect.Effect<void>, never, Scope.Scope>
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @since 1.0.0
|
|
55
|
+
* @category type ids
|
|
56
|
+
*/
|
|
57
|
+
export const CloseEventTypeId = Symbol.for("@effect/platform/Socket/CloseEvent")
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @since 1.0.0
|
|
61
|
+
* @category type ids
|
|
62
|
+
*/
|
|
63
|
+
export type CloseEventTypeId = typeof CloseEventTypeId
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @since 1.0.0
|
|
67
|
+
* @category models
|
|
68
|
+
*/
|
|
69
|
+
export class CloseEvent {
|
|
70
|
+
/**
|
|
71
|
+
* @since 1.0.0
|
|
72
|
+
*/
|
|
73
|
+
readonly [CloseEventTypeId]: CloseEventTypeId
|
|
74
|
+
constructor(readonly code = 1000, readonly reason?: string) {
|
|
75
|
+
this[CloseEventTypeId] = CloseEventTypeId
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* @since 1.0.0
|
|
79
|
+
*/
|
|
80
|
+
toString() {
|
|
81
|
+
return this.reason ? `${this.code}: ${this.reason}` : `${this.code}`
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @since 1.0.0
|
|
87
|
+
* @category refinements
|
|
88
|
+
*/
|
|
89
|
+
export const isCloseEvent = (u: unknown): u is CloseEvent => Predicate.hasProperty(u, CloseEventTypeId)
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @since 1.0.0
|
|
93
|
+
* @category type ids
|
|
94
|
+
*/
|
|
95
|
+
export const SocketErrorTypeId = Symbol.for("@effect/platform/Socket/SocketError")
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @since 1.0.0
|
|
99
|
+
* @category type ids
|
|
100
|
+
*/
|
|
101
|
+
export type SocketErrorTypeId = typeof SocketErrorTypeId
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @since 1.0.0
|
|
105
|
+
* @category refinements
|
|
106
|
+
*/
|
|
107
|
+
export const isSocketError = (u: unknown): u is SocketError => Predicate.hasProperty(u, SocketErrorTypeId)
|
|
108
|
+
|
|
50
109
|
/**
|
|
51
110
|
* @since 1.0.0
|
|
52
111
|
* @category errors
|
|
53
112
|
*/
|
|
54
|
-
export
|
|
55
|
-
|
|
56
|
-
|
|
113
|
+
export type SocketError = SocketGenericError | SocketCloseError
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @since 1.0.0
|
|
117
|
+
* @category errors
|
|
118
|
+
*/
|
|
119
|
+
export class SocketGenericError extends RefailError(SocketErrorTypeId, "SocketError")<{
|
|
120
|
+
readonly reason: "Write" | "Read" | "Open" | "OpenTimeout"
|
|
121
|
+
}> {
|
|
122
|
+
get message() {
|
|
123
|
+
return `${this.reason}: ${super.message}`
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @since 1.0.0
|
|
129
|
+
* @category errors
|
|
130
|
+
*/
|
|
131
|
+
export class SocketCloseError extends TypeIdError(SocketErrorTypeId, "SocketError")<{
|
|
132
|
+
readonly reason: "Close"
|
|
133
|
+
readonly code: number
|
|
134
|
+
readonly closeReason?: string
|
|
57
135
|
}> {
|
|
58
136
|
/**
|
|
59
137
|
* @since 1.0.0
|
|
60
138
|
*/
|
|
61
|
-
|
|
62
|
-
return
|
|
139
|
+
static is(u: unknown): u is SocketCloseError {
|
|
140
|
+
return isSocketError(u) && u.reason === "Close"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @since 1.0.0
|
|
145
|
+
*/
|
|
146
|
+
static isClean(isClean: (code: number) => boolean) {
|
|
147
|
+
return function(u: unknown): u is SocketCloseError {
|
|
148
|
+
return SocketCloseError.is(u) && isClean(u.code)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
get message() {
|
|
153
|
+
if (this.closeReason) {
|
|
154
|
+
return `${this.reason}: ${this.code}: ${this.closeReason}`
|
|
155
|
+
}
|
|
156
|
+
return `${this.reason}: ${this.code}`
|
|
63
157
|
}
|
|
64
158
|
}
|
|
65
159
|
|
|
@@ -69,14 +163,21 @@ export class SocketError extends Data.TaggedError("SocketError")<{
|
|
|
69
163
|
*/
|
|
70
164
|
export const toChannel = <IE>(
|
|
71
165
|
self: Socket
|
|
72
|
-
): Channel.Channel<
|
|
166
|
+
): Channel.Channel<
|
|
167
|
+
Chunk.Chunk<Uint8Array>,
|
|
168
|
+
Chunk.Chunk<Uint8Array | CloseEvent>,
|
|
169
|
+
SocketError | IE,
|
|
170
|
+
IE,
|
|
171
|
+
void,
|
|
172
|
+
unknown
|
|
173
|
+
> =>
|
|
73
174
|
Channel.unwrap(
|
|
74
175
|
Effect.gen(function*(_) {
|
|
75
176
|
const writeScope = yield* _(Scope.make())
|
|
76
177
|
const write = yield* _(Scope.extend(self.writer, writeScope))
|
|
77
178
|
const exitQueue = yield* _(Queue.unbounded<Exit.Exit<Chunk.Chunk<Uint8Array>, SocketError | IE>>())
|
|
78
179
|
|
|
79
|
-
const input: AsyncProducer.AsyncInputProducer<IE, Chunk.Chunk<Uint8Array>, unknown> = {
|
|
180
|
+
const input: AsyncProducer.AsyncInputProducer<IE, Chunk.Chunk<Uint8Array | CloseEvent>, unknown> = {
|
|
80
181
|
awaitRead: () => Effect.unit,
|
|
81
182
|
emit(chunk) {
|
|
82
183
|
return Effect.catchAllCause(
|
|
@@ -123,8 +224,14 @@ export const toChannel = <IE>(
|
|
|
123
224
|
export const toChannelWith = <IE = never>() =>
|
|
124
225
|
(
|
|
125
226
|
self: Socket
|
|
126
|
-
): Channel.Channel<
|
|
127
|
-
|
|
227
|
+
): Channel.Channel<
|
|
228
|
+
Chunk.Chunk<Uint8Array>,
|
|
229
|
+
Chunk.Chunk<Uint8Array | CloseEvent>,
|
|
230
|
+
SocketError | IE,
|
|
231
|
+
IE,
|
|
232
|
+
void,
|
|
233
|
+
unknown
|
|
234
|
+
> => toChannel(self)
|
|
128
235
|
|
|
129
236
|
/**
|
|
130
237
|
* @since 1.0.0
|
|
@@ -132,7 +239,7 @@ export const toChannelWith = <IE = never>() =>
|
|
|
132
239
|
*/
|
|
133
240
|
export const makeChannel = <IE = never>(): Channel.Channel<
|
|
134
241
|
Chunk.Chunk<Uint8Array>,
|
|
135
|
-
Chunk.Chunk<Uint8Array>,
|
|
242
|
+
Chunk.Chunk<Uint8Array | CloseEvent>,
|
|
136
243
|
SocketError | IE,
|
|
137
244
|
IE,
|
|
138
245
|
void,
|
|
@@ -167,6 +274,7 @@ export const WebSocket: Context.Tag<WebSocket, globalThis.WebSocket> = Context.G
|
|
|
167
274
|
*/
|
|
168
275
|
export const makeWebSocket = (url: string | Effect.Effect<string>, options?: {
|
|
169
276
|
readonly closeCodeIsError?: (code: number) => boolean
|
|
277
|
+
readonly openTimeout?: DurationInput
|
|
170
278
|
}): Effect.Effect<Socket> =>
|
|
171
279
|
fromWebSocket(
|
|
172
280
|
Effect.acquireRelease(
|
|
@@ -190,11 +298,12 @@ export const fromWebSocket = (
|
|
|
190
298
|
acquire: Effect.Effect<globalThis.WebSocket, SocketError, Scope.Scope>,
|
|
191
299
|
options?: {
|
|
192
300
|
readonly closeCodeIsError?: (code: number) => boolean
|
|
301
|
+
readonly openTimeout?: DurationInput
|
|
193
302
|
}
|
|
194
303
|
): Effect.Effect<Socket> =>
|
|
195
304
|
Effect.gen(function*(_) {
|
|
196
305
|
const closeCodeIsError = options?.closeCodeIsError ?? defaultCloseCodeIsError
|
|
197
|
-
const sendQueue = yield* _(Queue.unbounded<Uint8Array>())
|
|
306
|
+
const sendQueue = yield* _(Queue.unbounded<Uint8Array | CloseEvent>())
|
|
198
307
|
|
|
199
308
|
const run = <R, E, _>(handler: (_: Uint8Array) => Effect.Effect<_, E, R>) =>
|
|
200
309
|
Effect.gen(function*(_) {
|
|
@@ -219,23 +328,38 @@ export const fromWebSocket = (
|
|
|
219
328
|
}
|
|
220
329
|
|
|
221
330
|
if (ws.readyState !== IsoWebSocket.OPEN) {
|
|
222
|
-
yield* _(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
331
|
+
yield* _(
|
|
332
|
+
Effect.async<void, SocketError, never>((resume) => {
|
|
333
|
+
ws.onopen = () => {
|
|
334
|
+
resume(Effect.unit)
|
|
335
|
+
}
|
|
336
|
+
ws.onerror = (error_) => {
|
|
337
|
+
resume(Effect.fail(new SocketGenericError({ reason: "Open", error: (error_ as any).message })))
|
|
338
|
+
}
|
|
339
|
+
}),
|
|
340
|
+
Effect.timeoutFail({
|
|
341
|
+
duration: options?.openTimeout ?? 10000,
|
|
342
|
+
onTimeout: () => new SocketGenericError({ reason: "OpenTimeout", error: "timeout waiting for \"open\"" })
|
|
343
|
+
})
|
|
344
|
+
)
|
|
230
345
|
}
|
|
231
346
|
|
|
232
|
-
yield* _(
|
|
347
|
+
const writeFiber = yield* _(
|
|
233
348
|
Queue.take(sendQueue),
|
|
234
349
|
Effect.tap((chunk) =>
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
350
|
+
isCloseEvent(chunk) ?
|
|
351
|
+
Effect.failSync(() => {
|
|
352
|
+
ws.close(chunk.code, chunk.reason)
|
|
353
|
+
return new SocketCloseError({
|
|
354
|
+
reason: "Close",
|
|
355
|
+
code: chunk.code,
|
|
356
|
+
closeReason: chunk.reason
|
|
357
|
+
})
|
|
358
|
+
}) :
|
|
359
|
+
Effect.try({
|
|
360
|
+
try: () => ws.send(chunk),
|
|
361
|
+
catch: (error) => new SocketGenericError({ reason: "Write", error: (error as any).message })
|
|
362
|
+
})
|
|
239
363
|
),
|
|
240
364
|
Effect.forever,
|
|
241
365
|
Effect.fork
|
|
@@ -244,25 +368,34 @@ export const fromWebSocket = (
|
|
|
244
368
|
yield* _(
|
|
245
369
|
Effect.async<void, SocketError, never>((resume) => {
|
|
246
370
|
ws.onclose = (event) => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
371
|
+
resume(
|
|
372
|
+
Effect.fail(
|
|
373
|
+
new SocketCloseError({
|
|
374
|
+
reason: "Close",
|
|
375
|
+
code: event.code,
|
|
376
|
+
closeReason: event.reason
|
|
377
|
+
})
|
|
378
|
+
)
|
|
379
|
+
)
|
|
252
380
|
}
|
|
253
381
|
ws.onerror = (error) => {
|
|
254
|
-
resume(Effect.fail(new
|
|
382
|
+
resume(Effect.fail(new SocketGenericError({ reason: "Read", error: (error as any).message })))
|
|
255
383
|
}
|
|
256
384
|
}),
|
|
257
|
-
Effect.raceFirst(FiberSet.join(fiberSet))
|
|
385
|
+
Effect.raceFirst(FiberSet.join(fiberSet)),
|
|
386
|
+
Effect.raceFirst(Fiber.join(writeFiber)),
|
|
387
|
+
Effect.catchIf(
|
|
388
|
+
SocketCloseError.isClean((_) => !closeCodeIsError(_)),
|
|
389
|
+
(_) => Effect.unit
|
|
390
|
+
)
|
|
258
391
|
)
|
|
259
392
|
}).pipe(Effect.scoped)
|
|
260
393
|
|
|
261
|
-
const write = (chunk: Uint8Array) => Queue.offer(sendQueue, chunk)
|
|
394
|
+
const write = (chunk: Uint8Array | CloseEvent) => Queue.offer(sendQueue, chunk)
|
|
262
395
|
const writer = Effect.succeed(write)
|
|
263
396
|
|
|
264
397
|
return Socket.of({
|
|
265
|
-
[
|
|
398
|
+
[TypeId]: TypeId,
|
|
266
399
|
run,
|
|
267
400
|
writer
|
|
268
401
|
})
|
|
@@ -277,7 +410,14 @@ export const makeWebSocketChannel = <IE = never>(
|
|
|
277
410
|
options?: {
|
|
278
411
|
readonly closeCodeIsError?: (code: number) => boolean
|
|
279
412
|
}
|
|
280
|
-
): Channel.Channel<
|
|
413
|
+
): Channel.Channel<
|
|
414
|
+
Chunk.Chunk<Uint8Array>,
|
|
415
|
+
Chunk.Chunk<Uint8Array | CloseEvent>,
|
|
416
|
+
SocketError | IE,
|
|
417
|
+
IE,
|
|
418
|
+
void,
|
|
419
|
+
unknown
|
|
420
|
+
> =>
|
|
281
421
|
Channel.unwrapScoped(
|
|
282
422
|
Effect.map(makeWebSocket(url, options), toChannelWith<IE>())
|
|
283
423
|
)
|
package/src/Transferable.ts
CHANGED
package/src/Worker.ts
CHANGED
|
@@ -134,7 +134,7 @@ export declare namespace Worker {
|
|
|
134
134
|
| readonly [id: number, end: 1]
|
|
135
135
|
| readonly [id: number, end: 1, ReadonlyArray<O>]
|
|
136
136
|
| readonly [id: number, error: 2, E]
|
|
137
|
-
| readonly [id: number, defect: 3, Schema.
|
|
137
|
+
| readonly [id: number, defect: 3, Schema.CauseEncoded<WorkerErrorFrom>]
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
/**
|
|
@@ -246,12 +246,12 @@ export interface SerializedWorker<I extends Schema.TaggedRequest.Any> {
|
|
|
246
246
|
readonly id: number
|
|
247
247
|
readonly execute: <Req extends I>(
|
|
248
248
|
message: Req
|
|
249
|
-
) => Req extends Serializable.WithResult<infer
|
|
249
|
+
) => Req extends Serializable.WithResult<infer A, infer _I, infer E, infer _EI, infer R>
|
|
250
250
|
? Stream.Stream<A, E | WorkerError | ParseResult.ParseError, R>
|
|
251
251
|
: never
|
|
252
252
|
readonly executeEffect: <Req extends I>(
|
|
253
253
|
message: Req
|
|
254
|
-
) => Req extends Serializable.WithResult<infer
|
|
254
|
+
) => Req extends Serializable.WithResult<infer A, infer _I, infer E, infer _EI, infer R>
|
|
255
255
|
? Effect.Effect<A, E | WorkerError | ParseResult.ParseError, R>
|
|
256
256
|
: never
|
|
257
257
|
}
|
|
@@ -290,17 +290,17 @@ export interface SerializedWorkerPool<I extends Schema.TaggedRequest.Any> {
|
|
|
290
290
|
readonly backing: Pool.Pool<SerializedWorker<I>, WorkerError>
|
|
291
291
|
readonly broadcast: <Req extends I>(
|
|
292
292
|
message: Req
|
|
293
|
-
) => Req extends Serializable.WithResult<infer
|
|
293
|
+
) => Req extends Serializable.WithResult<infer _A, infer _I, infer E, infer _EI, infer R>
|
|
294
294
|
? Effect.Effect<void, E | WorkerError | ParseResult.ParseError, R>
|
|
295
295
|
: never
|
|
296
296
|
readonly execute: <Req extends I>(
|
|
297
297
|
message: Req
|
|
298
|
-
) => Req extends Serializable.WithResult<infer
|
|
298
|
+
) => Req extends Serializable.WithResult<infer A, infer _I, infer E, infer _EI, infer R>
|
|
299
299
|
? Stream.Stream<A, E | WorkerError | ParseResult.ParseError, R>
|
|
300
300
|
: never
|
|
301
301
|
readonly executeEffect: <Req extends I>(
|
|
302
302
|
message: Req
|
|
303
|
-
) => Req extends Serializable.WithResult<infer
|
|
303
|
+
) => Req extends Serializable.WithResult<infer A, infer _I, infer E, infer _EI, infer R>
|
|
304
304
|
? Effect.Effect<A, E | WorkerError | ParseResult.ParseError, R>
|
|
305
305
|
: never
|
|
306
306
|
}
|