@effect/platform-browser 0.74.0 → 4.0.0-beta.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 +0 -6
- package/dist/BrowserHttpClient.d.ts +49 -0
- package/dist/BrowserHttpClient.d.ts.map +1 -0
- package/dist/{esm/internal/httpClient.js → BrowserHttpClient.js} +98 -60
- package/dist/BrowserHttpClient.js.map +1 -0
- package/dist/BrowserKeyValueStore.d.ts +24 -0
- package/dist/BrowserKeyValueStore.d.ts.map +1 -0
- package/dist/BrowserKeyValueStore.js +20 -0
- package/dist/BrowserKeyValueStore.js.map +1 -0
- package/dist/BrowserRuntime.d.ts +28 -0
- package/dist/BrowserRuntime.d.ts.map +1 -0
- package/dist/BrowserRuntime.js +13 -0
- package/dist/BrowserRuntime.js.map +1 -0
- package/dist/{dts/BrowserSocket.d.ts → BrowserSocket.d.ts} +4 -4
- package/dist/BrowserSocket.d.ts.map +1 -0
- package/dist/{esm/BrowserSocket.js → BrowserSocket.js} +5 -5
- package/dist/BrowserSocket.js.map +1 -0
- package/dist/BrowserStream.d.ts +35 -0
- package/dist/BrowserStream.d.ts.map +1 -0
- package/dist/BrowserStream.js +25 -0
- package/dist/BrowserStream.js.map +1 -0
- package/dist/BrowserWorker.d.ts +13 -0
- package/dist/BrowserWorker.d.ts.map +1 -0
- package/dist/{esm/internal/worker.js → BrowserWorker.js} +23 -17
- package/dist/BrowserWorker.js.map +1 -0
- package/dist/BrowserWorkerRunner.d.ts +18 -0
- package/dist/BrowserWorkerRunner.d.ts.map +1 -0
- package/dist/BrowserWorkerRunner.js +143 -0
- package/dist/BrowserWorkerRunner.js.map +1 -0
- package/dist/{dts/Clipboard.d.ts → Clipboard.d.ts} +13 -30
- package/dist/Clipboard.d.ts.map +1 -0
- package/dist/{esm/Clipboard.js → Clipboard.js} +12 -18
- package/dist/Clipboard.js.map +1 -0
- package/dist/Geolocation.d.ts +97 -0
- package/dist/Geolocation.d.ts.map +1 -0
- package/dist/Geolocation.js +99 -0
- package/dist/Geolocation.js.map +1 -0
- package/dist/Permissions.d.ts +80 -0
- package/dist/Permissions.d.ts.map +1 -0
- package/dist/Permissions.js +70 -0
- package/dist/Permissions.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/{esm/index.js → index.js} +4 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -111
- package/src/BrowserHttpClient.ts +364 -16
- package/src/BrowserKeyValueStore.ts +15 -8
- package/src/BrowserRuntime.ts +30 -4
- package/src/BrowserSocket.ts +5 -5
- package/src/BrowserStream.ts +20 -10
- package/src/BrowserWorker.ts +58 -21
- package/src/BrowserWorkerRunner.ts +151 -18
- package/src/Clipboard.ts +16 -38
- package/src/Geolocation.ts +80 -40
- package/src/Permissions.ts +49 -34
- package/src/index.ts +16 -10
- package/BrowserHttpClient/package.json +0 -6
- package/BrowserKeyValueStore/package.json +0 -6
- package/BrowserRuntime/package.json +0 -6
- package/BrowserSocket/package.json +0 -6
- package/BrowserStream/package.json +0 -6
- package/BrowserWorker/package.json +0 -6
- package/BrowserWorkerRunner/package.json +0 -6
- package/Clipboard/package.json +0 -6
- package/Geolocation/package.json +0 -6
- package/Permissions/package.json +0 -6
- package/dist/cjs/BrowserHttpClient.js +0 -31
- package/dist/cjs/BrowserHttpClient.js.map +0 -1
- package/dist/cjs/BrowserKeyValueStore.js +0 -23
- package/dist/cjs/BrowserKeyValueStore.js.map +0 -1
- package/dist/cjs/BrowserRuntime.js +0 -14
- package/dist/cjs/BrowserRuntime.js.map +0 -1
- package/dist/cjs/BrowserSocket.js +0 -27
- package/dist/cjs/BrowserSocket.js.map +0 -1
- package/dist/cjs/BrowserStream.js +0 -23
- package/dist/cjs/BrowserStream.js.map +0 -1
- package/dist/cjs/BrowserWorker.js +0 -29
- package/dist/cjs/BrowserWorker.js.map +0 -1
- package/dist/cjs/BrowserWorkerRunner.js +0 -31
- package/dist/cjs/BrowserWorkerRunner.js.map +0 -1
- package/dist/cjs/Clipboard.js +0 -86
- package/dist/cjs/Clipboard.js.map +0 -1
- package/dist/cjs/Geolocation.js +0 -73
- package/dist/cjs/Geolocation.js.map +0 -1
- package/dist/cjs/Permissions.js +0 -59
- package/dist/cjs/Permissions.js.map +0 -1
- package/dist/cjs/index.js +0 -28
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/httpClient.js +0 -266
- package/dist/cjs/internal/httpClient.js.map +0 -1
- package/dist/cjs/internal/keyValueStore.js +0 -13
- package/dist/cjs/internal/keyValueStore.js.map +0 -1
- package/dist/cjs/internal/runtime.js +0 -16
- package/dist/cjs/internal/runtime.js.map +0 -1
- package/dist/cjs/internal/stream.js +0 -19
- package/dist/cjs/internal/stream.js.map +0 -1
- package/dist/cjs/internal/worker.js +0 -60
- package/dist/cjs/internal/worker.js.map +0 -1
- package/dist/cjs/internal/workerRunner.js +0 -144
- package/dist/cjs/internal/workerRunner.js.map +0 -1
- package/dist/dts/BrowserHttpClient.d.ts +0 -33
- package/dist/dts/BrowserHttpClient.d.ts.map +0 -1
- package/dist/dts/BrowserKeyValueStore.d.ts +0 -20
- package/dist/dts/BrowserKeyValueStore.d.ts.map +0 -1
- package/dist/dts/BrowserRuntime.d.ts +0 -10
- package/dist/dts/BrowserRuntime.d.ts.map +0 -1
- package/dist/dts/BrowserSocket.d.ts.map +0 -1
- package/dist/dts/BrowserStream.d.ts +0 -25
- package/dist/dts/BrowserStream.d.ts.map +0 -1
- package/dist/dts/BrowserWorker.d.ts +0 -26
- package/dist/dts/BrowserWorker.d.ts.map +0 -1
- package/dist/dts/BrowserWorkerRunner.d.ts +0 -27
- package/dist/dts/BrowserWorkerRunner.d.ts.map +0 -1
- package/dist/dts/Clipboard.d.ts.map +0 -1
- package/dist/dts/Geolocation.d.ts +0 -67
- package/dist/dts/Geolocation.d.ts.map +0 -1
- package/dist/dts/Permissions.d.ts +0 -67
- package/dist/dts/Permissions.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -41
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/dts/internal/httpClient.d.ts +0 -2
- package/dist/dts/internal/httpClient.d.ts.map +0 -1
- package/dist/dts/internal/keyValueStore.d.ts +0 -2
- package/dist/dts/internal/keyValueStore.d.ts.map +0 -1
- package/dist/dts/internal/runtime.d.ts +0 -2
- package/dist/dts/internal/runtime.d.ts.map +0 -1
- package/dist/dts/internal/stream.d.ts +0 -5
- package/dist/dts/internal/stream.d.ts.map +0 -1
- package/dist/dts/internal/worker.d.ts +0 -2
- package/dist/dts/internal/worker.d.ts.map +0 -1
- package/dist/dts/internal/workerRunner.d.ts +0 -2
- package/dist/dts/internal/workerRunner.d.ts.map +0 -1
- package/dist/esm/BrowserHttpClient.js +0 -23
- package/dist/esm/BrowserHttpClient.js.map +0 -1
- package/dist/esm/BrowserKeyValueStore.js +0 -16
- package/dist/esm/BrowserKeyValueStore.js.map +0 -1
- package/dist/esm/BrowserRuntime.js +0 -7
- package/dist/esm/BrowserRuntime.js.map +0 -1
- package/dist/esm/BrowserSocket.js.map +0 -1
- package/dist/esm/BrowserStream.js +0 -15
- package/dist/esm/BrowserStream.js.map +0 -1
- package/dist/esm/BrowserWorker.js +0 -22
- package/dist/esm/BrowserWorker.js.map +0 -1
- package/dist/esm/BrowserWorkerRunner.js +0 -23
- package/dist/esm/BrowserWorkerRunner.js.map +0 -1
- package/dist/esm/Clipboard.js.map +0 -1
- package/dist/esm/Geolocation.js +0 -63
- package/dist/esm/Geolocation.js.map +0 -1
- package/dist/esm/Permissions.js +0 -50
- package/dist/esm/Permissions.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/httpClient.js.map +0 -1
- package/dist/esm/internal/keyValueStore.js +0 -6
- package/dist/esm/internal/keyValueStore.js.map +0 -1
- package/dist/esm/internal/runtime.js +0 -10
- package/dist/esm/internal/runtime.js.map +0 -1
- package/dist/esm/internal/stream.js +0 -9
- package/dist/esm/internal/stream.js.map +0 -1
- package/dist/esm/internal/worker.js.map +0 -1
- package/dist/esm/internal/workerRunner.js +0 -135
- package/dist/esm/internal/workerRunner.js.map +0 -1
- package/dist/esm/package.json +0 -4
- package/index/package.json +0 -6
- package/src/internal/httpClient.ts +0 -324
- package/src/internal/keyValueStore.ts +0 -7
- package/src/internal/runtime.ts +0 -8
- package/src/internal/stream.ts +0 -27
- package/src/internal/worker.ts +0 -58
- package/src/internal/workerRunner.ts +0 -155
package/src/BrowserHttpClient.ts
CHANGED
|
@@ -1,37 +1,385 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
import * as
|
|
6
|
-
import type { Effect } from "effect/Effect"
|
|
7
|
-
import type * as FiberRef from "effect/FiberRef"
|
|
4
|
+
import * as Cause from "effect/Cause"
|
|
5
|
+
import * as Effect from "effect/Effect"
|
|
8
6
|
import type { LazyArg } from "effect/Function"
|
|
7
|
+
import * as Inspectable from "effect/Inspectable"
|
|
9
8
|
import type * as Layer from "effect/Layer"
|
|
10
|
-
import * as
|
|
9
|
+
import * as Queue from "effect/Queue"
|
|
10
|
+
import * as ServiceMap from "effect/ServiceMap"
|
|
11
|
+
import * as Stream from "effect/Stream"
|
|
12
|
+
import * as Cookies from "effect/unstable/http/Cookies"
|
|
13
|
+
import * as Headers from "effect/unstable/http/Headers"
|
|
14
|
+
import * as HttpClient from "effect/unstable/http/HttpClient"
|
|
15
|
+
import * as HttpClientError from "effect/unstable/http/HttpClientError"
|
|
16
|
+
import type * as HttpClientRequest from "effect/unstable/http/HttpClientRequest"
|
|
17
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"
|
|
18
|
+
import * as HttpIncomingMessage from "effect/unstable/http/HttpIncomingMessage"
|
|
19
|
+
import * as UrlParams from "effect/unstable/http/UrlParams"
|
|
20
|
+
import * as HeaderParser from "multipasta/HeadersParser"
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Fetch
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
/**
|
|
28
|
+
* @since 1.0.0
|
|
29
|
+
* @category Fetch
|
|
30
|
+
*/
|
|
31
|
+
Fetch,
|
|
32
|
+
/**
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
* @category Fetch
|
|
35
|
+
*/
|
|
36
|
+
layer as layerFetch,
|
|
37
|
+
/**
|
|
38
|
+
* @since 1.0.0
|
|
39
|
+
* @category Fetch
|
|
40
|
+
*/
|
|
41
|
+
RequestInit
|
|
42
|
+
} from "effect/unstable/http/FetchHttpClient"
|
|
43
|
+
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// XML Http Request
|
|
46
|
+
// =============================================================================
|
|
11
47
|
|
|
12
48
|
/**
|
|
13
49
|
* @since 1.0.0
|
|
14
|
-
* @category
|
|
50
|
+
* @category Models
|
|
15
51
|
*/
|
|
16
|
-
export
|
|
52
|
+
export type XHRResponseType = "arraybuffer" | "text"
|
|
17
53
|
|
|
18
54
|
/**
|
|
19
55
|
* @since 1.0.0
|
|
20
|
-
* @category
|
|
56
|
+
* @category References
|
|
21
57
|
*/
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
58
|
+
export const CurrentXHRResponseType: ServiceMap.Reference<XHRResponseType> = ServiceMap.Reference(
|
|
59
|
+
"@effect/platform-browser/BrowserHttpClient/CurrentXHRResponseType",
|
|
60
|
+
{ defaultValue: (): XHRResponseType => "text" }
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @since 1.0.0
|
|
65
|
+
* @category References
|
|
66
|
+
*/
|
|
67
|
+
export const withXHRArrayBuffer = <A, E, R>(
|
|
68
|
+
self: Effect.Effect<A, E, R>
|
|
69
|
+
): Effect.Effect<A, E, R> =>
|
|
70
|
+
Effect.provideService(
|
|
71
|
+
self,
|
|
72
|
+
CurrentXHRResponseType,
|
|
73
|
+
"arraybuffer"
|
|
74
|
+
)
|
|
26
75
|
|
|
27
76
|
/**
|
|
28
77
|
* @since 1.0.0
|
|
29
|
-
* @category
|
|
78
|
+
* @category Services
|
|
30
79
|
*/
|
|
31
|
-
export
|
|
80
|
+
export class XMLHttpRequest extends ServiceMap.Service<
|
|
81
|
+
XMLHttpRequest,
|
|
82
|
+
LazyArg<globalThis.XMLHttpRequest>
|
|
83
|
+
>()("@effect/platform-browser/BrowserHttpClient/XMLHttpRequest") {}
|
|
84
|
+
|
|
85
|
+
const makeXhrRequest = () => new globalThis.XMLHttpRequest()
|
|
86
|
+
|
|
87
|
+
const makeXmlHttpRequest = HttpClient.make(
|
|
88
|
+
(request, url, signal, fiber) =>
|
|
89
|
+
Effect.suspend(() => {
|
|
90
|
+
const xhr = ServiceMap.getOrElse(
|
|
91
|
+
fiber.services,
|
|
92
|
+
XMLHttpRequest,
|
|
93
|
+
() => makeXhrRequest
|
|
94
|
+
)()
|
|
95
|
+
signal.addEventListener("abort", () => {
|
|
96
|
+
xhr.abort()
|
|
97
|
+
xhr.onreadystatechange = null
|
|
98
|
+
}, { once: true })
|
|
99
|
+
xhr.open(request.method, url.toString(), true)
|
|
100
|
+
xhr.responseType = fiber.getRef(CurrentXHRResponseType)
|
|
101
|
+
Object.entries(request.headers).forEach(([k, v]) => {
|
|
102
|
+
xhr.setRequestHeader(k, v)
|
|
103
|
+
})
|
|
104
|
+
return Effect.andThen(
|
|
105
|
+
sendBody(xhr, request),
|
|
106
|
+
Effect.callback<ClientResponseImpl, HttpClientError.HttpClientError>((resume) => {
|
|
107
|
+
let sent = false
|
|
108
|
+
const onChange = () => {
|
|
109
|
+
if (!sent && xhr.readyState >= 2) {
|
|
110
|
+
sent = true
|
|
111
|
+
resume(Effect.succeed(new ClientResponseImpl(request, xhr)))
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
xhr.onreadystatechange = onChange
|
|
115
|
+
xhr.onerror = (_event) => {
|
|
116
|
+
resume(Effect.fail(
|
|
117
|
+
new HttpClientError.HttpClientError({
|
|
118
|
+
reason: new HttpClientError.TransportError({
|
|
119
|
+
request,
|
|
120
|
+
cause: xhr.statusText
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
))
|
|
124
|
+
}
|
|
125
|
+
onChange()
|
|
126
|
+
return Effect.void
|
|
127
|
+
})
|
|
128
|
+
)
|
|
129
|
+
})
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
const sendBody = (
|
|
133
|
+
xhr: globalThis.XMLHttpRequest,
|
|
134
|
+
request: HttpClientRequest.HttpClientRequest
|
|
135
|
+
): Effect.Effect<void, HttpClientError.HttpClientError> => {
|
|
136
|
+
const body = request.body
|
|
137
|
+
switch (body._tag) {
|
|
138
|
+
case "Empty":
|
|
139
|
+
return Effect.sync(() => xhr.send())
|
|
140
|
+
case "Raw":
|
|
141
|
+
return Effect.sync(() => xhr.send(body.body as any))
|
|
142
|
+
case "Uint8Array":
|
|
143
|
+
return Effect.sync(() => xhr.send(body.body as any))
|
|
144
|
+
case "FormData":
|
|
145
|
+
return Effect.sync(() => xhr.send(body.formData))
|
|
146
|
+
case "Stream":
|
|
147
|
+
return Effect.matchEffect(
|
|
148
|
+
Stream.runFold(body.stream, () => new Uint8Array(0), (acc, chunk) => {
|
|
149
|
+
const next = new Uint8Array(acc.length + chunk.length)
|
|
150
|
+
next.set(acc, 0)
|
|
151
|
+
next.set(chunk, acc.length)
|
|
152
|
+
return next
|
|
153
|
+
}),
|
|
154
|
+
{
|
|
155
|
+
onFailure: (cause) =>
|
|
156
|
+
Effect.fail(
|
|
157
|
+
new HttpClientError.HttpClientError({
|
|
158
|
+
reason: new HttpClientError.EncodeError({
|
|
159
|
+
request,
|
|
160
|
+
cause
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
),
|
|
164
|
+
onSuccess: (body) => Effect.sync(() => xhr.send(body))
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const encoder = new TextEncoder()
|
|
171
|
+
|
|
172
|
+
abstract class IncomingMessageImpl<E> extends Inspectable.Class implements HttpIncomingMessage.HttpIncomingMessage<E> {
|
|
173
|
+
readonly [HttpIncomingMessage.TypeId]: typeof HttpIncomingMessage.TypeId
|
|
174
|
+
readonly source: globalThis.XMLHttpRequest
|
|
175
|
+
readonly onError: (error: unknown) => E
|
|
176
|
+
|
|
177
|
+
constructor(source: globalThis.XMLHttpRequest, onError: (error: unknown) => E) {
|
|
178
|
+
super()
|
|
179
|
+
this[HttpIncomingMessage.TypeId] = HttpIncomingMessage.TypeId
|
|
180
|
+
this.source = source
|
|
181
|
+
this.onError = onError
|
|
182
|
+
this._rawHeaderString = source.getAllResponseHeaders()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private _rawHeaderString: string
|
|
186
|
+
private _rawHeaders: Record<string, string | Array<string>> | undefined
|
|
187
|
+
private _headers: Headers.Headers | undefined
|
|
188
|
+
get headers() {
|
|
189
|
+
if (this._headers) {
|
|
190
|
+
return this._headers
|
|
191
|
+
}
|
|
192
|
+
if (this._rawHeaderString === "") {
|
|
193
|
+
return this._headers = Headers.empty
|
|
194
|
+
}
|
|
195
|
+
const parser = HeaderParser.make()
|
|
196
|
+
const result = parser(encoder.encode(this._rawHeaderString + "\r\n"), 0)
|
|
197
|
+
this._rawHeaders = result._tag === "Headers" ? result.headers : undefined
|
|
198
|
+
const parsed = result._tag === "Headers" ? Headers.fromInput(result.headers) : Headers.empty
|
|
199
|
+
return this._headers = parsed
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
cachedCookies: Cookies.Cookies | undefined
|
|
203
|
+
get cookies() {
|
|
204
|
+
if (this.cachedCookies) {
|
|
205
|
+
return this.cachedCookies
|
|
206
|
+
}
|
|
207
|
+
if (this._rawHeaders === undefined) {
|
|
208
|
+
return Cookies.empty
|
|
209
|
+
} else if (this._rawHeaders["set-cookie"] === undefined) {
|
|
210
|
+
return this.cachedCookies = Cookies.empty
|
|
211
|
+
}
|
|
212
|
+
return this.cachedCookies = Cookies.fromSetCookie(this._rawHeaders["set-cookie"])
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
get remoteAddress() {
|
|
216
|
+
return undefined
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
_textEffect: Effect.Effect<string, E> | undefined
|
|
220
|
+
get text(): Effect.Effect<string, E> {
|
|
221
|
+
if (this._textEffect) {
|
|
222
|
+
return this._textEffect
|
|
223
|
+
}
|
|
224
|
+
return this._textEffect = Effect.callback<string, E>((resume) => {
|
|
225
|
+
if (this.source.readyState === 4) {
|
|
226
|
+
resume(Effect.succeed(this.source.responseText))
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const onReadyStateChange = () => {
|
|
231
|
+
if (this.source.readyState === 4) {
|
|
232
|
+
resume(Effect.succeed(this.source.responseText))
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const onError = () => {
|
|
236
|
+
resume(Effect.fail(this.onError(this.source.statusText)))
|
|
237
|
+
}
|
|
238
|
+
this.source.addEventListener("readystatechange", onReadyStateChange)
|
|
239
|
+
this.source.addEventListener("error", onError)
|
|
240
|
+
return Effect.sync(() => {
|
|
241
|
+
this.source.removeEventListener("readystatechange", onReadyStateChange)
|
|
242
|
+
this.source.removeEventListener("error", onError)
|
|
243
|
+
})
|
|
244
|
+
}).pipe(
|
|
245
|
+
Effect.cached,
|
|
246
|
+
Effect.runSync
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
get json(): Effect.Effect<unknown, E> {
|
|
251
|
+
return Effect.flatMap(this.text, (text) =>
|
|
252
|
+
Effect.try({
|
|
253
|
+
try: () => text === "" ? null : JSON.parse(text) as unknown,
|
|
254
|
+
catch: this.onError
|
|
255
|
+
}))
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
get urlParamsBody(): Effect.Effect<UrlParams.UrlParams, E> {
|
|
259
|
+
return Effect.flatMap(this.text, (text) =>
|
|
260
|
+
Effect.try({
|
|
261
|
+
try: () => UrlParams.fromInput(new URLSearchParams(text)),
|
|
262
|
+
catch: this.onError
|
|
263
|
+
}))
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
get stream(): Stream.Stream<Uint8Array, E> {
|
|
267
|
+
return Stream.callback<Uint8Array, E>((queue) => {
|
|
268
|
+
let offset = 0
|
|
269
|
+
const onReadyStateChange = () => {
|
|
270
|
+
if (this.source.readyState === 3) {
|
|
271
|
+
const encoded = encoder.encode(this.source.responseText.slice(offset))
|
|
272
|
+
Queue.offerUnsafe(queue, encoded)
|
|
273
|
+
offset = this.source.responseText.length
|
|
274
|
+
} else if (this.source.readyState === 4) {
|
|
275
|
+
const encoded = encoder.encode(this.source.responseText.slice(offset))
|
|
276
|
+
if (offset < this.source.responseText.length) {
|
|
277
|
+
Queue.offerUnsafe(queue, encoded)
|
|
278
|
+
}
|
|
279
|
+
Queue.endUnsafe(queue)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const onError = () => {
|
|
283
|
+
Queue.failCauseUnsafe(queue, Cause.fail(this.onError(this.source.statusText)))
|
|
284
|
+
}
|
|
285
|
+
this.source.addEventListener("readystatechange", onReadyStateChange)
|
|
286
|
+
this.source.addEventListener("error", onError)
|
|
287
|
+
onReadyStateChange()
|
|
288
|
+
return Effect.sync(() => {
|
|
289
|
+
this.source.removeEventListener("readystatechange", onReadyStateChange)
|
|
290
|
+
this.source.removeEventListener("error", onError)
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
_arrayBufferEffect: Effect.Effect<ArrayBuffer, E> | undefined
|
|
296
|
+
get arrayBuffer(): Effect.Effect<ArrayBuffer, E> {
|
|
297
|
+
if (this._arrayBufferEffect) {
|
|
298
|
+
return this._arrayBufferEffect
|
|
299
|
+
}
|
|
300
|
+
return this._arrayBufferEffect = Effect.callback<ArrayBuffer, E>((resume) => {
|
|
301
|
+
if (this.source.readyState === 4) {
|
|
302
|
+
resume(Effect.succeed(this.source.response))
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const onReadyStateChange = () => {
|
|
307
|
+
if (this.source.readyState === 4) {
|
|
308
|
+
resume(Effect.succeed(this.source.response))
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const onError = () => {
|
|
312
|
+
resume(Effect.fail(this.onError(this.source.statusText)))
|
|
313
|
+
}
|
|
314
|
+
this.source.addEventListener("readystatechange", onReadyStateChange)
|
|
315
|
+
this.source.addEventListener("error", onError)
|
|
316
|
+
return Effect.sync(() => {
|
|
317
|
+
this.source.removeEventListener("readystatechange", onReadyStateChange)
|
|
318
|
+
this.source.removeEventListener("error", onError)
|
|
319
|
+
})
|
|
320
|
+
}).pipe(
|
|
321
|
+
Effect.map((response) => {
|
|
322
|
+
if (typeof response === "string") {
|
|
323
|
+
const arr = encoder.encode(response)
|
|
324
|
+
return arr.byteLength !== arr.buffer.byteLength
|
|
325
|
+
? arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength)
|
|
326
|
+
: arr.buffer
|
|
327
|
+
}
|
|
328
|
+
return response
|
|
329
|
+
}),
|
|
330
|
+
Effect.cached,
|
|
331
|
+
Effect.runSync
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
class ClientResponseImpl extends IncomingMessageImpl<HttpClientError.HttpClientError>
|
|
337
|
+
implements HttpClientResponse.HttpClientResponse
|
|
338
|
+
{
|
|
339
|
+
readonly [HttpClientResponse.TypeId]: typeof HttpClientResponse.TypeId
|
|
340
|
+
readonly request: HttpClientRequest.HttpClientRequest
|
|
341
|
+
|
|
342
|
+
constructor(
|
|
343
|
+
request: HttpClientRequest.HttpClientRequest,
|
|
344
|
+
source: globalThis.XMLHttpRequest
|
|
345
|
+
) {
|
|
346
|
+
super(source, (cause) =>
|
|
347
|
+
new HttpClientError.HttpClientError({
|
|
348
|
+
reason: new HttpClientError.DecodeError({
|
|
349
|
+
request,
|
|
350
|
+
response: this,
|
|
351
|
+
cause
|
|
352
|
+
})
|
|
353
|
+
}))
|
|
354
|
+
this.request = request
|
|
355
|
+
this[HttpClientResponse.TypeId] = HttpClientResponse.TypeId
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
get status() {
|
|
359
|
+
return this.source.status
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
get formData(): Effect.Effect<FormData, HttpClientError.HttpClientError> {
|
|
363
|
+
return Effect.die("Not implemented")
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
override toString(): string {
|
|
367
|
+
return `ClientResponse(${this.status})`
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
toJSON(): unknown {
|
|
371
|
+
return HttpIncomingMessage.inspect(this, {
|
|
372
|
+
_id: "@effect/platform/HttpClientResponse",
|
|
373
|
+
request: this.request.toJSON(),
|
|
374
|
+
status: this.status
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
}
|
|
32
378
|
|
|
33
379
|
/**
|
|
34
380
|
* @since 1.0.0
|
|
35
|
-
* @category
|
|
381
|
+
* @category Layers
|
|
36
382
|
*/
|
|
37
|
-
export const
|
|
383
|
+
export const layerXMLHttpRequest: Layer.Layer<HttpClient.HttpClient> = HttpClient.layerMergedServices(
|
|
384
|
+
Effect.succeed(makeXmlHttpRequest)
|
|
385
|
+
)
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import type * as KeyValueStore from "@effect/platform/KeyValueStore"
|
|
5
4
|
import type * as Layer from "effect/Layer"
|
|
6
|
-
import * as
|
|
5
|
+
import * as KeyValueStore from "effect/unstable/persistence/KeyValueStore"
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* Creates a KeyValueStore layer that uses the browser's localStorage api.
|
|
8
|
+
* Creates a `KeyValueStore` layer that uses the browser's `localStorage` api.
|
|
9
|
+
*
|
|
10
|
+
* Values are stored between sessions.
|
|
10
11
|
*
|
|
11
12
|
* @since 1.0.0
|
|
12
|
-
* @category
|
|
13
|
+
* @category Layers
|
|
13
14
|
*/
|
|
14
|
-
export const layerLocalStorage: Layer.Layer<KeyValueStore.KeyValueStore> =
|
|
15
|
+
export const layerLocalStorage: Layer.Layer<KeyValueStore.KeyValueStore> = KeyValueStore.layerStorage(() =>
|
|
16
|
+
globalThis.localStorage
|
|
17
|
+
)
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
|
-
* Creates a KeyValueStore layer that uses the browser's sessionStorage api.
|
|
20
|
+
* Creates a `KeyValueStore` layer that uses the browser's `sessionStorage` api.
|
|
21
|
+
*
|
|
22
|
+
* Values are stored only for the current session.
|
|
18
23
|
*
|
|
19
24
|
* @since 1.0.0
|
|
20
|
-
* @category
|
|
25
|
+
* @category Layers
|
|
21
26
|
*/
|
|
22
|
-
export const layerSessionStorage: Layer.Layer<KeyValueStore.KeyValueStore> =
|
|
27
|
+
export const layerSessionStorage: Layer.Layer<KeyValueStore.KeyValueStore> = KeyValueStore.layerStorage(() =>
|
|
28
|
+
globalThis.sessionStorage
|
|
29
|
+
)
|
package/src/BrowserRuntime.ts
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
5
|
-
import
|
|
4
|
+
import type * as Effect from "effect/Effect"
|
|
5
|
+
import { makeRunMain, type Teardown } from "effect/Runtime"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @since 1.0.0
|
|
9
|
-
* @category
|
|
9
|
+
* @category Runtime
|
|
10
10
|
*/
|
|
11
|
-
export const runMain:
|
|
11
|
+
export const runMain: {
|
|
12
|
+
/**
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
* @category Runtime
|
|
15
|
+
*/
|
|
16
|
+
(
|
|
17
|
+
options?: {
|
|
18
|
+
readonly disableErrorReporting?: boolean | undefined
|
|
19
|
+
readonly teardown?: Teardown | undefined
|
|
20
|
+
}
|
|
21
|
+
): <E, A>(effect: Effect.Effect<A, E>) => void
|
|
22
|
+
/**
|
|
23
|
+
* @since 1.0.0
|
|
24
|
+
* @category Runtime
|
|
25
|
+
*/
|
|
26
|
+
<E, A>(
|
|
27
|
+
effect: Effect.Effect<A, E>,
|
|
28
|
+
options?: {
|
|
29
|
+
readonly disableErrorReporting?: boolean | undefined
|
|
30
|
+
readonly teardown?: Teardown | undefined
|
|
31
|
+
}
|
|
32
|
+
): void
|
|
33
|
+
} = makeRunMain(({ fiber }) => {
|
|
34
|
+
globalThis.addEventListener("beforeunload", () => {
|
|
35
|
+
fiber.interruptUnsafe(fiber.id)
|
|
36
|
+
})
|
|
37
|
+
})
|
package/src/BrowserSocket.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import * as Socket from "@effect/platform/Socket"
|
|
5
4
|
import * as Layer from "effect/Layer"
|
|
5
|
+
import * as Socket from "effect/unstable/socket/Socket"
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @since 1.0.0
|
|
9
|
-
* @category
|
|
9
|
+
* @category Layers
|
|
10
10
|
*/
|
|
11
11
|
export const layerWebSocket = (url: string, options?: {
|
|
12
12
|
readonly closeCodeIsError?: (code: number) => boolean
|
|
13
13
|
}): Layer.Layer<Socket.Socket> =>
|
|
14
|
-
Layer.
|
|
14
|
+
Layer.effect(Socket.Socket, Socket.makeWebSocket(url, options)).pipe(
|
|
15
15
|
Layer.provide(layerWebSocketConstructor)
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* A WebSocket constructor that uses globalThis.WebSocket
|
|
19
|
+
* A WebSocket constructor that uses `globalThis.WebSocket`.
|
|
20
20
|
*
|
|
21
21
|
* @since 1.0.0
|
|
22
|
-
* @category
|
|
22
|
+
* @category Layers
|
|
23
23
|
*/
|
|
24
24
|
export const layerWebSocketConstructor: Layer.Layer<Socket.WebSocketConstructor> =
|
|
25
25
|
Socket.layerWebSocketConstructorGlobal
|
package/src/BrowserStream.ts
CHANGED
|
@@ -2,33 +2,43 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import * as internal from "./internal/stream.js"
|
|
5
|
+
import * as Stream from "effect/Stream"
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* Creates a `Stream` from window.addEventListener
|
|
8
|
+
* Creates a `Stream` from `window.addEventListener`.
|
|
9
|
+
*
|
|
10
|
+
* By default, the underlying buffer is unbounded in size. You can customize the
|
|
11
|
+
* buffer size an object as the second argument with the `bufferSize` field.
|
|
12
|
+
*
|
|
10
13
|
* @since 1.0.0
|
|
14
|
+
* @category Streams
|
|
11
15
|
*/
|
|
12
|
-
export const fromEventListenerWindow
|
|
16
|
+
export const fromEventListenerWindow = <K extends keyof WindowEventMap>(
|
|
13
17
|
type: K,
|
|
14
18
|
options?: boolean | {
|
|
15
19
|
readonly capture?: boolean
|
|
16
20
|
readonly passive?: boolean
|
|
17
21
|
readonly once?: boolean
|
|
18
|
-
readonly bufferSize?: number |
|
|
22
|
+
readonly bufferSize?: number | undefined
|
|
19
23
|
} | undefined
|
|
20
|
-
)
|
|
24
|
+
): Stream.Stream<WindowEventMap[K], never, never> => Stream.fromEventListener<WindowEventMap[K]>(window, type, options)
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
|
-
* Creates a `Stream` from document.addEventListener
|
|
27
|
+
* Creates a `Stream` from `document.addEventListener`.
|
|
28
|
+
*
|
|
29
|
+
* By default, the underlying buffer is unbounded in size. You can customize the
|
|
30
|
+
* buffer size an object as the second argument with the `bufferSize` field.
|
|
31
|
+
*
|
|
24
32
|
* @since 1.0.0
|
|
33
|
+
* @category Streams
|
|
25
34
|
*/
|
|
26
|
-
export const fromEventListenerDocument
|
|
35
|
+
export const fromEventListenerDocument = <K extends keyof DocumentEventMap>(
|
|
27
36
|
type: K,
|
|
28
37
|
options?: boolean | {
|
|
29
38
|
readonly capture?: boolean
|
|
30
39
|
readonly passive?: boolean
|
|
31
40
|
readonly once?: boolean
|
|
32
|
-
readonly bufferSize?: number |
|
|
41
|
+
readonly bufferSize?: number | undefined
|
|
33
42
|
} | undefined
|
|
34
|
-
)
|
|
43
|
+
): Stream.Stream<DocumentEventMap[K], never, never> =>
|
|
44
|
+
Stream.fromEventListener<DocumentEventMap[K]>(document, type, options)
|
package/src/BrowserWorker.ts
CHANGED
|
@@ -1,33 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import * as
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export const layerManager: Layer.Layer<Worker.WorkerManager> = internal.layerManager
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @since 1.0.0
|
|
15
|
-
* @category layers
|
|
16
|
-
*/
|
|
17
|
-
export const layerWorker: Layer.Layer<Worker.PlatformWorker> = internal.layerWorker
|
|
4
|
+
import * as Deferred from "effect/Deferred"
|
|
5
|
+
import * as Effect from "effect/Effect"
|
|
6
|
+
import * as Layer from "effect/Layer"
|
|
7
|
+
import * as Scope from "effect/Scope"
|
|
8
|
+
import * as Worker from "effect/unstable/workers/Worker"
|
|
9
|
+
import { WorkerError, WorkerReceiveError } from "effect/unstable/workers/WorkerError"
|
|
18
10
|
|
|
19
11
|
/**
|
|
20
12
|
* @since 1.0.0
|
|
21
|
-
* @category
|
|
13
|
+
* @category Layers
|
|
22
14
|
*/
|
|
23
|
-
export const layer
|
|
15
|
+
export const layer = (
|
|
24
16
|
spawn: (id: number) => Worker | SharedWorker | MessagePort
|
|
25
|
-
)
|
|
17
|
+
): Layer.Layer<Worker.WorkerPlatform | Worker.Spawner> =>
|
|
18
|
+
Layer.merge(
|
|
19
|
+
layerPlatform,
|
|
20
|
+
Worker.layerSpawner(spawn)
|
|
21
|
+
)
|
|
26
22
|
|
|
27
23
|
/**
|
|
28
24
|
* @since 1.0.0
|
|
29
|
-
* @category
|
|
25
|
+
* @category Layers
|
|
30
26
|
*/
|
|
31
|
-
export const layerPlatform: (
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
export const layerPlatform: Layer.Layer<Worker.WorkerPlatform> = Layer.succeed(Worker.WorkerPlatform)(
|
|
28
|
+
Worker.makePlatform<globalThis.SharedWorker | globalThis.Worker | MessagePort>()({
|
|
29
|
+
setup({ scope, worker }) {
|
|
30
|
+
const port = "port" in worker ? worker.port : worker
|
|
31
|
+
return Effect.as(
|
|
32
|
+
Scope.addFinalizer(
|
|
33
|
+
scope,
|
|
34
|
+
Effect.sync(() => {
|
|
35
|
+
port.postMessage([1])
|
|
36
|
+
})
|
|
37
|
+
),
|
|
38
|
+
port
|
|
39
|
+
)
|
|
40
|
+
},
|
|
41
|
+
listen({ deferred, emit, port, scope }) {
|
|
42
|
+
function onMessage(event: MessageEvent) {
|
|
43
|
+
emit(event.data)
|
|
44
|
+
}
|
|
45
|
+
function onError(event: ErrorEvent) {
|
|
46
|
+
Deferred.doneUnsafe(
|
|
47
|
+
deferred,
|
|
48
|
+
new WorkerError({
|
|
49
|
+
reason: new WorkerReceiveError({
|
|
50
|
+
message: "An error event was emitter",
|
|
51
|
+
cause: event.error ?? event.message
|
|
52
|
+
})
|
|
53
|
+
}).asEffect()
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
port.addEventListener("message", onMessage as any)
|
|
57
|
+
port.addEventListener("error", onError as any)
|
|
58
|
+
if ("start" in port) {
|
|
59
|
+
port.start()
|
|
60
|
+
}
|
|
61
|
+
return Scope.addFinalizer(
|
|
62
|
+
scope,
|
|
63
|
+
Effect.sync(() => {
|
|
64
|
+
port.removeEventListener("message", onMessage as any)
|
|
65
|
+
port.removeEventListener("error", onError as any)
|
|
66
|
+
})
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
)
|