UNPKG

@typed/fp

Version:

Data Structures and Resources for fp-ts

123 lines 4.41 kB
/** * @typed/fp/browser is a place to place implementations of environment from other modules that require or * are best used with implementations specificall for the browser. * @since 0.9.4 */ import * as Ei from 'fp-ts/Either'; import * as D from './Disposable'; import * as E from './Env'; import * as R from './Resume'; import * as S from './Stream'; /** * @category Environment * @since 0.9.4 */ export const HttpEnv = { http: E.fromResumeK(httpFetchRequest) }; function httpFetchRequest(uri, options = {}) { return R.async((cb) => { const { method = 'GET', headers = {}, body } = options; const disposable = D.settable(); const abortController = new AbortController(); disposable.addDisposable({ dispose: () => abortController.abort(), }); const init = { method, headers: Object.entries(headers).map(([key, value = '']) => [key, value]), body, credentials: 'include', signal: abortController.signal, }; async function makeRequest() { const response = await fetch(uri, init); const headers = {}; response.headers.forEach((value, key) => { headers[key] = value; }); const httpResponse = { status: response.status, body: await response.json().catch(() => response.text()), headers, }; if (!disposable.isDisposed()) { disposable.addDisposable(cb(Ei.right(httpResponse))); } } makeRequest().catch((error) => { if (!disposable.isDisposed()) { disposable.addDisposable(cb(Ei.left(error))); } }); return disposable; }); } /** * Constructs an Adapter that utilizes a BroadcastChannel to communicate messages across * all scripts of the same origin, including workers. * * _Note:_ An error will occur, and the stream will fail, if you send events which cannot be * structurally cloned. See * https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm * @category Constructor * @since 0.12.2 */ export const broadcastChannel = (name) => { const channel = new BroadcastChannel(name); const send = (event) => channel.postMessage(event); const stream = S.newStream((sink, scheduler) => { const onMessage = (event) => sink.event(scheduler.currentTime(), event.data); const onMessageError = (event) => sink.error(scheduler.currentTime(), event.data); channel.addEventListener('message', onMessage); channel.addEventListener('messageerror', onMessageError); return { dispose: () => { channel.removeEventListener('message', onMessage); channel.removeEventListener('messageerror', onMessageError); }, }; }); return [send, stream]; }; /** * Utilize the Crypto API to generate 8-bit numbers * @category Constructor * @since 0.12.2 */ export const random8Bits = (count) => E.fromIO(() => [...crypto.getRandomValues(new Uint8Array(count))]); /** * Utilize the Crypto API to generate 16-bit numbers * @category Constructor * @since 0.12.2 */ export const random16Bits = (count) => E.fromIO(() => [...crypto.getRandomValues(new Uint16Array(count))]); /** * Utilize the Crypto API to generate 32-bit numbers * @category Constructor * @since 0.12.2 */ export const random32Bits = (count) => E.fromIO(() => [...crypto.getRandomValues(new Uint32Array(count))]); /** * @category Environment * @since 0.13.2 */ export const rafEnv = { raf: R.async((resume) => { const disposable = D.settable(); let handle = requestAnimationFrame(() => (handle = requestAnimationFrame((n) => disposable.addDisposable(resume(n))))); disposable.addDisposable({ dispose: () => cancelAnimationFrame(handle) }); return disposable; }), }; /** * @category Environment * @since 0.13.2 */ export const whenIdleEnv = { whenIdle: R.async((cb) => { const disposable = D.settable(); const handle = window.requestIdleCallback((d) => disposable.addDisposable(cb(d))); disposable.addDisposable({ dispose: () => cancelAnimationFrame(handle) }); return disposable; }), }; //# sourceMappingURL=browser.js.map