reflected 0.1.3 → 0.1.5
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 +2 -2
- package/dist/{async-CYIlyalV.js → async-CDZL7tYL.js} +1 -1
- package/dist/async.js +1 -1
- package/dist/{broadcast-BDDwfg2T.js → broadcast-D1fpCELk.js} +1 -1
- package/dist/broadcast.js +1 -1
- package/dist/ffi/{async-GRzyB2di.js → async-CwB3HVh4.js} +1 -1
- package/dist/ffi/{async-BNBXm5a_.js → async-DhVtZ4wl.js} +1 -1
- package/dist/ffi/{broadcast-By0cJHF9.js → broadcast-BAquhdtc.js} +1 -1
- package/dist/ffi/{broadcast-BqHn8hZt.js → broadcast-C0yTW057.js} +1 -1
- package/dist/ffi/main.js +1 -1
- package/dist/ffi/{message-HrRNTxf_.js → message-BDLi9xtr.js} +1 -1
- package/dist/ffi/{message-BDoj0Sat.js → message-CJgJHezK.js} +1 -1
- package/dist/ffi/{sender-BT8LRjVR.js → sender-BskapjNv.js} +1 -1
- package/dist/ffi/{sender-Cg6GoMam.js → sender-oKBWXO4e.js} +1 -1
- package/dist/ffi/{shared-BGovulqy.js → shared-CEDblaxF.js} +1 -1
- package/dist/ffi/{shared-DO64_ikX.js → shared-CgVCTgQi.js} +1 -1
- package/dist/ffi/worker.js +1 -1
- package/dist/ffi/{xhr-DncbZcB-.js → xhr-Bph_vID8.js} +1 -1
- package/dist/ffi/{xhr-mth_w1Qg.js → xhr-DpdgA5CQ.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{message-Dt36xGK4.js → message-CnhrtE83.js} +1 -1
- package/dist/message.js +1 -1
- package/dist/{sender-DL3isFNg.js → sender-D2z-45zI.js} +1 -1
- package/dist/{shared-DPsM-o7V.js → shared-d1h2fx_s.js} +1 -1
- package/dist/{xhr-1Wu8YOTt.js → xhr-CHdFcg-8.js} +1 -1
- package/dist/xhr.js +1 -1
- package/package.json +12 -8
- package/reflected.tar.gz +0 -0
- package/rollup.js +0 -75
- package/src/async.js +0 -8
- package/src/broadcast.js +0 -8
- package/src/channel.js +0 -1
- package/src/ffi/main.js +0 -37
- package/src/ffi/worker.js +0 -24
- package/src/index.js +0 -57
- package/src/main/async.js +0 -29
- package/src/main/broadcast.js +0 -21
- package/src/main/message.js +0 -20
- package/src/main/sab.js +0 -12
- package/src/main/sender.js +0 -38
- package/src/main/shared.js +0 -99
- package/src/main/xhr.js +0 -102
- package/src/message.js +0 -8
- package/src/service/listeners.js +0 -47
- package/src/service/worker.js +0 -5
- package/src/shared.js +0 -12
- package/src/worker/async.js +0 -40
- package/src/worker/broadcast.js +0 -11
- package/src/worker/message.js +0 -11
- package/src/worker/sender.js +0 -16
- package/src/worker/shared.js +0 -52
- package/src/worker/xhr.js +0 -40
- package/src/xhr.js +0 -8
- package/test/README/index.html +0 -11
- package/test/README/index.js +0 -50
- package/test/README/worker.js +0 -26
- package/test/ffi/index.html +0 -10
- package/test/ffi/index.js +0 -8
- package/test/ffi/sw.js +0 -1
- package/test/ffi/worker.js +0 -13
- package/test/index.html +0 -17
- package/test/index.js +0 -35
- package/test/mini-coi.js +0 -28
- package/test/sw.js +0 -1
- package/test/worker.js +0 -22
- package/types/reflected/src/async.d.ts +0 -3
- package/types/reflected/src/broadcast.d.ts +0 -3
- package/types/reflected/src/channel.d.ts +0 -2
- package/types/reflected/src/index.d.ts +0 -3
- package/types/reflected/src/main/async.d.ts +0 -7
- package/types/reflected/src/main/broadcast.d.ts +0 -2
- package/types/reflected/src/main/message.d.ts +0 -2
- package/types/reflected/src/main/sab.d.ts +0 -5
- package/types/reflected/src/main/sender.d.ts +0 -5
- package/types/reflected/src/main/shared.d.ts +0 -44
- package/types/reflected/src/main/xhr.d.ts +0 -2
- package/types/reflected/src/message.d.ts +0 -3
- package/types/reflected/src/service/listeners.d.ts +0 -3
- package/types/reflected/src/service/worker.d.ts +0 -1
- package/types/reflected/src/shared.d.ts +0 -1
- package/types/reflected/src/worker/async.d.ts +0 -3
- package/types/reflected/src/worker/broadcast.d.ts +0 -3
- package/types/reflected/src/worker/message.d.ts +0 -3
- package/types/reflected/src/worker/sender.d.ts +0 -2
- package/types/reflected/src/worker/shared.d.ts +0 -11
- package/types/reflected/src/worker/xhr.d.ts +0 -3
- package/types/reflected/src/xhr.d.ts +0 -3
- package/types/weak-id/i32.d.ts +0 -2
package/src/ffi/worker.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import remote from 'reflected-ffi/remote';
|
|
2
|
-
|
|
3
|
-
import worker from '../index.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {import('../index.js').WorkerOptions & import('reflected-ffi/remote').RemoteOptions} options
|
|
7
|
-
*/
|
|
8
|
-
export default async options => {
|
|
9
|
-
const reflected = await worker({
|
|
10
|
-
...options,
|
|
11
|
-
onsync: args => args,
|
|
12
|
-
// @ts-ignore
|
|
13
|
-
onsend: args => ffi.reflect(...args),
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const ffi = remote({
|
|
17
|
-
timeout: 0,
|
|
18
|
-
buffer: true,
|
|
19
|
-
...options,
|
|
20
|
-
reflect: (...args) => reflected(args),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
return ffi;
|
|
24
|
-
};
|
package/src/index.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { native } from '@webreflection/utils/shared-array-buffer';
|
|
3
|
-
|
|
4
|
-
/** @typedef {import('./main/shared.js').Options} MainOptions */
|
|
5
|
-
/** @typedef {import('./worker/shared.js').Options} WorkerOptions */
|
|
6
|
-
|
|
7
|
-
/** @type {string} */
|
|
8
|
-
let channel;
|
|
9
|
-
|
|
10
|
-
/** @type {Function} */
|
|
11
|
-
let module;
|
|
12
|
-
|
|
13
|
-
if ('importScripts' in globalThis) {
|
|
14
|
-
let get;
|
|
15
|
-
const { promise, resolve } = withResolvers();
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
const reflected = new URL(location).searchParams.get('reflected');
|
|
18
|
-
channel = reflected;
|
|
19
|
-
if (reflected === 'message') get = import(/* webpackIgnore: true */'./worker/message.js');
|
|
20
|
-
else if (reflected === 'broadcast') get = import(/* webpackIgnore: true */'./worker/broadcast.js');
|
|
21
|
-
else if (reflected === 'xhr') get = import(/* webpackIgnore: true */'./worker/xhr.js');
|
|
22
|
-
else get = import(/* webpackIgnore: true */'./worker/async.js');
|
|
23
|
-
module = async options => {
|
|
24
|
-
const { data, ports } = await promise;
|
|
25
|
-
const { default: reflect } = await get;
|
|
26
|
-
const event = new Event('message');
|
|
27
|
-
// @ts-ignore
|
|
28
|
-
event.data = data;
|
|
29
|
-
// @ts-ignore
|
|
30
|
-
event.ports = ports;
|
|
31
|
-
dispatchEvent(event);
|
|
32
|
-
return reflect(options);
|
|
33
|
-
};
|
|
34
|
-
addEventListener('message', resolve, { once: true });
|
|
35
|
-
}
|
|
36
|
-
else if (native) {
|
|
37
|
-
if ('InstallTrigger' in globalThis) {
|
|
38
|
-
channel = 'broadcast';
|
|
39
|
-
module = (await import(/* webpackIgnore: true */'./main/broadcast.js')).default;
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
channel = 'message';
|
|
43
|
-
module = (await import(/* webpackIgnore: true */'./main/message.js')).default;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else if (navigator.serviceWorker) {
|
|
47
|
-
channel = 'xhr';
|
|
48
|
-
module = (await import(/* webpackIgnore: true */'./main/xhr.js')).default;
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
channel = 'async';
|
|
52
|
-
module = (await import(/* webpackIgnore: true */'./main/async.js')).default;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export { channel };
|
|
56
|
-
|
|
57
|
-
export default module;
|
package/src/main/async.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import Sender from './sender.js';
|
|
2
|
-
import SAB from './sab.js';
|
|
3
|
-
import { bootstrap, handler, post, url } from './shared.js';
|
|
4
|
-
import { byteOffset, randomUUID } from '../shared.js';
|
|
5
|
-
|
|
6
|
-
const CHANNEL = 'async';
|
|
7
|
-
|
|
8
|
-
export class Worker extends Sender {
|
|
9
|
-
constructor(scriptURL, options, resolve) {
|
|
10
|
-
const channel = randomUUID();
|
|
11
|
-
const bc = new BroadcastChannel(channel);
|
|
12
|
-
const sab = SAB(options);
|
|
13
|
-
const i32a = new Int32Array(sab);
|
|
14
|
-
const handle = handler(sab, options, false);
|
|
15
|
-
bc.addEventListener('message', async ({ data: [id, payload] }) => {
|
|
16
|
-
await handle({ data: payload });
|
|
17
|
-
bc.postMessage([id, new Uint8Array(sab, byteOffset, i32a[1])]);
|
|
18
|
-
});
|
|
19
|
-
super(...url(scriptURL, CHANNEL, options));
|
|
20
|
-
super.addEventListener('message', () => resolve(this), { once: true });
|
|
21
|
-
super.postMessage(post(sab, options).concat(channel));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get channel() {
|
|
25
|
-
return CHANNEL;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default bootstrap(Worker);
|
package/src/main/broadcast.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import Sender from './sender.js';
|
|
2
|
-
import { SAB, bootstrap, handler, post, url } from './shared.js';
|
|
3
|
-
import { randomUUID } from '../shared.js';
|
|
4
|
-
|
|
5
|
-
const CHANNEL = 'broadcast';
|
|
6
|
-
|
|
7
|
-
export default bootstrap(class Worker extends Sender {
|
|
8
|
-
constructor(scriptURL, options, resolve) {
|
|
9
|
-
const channel = randomUUID();
|
|
10
|
-
const bc = new BroadcastChannel(channel);
|
|
11
|
-
const sab = SAB(options);
|
|
12
|
-
bc.addEventListener('message', handler(sab, options, true));
|
|
13
|
-
super(...url(scriptURL, CHANNEL, options));
|
|
14
|
-
super.addEventListener('message', () => resolve(this), { once: true });
|
|
15
|
-
super.postMessage(post(sab, options).concat(channel));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
get channel() {
|
|
19
|
-
return CHANNEL;
|
|
20
|
-
}
|
|
21
|
-
});
|
package/src/main/message.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import Sender from './sender.js';
|
|
2
|
-
import { SAB, bootstrap, handler, post, url } from './shared.js';
|
|
3
|
-
|
|
4
|
-
const CHANNEL = 'message';
|
|
5
|
-
|
|
6
|
-
export default bootstrap(class Worker extends Sender {
|
|
7
|
-
constructor(scriptURL, options, resolve) {
|
|
8
|
-
const { port1, port2 } = new MessageChannel;
|
|
9
|
-
const sab = SAB(options);
|
|
10
|
-
port1.addEventListener(CHANNEL, handler(sab, options, true));
|
|
11
|
-
port1.start();
|
|
12
|
-
super(...url(scriptURL, CHANNEL, options));
|
|
13
|
-
super.addEventListener(CHANNEL, () => resolve(this), { once: true });
|
|
14
|
-
super.postMessage(post(sab, options), [port2]);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
get channel() {
|
|
18
|
-
return CHANNEL;
|
|
19
|
-
}
|
|
20
|
-
});
|
package/src/main/sab.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { SharedArrayBuffer } from '@webreflection/utils/shared-array-buffer';
|
|
2
|
-
|
|
3
|
-
import { byteOffset } from '../shared.js';
|
|
4
|
-
|
|
5
|
-
export default ({
|
|
6
|
-
initByteLength = 1024,
|
|
7
|
-
maxByteLength = (1024 * 8)
|
|
8
|
-
}) =>
|
|
9
|
-
new SharedArrayBuffer(
|
|
10
|
-
byteOffset + initByteLength,
|
|
11
|
-
{ maxByteLength: byteOffset + maxByteLength }
|
|
12
|
-
);
|
package/src/main/sender.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import i32 from 'weak-id/i32';
|
|
3
|
-
|
|
4
|
-
import SHARED_CHANNEL from '../channel.js';
|
|
5
|
-
|
|
6
|
-
const { isArray } = Array;
|
|
7
|
-
|
|
8
|
-
const onsend = value => value;
|
|
9
|
-
|
|
10
|
-
export default class Sender extends Worker {
|
|
11
|
-
#next;
|
|
12
|
-
#requests;
|
|
13
|
-
constructor(scriptURL, options) {
|
|
14
|
-
super(scriptURL, options);
|
|
15
|
-
this.#next = i32();
|
|
16
|
-
this.#requests = new Map;
|
|
17
|
-
if (!options.onsend) options.onsend = onsend;
|
|
18
|
-
super.addEventListener('message', async event => {
|
|
19
|
-
const { data } = event;
|
|
20
|
-
if (isArray(data) && data.length === 2 && data[0] === SHARED_CHANNEL) {
|
|
21
|
-
event.stopImmediatePropagation();
|
|
22
|
-
event.preventDefault();
|
|
23
|
-
const [id, payload] = data[1];
|
|
24
|
-
const resolve = this.#requests.get(id);
|
|
25
|
-
this.#requests.delete(id);
|
|
26
|
-
resolve(await options.onsend(payload));
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
send(payload, ...rest) {
|
|
32
|
-
const id = this.#next();
|
|
33
|
-
const { promise, resolve } = withResolvers();
|
|
34
|
-
this.#requests.set(id, resolve);
|
|
35
|
-
super.postMessage([SHARED_CHANNEL, [id, payload]], ...rest);
|
|
36
|
-
return promise;
|
|
37
|
-
}
|
|
38
|
-
}
|
package/src/main/shared.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { encoder } from 'reflected-ffi/encoder';
|
|
3
|
-
|
|
4
|
-
import { byteOffset } from '../shared.js';
|
|
5
|
-
|
|
6
|
-
const { notify, store } = Atomics;
|
|
7
|
-
|
|
8
|
-
export const SAB = ({
|
|
9
|
-
initByteLength = 1024,
|
|
10
|
-
maxByteLength = (1024 * 8)
|
|
11
|
-
}) =>
|
|
12
|
-
new SharedArrayBuffer(
|
|
13
|
-
byteOffset + initByteLength,
|
|
14
|
-
{ maxByteLength: byteOffset + maxByteLength }
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {Object} ServiceWorkerOptions see https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register#options
|
|
19
|
-
* @property {string} [url] will use the `serviceWorker` value if that is a `string`, otherwise it refers to where the service worker file is located.
|
|
20
|
-
* @property {'classic' | 'module'} [type]
|
|
21
|
-
* @property {'all' | 'imports' | 'none'} [updateViaCache]
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {Object} Options
|
|
26
|
-
* @property {(payload: unknown) => Int32Array | Promise<Int32Array>} onsync invoked when the worker expect a response as `Int32Array` to populate the SharedArrayBuffer with.
|
|
27
|
-
* @property {(payload: unknown) => unknown | Promise<unknown>} [onsend] invoked when the worker replies to a `worker.send(data)` call.
|
|
28
|
-
* @property {number} [initByteLength=1024] defines the initial byte length of the SharedArrayBuffer.
|
|
29
|
-
* @property {number} [maxByteLength=8192] defines the maximum byte length (growth) of the SharedArrayBuffer.
|
|
30
|
-
* @property {string | ServiceWorkerOptions} [serviceWorker] defines the service worker to use as fallback if SharedArrayBuffer is not supported. If not defined, the `async` fallback will be used so that no `sync` operations from the worker will be possible.
|
|
31
|
-
* @property {import('reflected-ffi/encoder').encoder} [encoder] defines the encoder function to use to encode the result into the SharedArrayBuffer.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Initialize the worker channel communication and resolves with the worker instance.
|
|
36
|
-
* @template T
|
|
37
|
-
* @param {T} Worker
|
|
38
|
-
* @returns
|
|
39
|
-
*/
|
|
40
|
-
export const bootstrap = Worker => {
|
|
41
|
-
/**
|
|
42
|
-
* @param {string} scriptURL
|
|
43
|
-
* @param {Options} options
|
|
44
|
-
* @returns
|
|
45
|
-
*/
|
|
46
|
-
return (scriptURL, options) => {
|
|
47
|
-
const { promise, resolve } = withResolvers();
|
|
48
|
-
// @ts-ignore
|
|
49
|
-
new Worker(scriptURL, options, resolve);
|
|
50
|
-
return /** @type {Promise<T>} */(promise);
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const handler = (sab, options, useAtomics) => {
|
|
55
|
-
const i32a = new Int32Array(sab);
|
|
56
|
-
const encode = (options.encoder ?? encoder)({ byteOffset });
|
|
57
|
-
|
|
58
|
-
const resolve = useAtomics ?
|
|
59
|
-
(length => {
|
|
60
|
-
store(i32a, 1, length);
|
|
61
|
-
store(i32a, 0, 1);
|
|
62
|
-
notify(i32a, 0);
|
|
63
|
-
}) :
|
|
64
|
-
(length => {
|
|
65
|
-
i32a[1] = length;
|
|
66
|
-
i32a[0] = 1;
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const process = result => {
|
|
70
|
-
const length = encode(result, sab);
|
|
71
|
-
return typeof length === 'number' ? resolve(length) : length.then(resolve);
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
return async ({ data }) => process(await options.onsync(data));
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const isOK = value => {
|
|
78
|
-
switch (typeof value) {
|
|
79
|
-
case 'symbol':
|
|
80
|
-
case 'function':
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
return true;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export const post = (sab, options) => {
|
|
87
|
-
const opts = {};
|
|
88
|
-
for (const key in options) {
|
|
89
|
-
const value = options[key];
|
|
90
|
-
if (isOK(key) && isOK(value)) opts[key] = value;
|
|
91
|
-
}
|
|
92
|
-
return [sab, opts];
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export const url = (scriptURL, reflected, options) => {
|
|
96
|
-
const url = new URL(scriptURL, location.href);
|
|
97
|
-
url.searchParams.set('reflected', reflected);
|
|
98
|
-
return [url, { ...options, type: 'module' }];
|
|
99
|
-
};
|
package/src/main/xhr.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { Worker as AsyncWorker } from './async.js';
|
|
3
|
-
|
|
4
|
-
import SHARED_CHANNEL from '../channel.js';
|
|
5
|
-
import SAB from './sab.js';
|
|
6
|
-
import Sender from './sender.js';
|
|
7
|
-
|
|
8
|
-
import { handler, post, url } from './shared.js';
|
|
9
|
-
import { byteOffset, randomUUID } from '../shared.js';
|
|
10
|
-
|
|
11
|
-
const CHANNEL = 'xhr';
|
|
12
|
-
|
|
13
|
-
const channels = new Map;
|
|
14
|
-
|
|
15
|
-
const sharedBC = new BroadcastChannel(SHARED_CHANNEL);
|
|
16
|
-
sharedBC.addEventListener('message', async ({ data: [op, details] }) => {
|
|
17
|
-
if (op === 'request') {
|
|
18
|
-
const [uid, [id, channel]] = details;
|
|
19
|
-
const responses = channels.get(channel);
|
|
20
|
-
if (responses) {
|
|
21
|
-
const promise = responses.get(id);
|
|
22
|
-
responses.delete(id);
|
|
23
|
-
sharedBC.postMessage(['response', [uid, await promise]]);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const { promise: sw, resolve } = withResolvers();
|
|
29
|
-
let init = true;
|
|
30
|
-
|
|
31
|
-
const activate = (swc, options) => {
|
|
32
|
-
let w, c = true, { url } = options;
|
|
33
|
-
swc.getRegistration(url)
|
|
34
|
-
.then(r => (r ?? swc.register(url, options)))
|
|
35
|
-
.then(function ready(r) {
|
|
36
|
-
const { controller } = swc;
|
|
37
|
-
c = c && !!controller;
|
|
38
|
-
w = (r.installing || r.waiting || r.active);
|
|
39
|
-
if (!w) return activate(swc, options);
|
|
40
|
-
if (w.state === 'activated') {
|
|
41
|
-
if (c) {
|
|
42
|
-
// allow ServiceWorker swap on different URL
|
|
43
|
-
if (controller.scriptURL === url)
|
|
44
|
-
return resolve();
|
|
45
|
-
r.unregister();
|
|
46
|
-
}
|
|
47
|
-
location.reload();
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
w.addEventListener('statechange', () => ready(r), { once: true });
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
class Worker extends Sender {
|
|
56
|
-
#channel;
|
|
57
|
-
constructor(scriptURL, options, resolve) {
|
|
58
|
-
if (init) {
|
|
59
|
-
init = false;
|
|
60
|
-
let { serviceWorker } = options;
|
|
61
|
-
if (!serviceWorker) {
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
return new AsyncWorker(scriptURL, options, resolve);
|
|
64
|
-
}
|
|
65
|
-
if (typeof serviceWorker === 'string') serviceWorker = { url: serviceWorker };
|
|
66
|
-
serviceWorker.url = new URL(serviceWorker.url, location.href).href;
|
|
67
|
-
activate(navigator.serviceWorker, serviceWorker);
|
|
68
|
-
}
|
|
69
|
-
const channel = randomUUID();
|
|
70
|
-
const bc = new BroadcastChannel(channel);
|
|
71
|
-
const sab = SAB(options);
|
|
72
|
-
const responses = new Map;
|
|
73
|
-
const i32a = new Int32Array(sab);
|
|
74
|
-
const handle = handler(sab, options, false);
|
|
75
|
-
channels.set(channel, responses);
|
|
76
|
-
bc.addEventListener('message', async ({ data: [id, payload] }) => {
|
|
77
|
-
const { promise, resolve } = withResolvers();
|
|
78
|
-
responses.set(id, promise);
|
|
79
|
-
await handle({ data: payload });
|
|
80
|
-
resolve(new Uint8Array(sab, byteOffset, i32a[1]));
|
|
81
|
-
});
|
|
82
|
-
super(...url(scriptURL, CHANNEL, options));
|
|
83
|
-
super.addEventListener('message', () => resolve(this), { once: true });
|
|
84
|
-
super.postMessage(post(sab, options).concat(channel));
|
|
85
|
-
this.#channel = channel;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
terminate() {
|
|
89
|
-
channels.delete(this.#channel);
|
|
90
|
-
super.terminate();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
get channel() {
|
|
94
|
-
return CHANNEL;
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export default (scriptURL, options) => {
|
|
99
|
-
const { promise, resolve } = withResolvers();
|
|
100
|
-
const worker = new Worker(scriptURL, options, resolve);
|
|
101
|
-
return worker instanceof AsyncWorker ? promise : sw.then(() => promise);
|
|
102
|
-
};
|
package/src/message.js
DELETED
package/src/service/listeners.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import CHANNEL from '../channel.js';
|
|
2
|
-
|
|
3
|
-
import nextResolver from 'next-resolver';
|
|
4
|
-
|
|
5
|
-
const [next, resolve] = nextResolver();
|
|
6
|
-
|
|
7
|
-
const { protocol, host, pathname } = location;
|
|
8
|
-
const url = `${protocol}//${host}${pathname}`;
|
|
9
|
-
|
|
10
|
-
const bc = new BroadcastChannel(CHANNEL);
|
|
11
|
-
bc.addEventListener('message', ({ data: [op, details] }) => {
|
|
12
|
-
if (op === 'response') {
|
|
13
|
-
const [uid, payload] = details;
|
|
14
|
-
resolve(uid, `[${payload.join(',')}]`);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const response = {
|
|
19
|
-
status: 200,
|
|
20
|
-
statusText: 'OK',
|
|
21
|
-
headers: new Headers({
|
|
22
|
-
'Cache-Control': 'no-cache, must-revalidate',
|
|
23
|
-
'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
|
|
24
|
-
'Content-type': 'application/json',
|
|
25
|
-
})
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const respond = async details => {
|
|
29
|
-
const [uid, promise] = next();
|
|
30
|
-
bc.postMessage(['request', [uid, details]]);
|
|
31
|
-
return new Response(await promise, response);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// @ts-ignore
|
|
35
|
-
export const activate = event => event.waitUntil(clients.claim());
|
|
36
|
-
|
|
37
|
-
export const fetch = async event => {
|
|
38
|
-
const { request: r } = event;
|
|
39
|
-
if (r.method === 'POST' && r.url.startsWith(url)) {
|
|
40
|
-
event.stopImmediatePropagation();
|
|
41
|
-
event.respondWith(r.json().then(respond));
|
|
42
|
-
event.preventDefault();
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// @ts-ignore
|
|
47
|
-
export const install = () => skipWaiting();
|
package/src/service/worker.js
DELETED
package/src/shared.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export const byteOffset = Int32Array.BYTES_PER_ELEMENT * 2;
|
|
2
|
-
|
|
3
|
-
let hasRandomUUID = true;
|
|
4
|
-
try {
|
|
5
|
-
crypto.randomUUID();
|
|
6
|
-
} catch (_) {
|
|
7
|
-
hasRandomUUID = false;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const randomUUID = hasRandomUUID ?
|
|
11
|
-
(() => crypto.randomUUID() ):
|
|
12
|
-
(() => (Date.now() + Math.random()).toString(36));
|
package/src/worker/async.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { decoder } from 'reflected-ffi/decoder';
|
|
3
|
-
import i32 from 'weak-id/i32';
|
|
4
|
-
|
|
5
|
-
import sender from './sender.js';
|
|
6
|
-
import { byteOffset } from '../shared.js';
|
|
7
|
-
|
|
8
|
-
const { promise, resolve } = withResolvers();
|
|
9
|
-
|
|
10
|
-
addEventListener(
|
|
11
|
-
'message',
|
|
12
|
-
({ data: [_, main, channel] }) => resolve([main, channel]),
|
|
13
|
-
{ once: true }
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
export const channel = 'async';
|
|
17
|
-
|
|
18
|
-
const handle = (channel, options) => {
|
|
19
|
-
const bc = new BroadcastChannel(channel);
|
|
20
|
-
const next = i32();
|
|
21
|
-
const decode = (options.decoder ?? decoder)({ byteOffset });
|
|
22
|
-
const map = new Map;
|
|
23
|
-
bc.addEventListener('message', ({ data: [id, { length, buffer }] }) => {
|
|
24
|
-
map.get(id)(options.onsync(length ? decode(length, buffer) : void 0));
|
|
25
|
-
map.delete(id);
|
|
26
|
-
});
|
|
27
|
-
return (payload, ...rest) => {
|
|
28
|
-
const { promise, resolve } = withResolvers();
|
|
29
|
-
const id = next();
|
|
30
|
-
map.set(id, resolve);
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
bc.postMessage([id, payload], ...rest);
|
|
33
|
-
return promise;
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export default options => promise.then(([main, channel]) => {
|
|
38
|
-
postMessage(1);
|
|
39
|
-
return handle(channel, sender({ ...main, ...options }));
|
|
40
|
-
});
|
package/src/worker/broadcast.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { handler } from './shared.js';
|
|
3
|
-
|
|
4
|
-
const { promise, resolve } = withResolvers();
|
|
5
|
-
|
|
6
|
-
export const channel = 'broadcast';
|
|
7
|
-
|
|
8
|
-
export default handler(
|
|
9
|
-
promise,
|
|
10
|
-
({ data: [sab, main, channel] }) => resolve([sab, main, new BroadcastChannel(channel)]),
|
|
11
|
-
);
|
package/src/worker/message.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { handler } from './shared.js';
|
|
3
|
-
|
|
4
|
-
const { promise, resolve } = withResolvers();
|
|
5
|
-
|
|
6
|
-
export const channel = 'message';
|
|
7
|
-
|
|
8
|
-
export default handler(
|
|
9
|
-
promise,
|
|
10
|
-
({ data: [sab, main], ports: [channel] }) => resolve([sab, main, channel])
|
|
11
|
-
);
|
package/src/worker/sender.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import SHARED_CHANNEL from '../channel.js';
|
|
2
|
-
|
|
3
|
-
const { isArray } = Array;
|
|
4
|
-
|
|
5
|
-
export default options => {
|
|
6
|
-
addEventListener('message', async event => {
|
|
7
|
-
const { data } = event;
|
|
8
|
-
if (isArray(data) && data[0] === SHARED_CHANNEL) {
|
|
9
|
-
event.stopImmediatePropagation();
|
|
10
|
-
event.preventDefault();
|
|
11
|
-
const [id, payload] = data[1];
|
|
12
|
-
postMessage([SHARED_CHANNEL, [id, await options.onsend(payload)]]);
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
return options;
|
|
16
|
-
};
|
package/src/worker/shared.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { decoder } from 'reflected-ffi/decoder';
|
|
2
|
-
|
|
3
|
-
import sender from './sender.js';
|
|
4
|
-
import { byteOffset } from '../shared.js';
|
|
5
|
-
|
|
6
|
-
const { load, store, wait } = Atomics;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {Object} Options
|
|
10
|
-
* @property {(payload: Int32Array) => unknown} onsync transforms the resulting `Int32Array` from *main* thread into a value usable within the worker.
|
|
11
|
-
* @property {(payload: unknown) => unknown |Promise<unknown>} onsend invoked to define what to return to the *main* thread when it calls `worker.send(payload)`.
|
|
12
|
-
* @property {import('reflected-ffi/decoder').decoder} [decoder] defines the decoder function to use to decode the result from the SharedArrayBuffer.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {MessageChannel | BroadcastChannel} channel
|
|
17
|
-
* @param {Int32Array} i32a
|
|
18
|
-
* @param {Options} options
|
|
19
|
-
* @returns {(payload: unknown, ...rest: unknown[]) => unknown}
|
|
20
|
-
*/
|
|
21
|
-
const handle = (channel, i32a, options) => {
|
|
22
|
-
const decode = (options.decoder ?? decoder)({ byteOffset });
|
|
23
|
-
const { buffer } = i32a;
|
|
24
|
-
return (payload, ...rest) => {
|
|
25
|
-
// @ts-ignore
|
|
26
|
-
channel.postMessage(payload, ...rest);
|
|
27
|
-
wait(i32a, 0, 0);
|
|
28
|
-
store(i32a, 0, 0);
|
|
29
|
-
const length = load(i32a, 1);
|
|
30
|
-
return options.onsync(length ? decode(length, buffer) : void 0);
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
*
|
|
36
|
-
* @param {Promise<[SharedArrayBuffer, Options, MessageChannel | BroadcastChannel]>} promise
|
|
37
|
-
* @param {(event:MessageEvent) => void} listener
|
|
38
|
-
* @returns
|
|
39
|
-
*/
|
|
40
|
-
export const handler = (promise, listener) => {
|
|
41
|
-
addEventListener('message', listener, { once: true });
|
|
42
|
-
/**
|
|
43
|
-
* @param {Options} options
|
|
44
|
-
* @returns
|
|
45
|
-
*/
|
|
46
|
-
return options => promise.then(
|
|
47
|
-
([sab, main, channel]) => {
|
|
48
|
-
postMessage(1);
|
|
49
|
-
return handle(channel, new Int32Array(sab), sender({ ...main, ...options }));
|
|
50
|
-
}
|
|
51
|
-
);
|
|
52
|
-
};
|
package/src/worker/xhr.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
-
import { decoder } from 'reflected-ffi/decoder';
|
|
3
|
-
import i32 from 'weak-id/i32';
|
|
4
|
-
|
|
5
|
-
import sender from './sender.js';
|
|
6
|
-
|
|
7
|
-
const { parse, stringify } = JSON;
|
|
8
|
-
|
|
9
|
-
const { promise, resolve } = withResolvers();
|
|
10
|
-
|
|
11
|
-
addEventListener(
|
|
12
|
-
'message',
|
|
13
|
-
({ data: [_, main, channel] }) => resolve([main, channel]),
|
|
14
|
-
{ once: true }
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
export const channel = 'xhr';
|
|
18
|
-
|
|
19
|
-
const handle = (channel, options) => {
|
|
20
|
-
const bc = new BroadcastChannel(channel);
|
|
21
|
-
const next = i32();
|
|
22
|
-
const decode = (options.decoder ?? decoder)({ byteOffset: 0 });
|
|
23
|
-
const { serviceWorker } = options;
|
|
24
|
-
return (payload, ...rest) => {
|
|
25
|
-
const id = next();
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
bc.postMessage([id, payload], ...rest);
|
|
28
|
-
const xhr = new XMLHttpRequest;
|
|
29
|
-
xhr.open('POST', serviceWorker, false);
|
|
30
|
-
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
31
|
-
xhr.send(stringify([id, channel]));
|
|
32
|
-
const { length, buffer } = new Uint8Array(parse(xhr.responseText));
|
|
33
|
-
return options.onsync(length ? decode(length, buffer) : void 0);
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export default options => promise.then(([main, channel]) => {
|
|
38
|
-
postMessage(1);
|
|
39
|
-
return handle(channel, sender({ ...main, ...options }));
|
|
40
|
-
});
|