reflected 0.0.0 → 0.0.1
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/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/async-Cn7CWifh.js +1 -0
- package/dist/async.js +1 -0
- package/dist/broadcast-BPNfR9nK.js +1 -0
- package/dist/broadcast-CwqVSk2p.js +1 -0
- package/dist/broadcast.js +1 -0
- package/dist/channel-BwDpH9fR.js +1 -0
- package/dist/i32-C78nBJH2.js +1 -0
- package/dist/index.js +1 -0
- package/dist/message-CgNarJIa.js +1 -0
- package/dist/message-YPvgpfHS.js +1 -0
- package/dist/message.js +1 -0
- package/dist/sender-23_Enxlo.js +1 -0
- package/dist/shared-D9sRqO2H.js +1 -0
- package/dist/shared-DdAq4SGF.js +1 -0
- package/dist/shared-RFmxa5x4.js +1 -0
- package/dist/shared-array-buffer-cwdMr2mc.js +1 -0
- package/dist/sw.js +1 -0
- package/dist/with-resolvers-CHEvl4oe.js +1 -0
- package/dist/xhr-C97Ssg1V.js +1 -0
- package/dist/xhr-CYct95wr.js +1 -0
- package/dist/xhr.js +1 -0
- package/package.json +86 -9
- package/rollup.js +59 -0
- package/src/async.js +8 -0
- package/src/broadcast.js +8 -0
- package/src/channel.js +1 -0
- package/src/index.js +30 -10
- package/src/main/async.js +29 -0
- package/src/main/broadcast.js +21 -0
- package/src/main/message.js +20 -0
- package/src/main/sab.js +12 -0
- package/src/main/sender.js +38 -0
- package/src/main/shared.js +74 -16
- package/src/main/xhr.js +104 -0
- package/src/message.js +8 -0
- package/src/service/listeners.js +37 -0
- package/src/service/worker.js +5 -0
- package/src/shared.js +10 -0
- package/src/worker/async.js +38 -0
- package/src/worker/{firefox.js → broadcast.js} +4 -1
- package/src/worker/{chrome.js → message.js} +4 -1
- package/src/worker/sender.js +16 -0
- package/src/worker/shared.js +26 -5
- package/src/worker/xhr.js +38 -0
- package/src/xhr.js +8 -0
- package/test/index.html +8 -9
- package/test/index.js +35 -0
- package/test/mini-coi.js +28 -0
- package/test/readme.html +66 -0
- package/test/readme.js +26 -0
- package/test/sw.js +1 -0
- package/test/worker.js +15 -3
- package/types/async.d.ts +3 -0
- package/types/broadcast.d.ts +21 -0
- package/types/channel.d.ts +2 -0
- package/types/index.d.ts +5 -0
- package/types/main/async.d.ts +7 -0
- package/types/main/broadcast.d.ts +20 -0
- package/types/main/message.d.ts +20 -0
- package/types/main/sab.d.ts +5 -0
- package/types/main/sender.d.ts +5 -0
- package/types/main/shared.d.ts +44 -0
- package/types/main/xhr.d.ts +2 -0
- package/types/message.d.ts +21 -0
- package/types/reflected/src/async.d.ts +3 -0
- package/types/reflected/src/broadcast.d.ts +3 -0
- package/types/reflected/src/channel.d.ts +2 -0
- package/types/reflected/src/index.d.ts +3 -0
- package/types/reflected/src/main/async.d.ts +7 -0
- package/types/reflected/src/main/broadcast.d.ts +2 -0
- package/types/reflected/src/main/message.d.ts +2 -0
- package/types/reflected/src/main/sab.d.ts +5 -0
- package/types/reflected/src/main/sender.d.ts +5 -0
- package/types/reflected/src/main/shared.d.ts +44 -0
- package/types/reflected/src/main/xhr.d.ts +2 -0
- package/types/reflected/src/message.d.ts +3 -0
- package/types/reflected/src/service/listeners.d.ts +3 -0
- package/types/reflected/src/service/worker.d.ts +1 -0
- package/types/reflected/src/shared.d.ts +1 -0
- package/types/reflected/src/worker/async.d.ts +3 -0
- package/types/reflected/src/worker/broadcast.d.ts +3 -0
- package/types/reflected/src/worker/message.d.ts +3 -0
- package/types/reflected/src/worker/sender.d.ts +2 -0
- package/types/reflected/src/worker/shared.d.ts +11 -0
- package/types/reflected/src/worker/xhr.d.ts +3 -0
- package/types/reflected/src/xhr.d.ts +3 -0
- package/types/service/listeners.d.ts +3 -0
- package/types/service/worker.d.ts +1 -0
- package/types/shared.d.ts +1 -0
- package/types/weak-id/i32.d.ts +2 -0
- package/types/worker/async.d.ts +3 -0
- package/types/worker/broadcast.d.ts +3 -0
- package/types/worker/message.d.ts +3 -0
- package/types/worker/sender.d.ts +2 -0
- package/types/worker/shared.d.ts +11 -0
- package/types/worker/xhr.d.ts +3 -0
- package/types/xhr.d.ts +3 -0
- package/src/main/chrome.js +0 -19
- package/src/main/fallback.js +0 -29
- package/src/main/firefox.js +0 -19
- package/src/main/shared-id.js +0 -1
- package/src/worker/fallback.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright © 2026-today, Andrea Giammarchi, @WebReflection
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the “Software”), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software
|
|
10
|
+
is furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included
|
|
13
|
+
in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
21
|
+
IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# reflected
|
|
2
|
+
|
|
3
|
+
A primitive to allow workers to call synchronously any functionality exposed on the main thread.
|
|
4
|
+
|
|
5
|
+
This module uses 3 synchronous strategies + 1 asynchronous fallback:
|
|
6
|
+
|
|
7
|
+
* **message** based on *SharedArrayBuffer* and *MessageChannel*, the fastest and most reliable "*channel strategy*" that requires headers to enable [Cross Origin Isolation](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated) on the page.
|
|
8
|
+
* **broadcast** also based on *SharedArrayBuffer* but with *BroadcastChannel* instead to satisfy a long standing [Firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1752287). This also requires headers to enable [Cross Origin Isolation](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated) on the page.
|
|
9
|
+
* **xhr** based on synchronous *XMLHttpRequest* and a dedicated *ServiceWorker* able to intercept such *POST* requests, broadcast to all listening channels the request and resolve as response for the worker.
|
|
10
|
+
* **async** which will always return a *Promise* and will not need special headers or *ServiceWorker*. This is also a fallback for the *xhr* case if the `serviceWorker` option field has not been provided.
|
|
11
|
+
|
|
12
|
+
All strategies are automatically detected through the default/main `import` but all dedicated strategies can be retrieved directly, example:
|
|
13
|
+
|
|
14
|
+
* `import reflect from 'reflected'` will decide automatically which strategy should be used.
|
|
15
|
+
* `import reflect from 'reflected/message'` will return the right *message* based module on the main thread and the worker mode within the worker.
|
|
16
|
+
* `import reflect from 'reflected/main/message'` will return the *message* strategy for the main thread only. This requires the least amount of bandwidth when you are sure that *message* strategy will work on main.
|
|
17
|
+
* `import reflect from 'reflected/worker/message'` will return the *message* strategy for the worker thread only. This requires the least amount of bandwidth when you are sure that *message* strategy will work within the worker.
|
|
18
|
+
|
|
19
|
+
Swap `message` with `broadcast`, `xhr` or `async`, and all exports will work equally well accordingly to the chosen "*channel strategy*".
|
|
20
|
+
|
|
21
|
+
### Worker Thread API
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// file: worker.js (always loaded as module)
|
|
25
|
+
import reflect from 'https://esm.run/reflected';
|
|
26
|
+
|
|
27
|
+
// ℹ️ must await the initialization
|
|
28
|
+
const reflected = await reflect({
|
|
29
|
+
// receives the returned data from the main thread.
|
|
30
|
+
// use this helper to transform such data into something
|
|
31
|
+
// that the worker can use/understand after invoke
|
|
32
|
+
// ⚠️ must be synchronous and it's invoked synchronously
|
|
33
|
+
ondata(response:Int32Array) {
|
|
34
|
+
return response.length ? response[0] : undefined;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// receives the data from the main thread when
|
|
38
|
+
// `worker.send(payload, ...rest)` is invoked.
|
|
39
|
+
// use this helper to transform the main thread request
|
|
40
|
+
// into something compatible with structuredClone algorithm
|
|
41
|
+
// ℹ️ works even if synchronous but it's resolved asynchronously
|
|
42
|
+
async onsend(payload) {
|
|
43
|
+
const data = await fetch('./data.json').then(r => r.json());
|
|
44
|
+
return process(payload, data);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// retrive the result of `test_sum(1, 2, 3)`
|
|
49
|
+
// directly from the main thread.
|
|
50
|
+
// only the async channel variant would need to await
|
|
51
|
+
const value = reflected({
|
|
52
|
+
invoke: 'test_sum',
|
|
53
|
+
args: [1, 2, 3]
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log(value); // 6
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Main Thread API
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
// file: index.js as module
|
|
63
|
+
import reflect from 'https://esm.run/reflected';
|
|
64
|
+
|
|
65
|
+
function test_sum(...args:number[]) {
|
|
66
|
+
let i = 0;
|
|
67
|
+
while (args.length)
|
|
68
|
+
i += args.pop();
|
|
69
|
+
return i;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ℹ️ must await the initialization
|
|
73
|
+
const worker = await reflect(
|
|
74
|
+
// Worker scriptURL
|
|
75
|
+
'./worker.js',
|
|
76
|
+
// Worker options + required utilities / helpers
|
|
77
|
+
// ℹ️ type is enforced to be 'module' due top-level await
|
|
78
|
+
{
|
|
79
|
+
// invoked when the worker asks to synchronize a call
|
|
80
|
+
// and it mmust return an Int32Array reference to populate
|
|
81
|
+
// the SharedArrayBuffer and notify/unlock the worker
|
|
82
|
+
// ℹ️ works even if synchronous but it's resolved asynchronously
|
|
83
|
+
// ⚠️ the worker is not responsive until this returns so
|
|
84
|
+
// be sure you handle errors gracefully to still provide
|
|
85
|
+
// a result the worker can consume out of the shared buffer!
|
|
86
|
+
async ondata(payload:unknown) {
|
|
87
|
+
const { invoke, args } = payload;
|
|
88
|
+
|
|
89
|
+
if (invoke === 'test_sum') {
|
|
90
|
+
// just demoing this can be async too
|
|
91
|
+
const value = await test_sum(...args);
|
|
92
|
+
return new Int32Array([value]);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// errors should still be Int32Array but
|
|
96
|
+
// it is trivial to return no result
|
|
97
|
+
return new Int32Array(0);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// *optional* helper to process data returned from the worker when
|
|
101
|
+
// the main thread `await worker.send(payload, ...rest)` operation
|
|
102
|
+
// is invoked. If not present, whatever payload the worker returned
|
|
103
|
+
// will be directly returned as invoke result, just like in here.
|
|
104
|
+
// ℹ️ works even if synchronous but it's resolved asynchronously
|
|
105
|
+
onsend(payload:unknown) {
|
|
106
|
+
return payload;
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// optional: the initial SharedArrayBuffer length
|
|
110
|
+
initByteLength: 1024,
|
|
111
|
+
|
|
112
|
+
// optional: the max possible SharedArrayBuffer growth
|
|
113
|
+
maxByteLength: 8192,
|
|
114
|
+
|
|
115
|
+
// optional: the service worker as fallback
|
|
116
|
+
// * if it's a string, it's used to register it
|
|
117
|
+
// * if it's an object, it's used to initialize it
|
|
118
|
+
// but it must contain a `url` field to register it
|
|
119
|
+
// ℹ️ if already registered it will not try to register it
|
|
120
|
+
serviceWorker: undefined,
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const value = await worker.send({ any: 'payload' });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Test [live](https://webreflection.github.io/reflected/test/readme.html) or read the [main thread](./test/readme.html) and [worker thread](./test/readme.js) code.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as e}from"./with-resolvers-CHEvl4oe.js";import{i as s}from"./i32-C78nBJH2.js";import{s as t}from"./sender-23_Enxlo.js";import"./channel-BwDpH9fR.js";const{promise:a,resolve:r}=e();addEventListener("message",({data:[e,s,t]})=>r([e,s,t]),{once:!0});const n="async";var o=r=>a.then(([a,n,o])=>(postMessage(1),((t,a,r)=>{const n=new BroadcastChannel(t),o=s(),d=new Map;return n.addEventListener("message",({data:[e,s]})=>{const[t,n]=d.get(e);a.set(s,0),t(r.ondata(a.subarray(2,2+a[1])))}),(s,...t)=>{const{promise:a,resolve:r}=e(),i=o();return d.set(i,[r,t]),n.postMessage([i,s],...t),a}})(o,new Int32Array(a),t({...n,...r}))));export{n as channel,o as default};
|
package/dist/async.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=Promise.withResolvers||function(){var e,t,s=new this((s,n)=>{e=s,t=n});return{resolve:e,reject:t,promise:s}};var t=e.bind(Promise),s=e=>{const t=new Int32Array(1);return()=>t[0]++},n="eac8422c-ea74-4190-9b8c-7966827497f0";const{isArray:r}=Array,a=e=>e;class o extends Worker{#e;#t;constructor(e,t){super(e,t),this.#e=s(),this.#t=new Map,t.onsend||(t.onsend=a),super.addEventListener("message",async e=>{const{data:s}=e;if(r(s)&&s[0]===n){e.stopImmediatePropagation(),e.preventDefault();const[n,r]=s[1],a=this.#t.get(n);this.#t.delete(n),a(await t.onsend(r))}})}send(e,...s){const r=this.#e(),{promise:a,resolve:o}=t();return this.#t.set(r,o),super.postMessage([n,[r,e]],...s),a}}let{SharedArrayBuffer:c}=globalThis;try{new c(4,{maxByteLength:8})}catch(e){c=class extends ArrayBuffer{get growable(){return super.resizable}grow(e){super.resize(e)}}}const i=2*Int32Array.BYTES_PER_ELEMENT,d=e=>{switch(typeof e){case"symbol":case"function":return!1}return!0};let u=!0;try{crypto.randomUUID()}catch(e){u=!1}const p=u?()=>crypto.randomUUID():()=>(Date.now()+Math.random()).toString(36),g="async";var y=(e=>(s,n)=>{const{promise:r,resolve:a}=t();return new e(s,n,a),r})(class extends o{constructor(e,t,s){const n=p(),r=new BroadcastChannel(n),a=(({initByteLength:e=1024,maxByteLength:t=8192})=>new c(i+e,{maxByteLength:i+t}))(t),o=new Int32Array(a),u=((e,t)=>{const s=new Int32Array(e);return async({data:n})=>{const r=await t.ondata(n),a=r.length,o=i+r.buffer.byteLength;e.byteLength<o&&e.grow(o),s.set(r,2),s[1]=a,s[0]=1}})(a,t);r.addEventListener("message",async({data:[e,t]})=>{await u({data:t}),r.postMessage([e,o.slice(0,2+o[1])])}),super(...((e,t,s)=>{const n=new URL(e,location.href);return n.searchParams.set("reflected",t),[n,{...s,type:"module"}]})(e,g,t)),super.addEventListener("message",()=>s(this),{once:!0}),super.postMessage(((e,t)=>{const s={};for(const e in t){const n=t[e];d(e)&&d(n)&&(s[e]=n)}return[e,s]})(a,t).concat(n))}get channel(){return g}});const{isArray:l}=Array;const{promise:h,resolve:m}=t();addEventListener("message",({data:[e,t,s]})=>m([e,t,s]),{once:!0});const w="async";var f="importScripts"in globalThis?e=>h.then(([r,a,o])=>(postMessage(1),((e,n,r)=>{const a=new BroadcastChannel(e),o=s(),c=new Map;return a.addEventListener("message",({data:[e,t]})=>{const[s,a]=c.get(e);n.set(t,0),s(r.ondata(n.subarray(2,2+n[1])))}),(e,...s)=>{const{promise:n,resolve:r}=t(),i=o();return c.set(i,[r,s]),a.postMessage([i,e],...s),n}})(o,new Int32Array(r),(e=>(addEventListener("message",async t=>{const{data:s}=t;if(l(s)&&s[0]===n){t.stopImmediatePropagation(),t.preventDefault();const[r,a]=s[1];postMessage([n,[r,await e.onsend(a)]])}}),e))({...a,...e})))):y;export{w as channel,f as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as s,S as e,a,h as r,u as t,p as n}from"./shared-D9sRqO2H.js";import{r as o}from"./shared-RFmxa5x4.js";import"./with-resolvers-CHEvl4oe.js";import"./i32-C78nBJH2.js";import"./channel-BwDpH9fR.js";const c="broadcast";var d=s(class extends e{constructor(s,e,d){const p=o(),i=new BroadcastChannel(p),m=a(e);i.addEventListener("message",r(m,e,!0)),super(...t(s,c,e)),super.addEventListener("message",()=>d(this),{once:!0}),super.postMessage(n(m,e).concat(p))}get channel(){return c}});export{d as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as r}from"./with-resolvers-CHEvl4oe.js";import{h as s}from"./shared-DdAq4SGF.js";import"./sender-23_Enxlo.js";import"./channel-BwDpH9fR.js";const{promise:a,resolve:e}=r(),o="broadcast";var t=s(a,({data:[r,s,a]})=>e([r,s,new BroadcastChannel(a)]));export{o as channel,t as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=Promise.withResolvers||function(){var e,t,s=new this((s,n)=>{e=s,t=n});return{resolve:e,reject:t,promise:s}};var t=e.bind(Promise),s="eac8422c-ea74-4190-9b8c-7966827497f0";const{isArray:n}=Array,r=e=>e;class a extends Worker{#e;#t;constructor(e,t){super(e,t),this.#e=(()=>{const e=new Int32Array(1);return()=>e[0]++})(),this.#t=new Map,t.onsend||(t.onsend=r),super.addEventListener("message",async e=>{const{data:r}=e;if(n(r)&&r[0]===s){e.stopImmediatePropagation(),e.preventDefault();const[s,n]=r[1],a=this.#t.get(s);this.#t.delete(s),a(await t.onsend(n))}})}send(e,...n){const r=this.#e(),{promise:a,resolve:o}=t();return this.#t.set(r,o),super.postMessage([s,[r,e]],...n),a}}const{notify:o,store:c}=Atomics,i=2*Int32Array.BYTES_PER_ELEMENT,d=e=>{switch(typeof e){case"symbol":case"function":return!1}return!0};let u=!0;try{crypto.randomUUID()}catch(e){u=!1}const p=u?()=>crypto.randomUUID():()=>(Date.now()+Math.random()).toString(36),h="broadcast";var m=(e=>(s,n)=>{const{promise:r,resolve:a}=t();return new e(s,n,a),r})(class extends a{constructor(e,t,s){const n=p(),r=new BroadcastChannel(n),a=(({initByteLength:e=1024,maxByteLength:t=8192})=>new SharedArrayBuffer(i+e,{maxByteLength:i+t}))(t);r.addEventListener("message",((e,t)=>{const s=new Int32Array(e);return async({data:n})=>{const r=await t.ondata(n),a=r.length,d=i+r.buffer.byteLength;e.byteLength<d&&e.grow(d),s.set(r,2),c(s,1,a),c(s,0,1),o(s,0)}})(a,t)),super(...((e,t,s)=>{const n=new URL(e,location.href);return n.searchParams.set("reflected",t),[n,{...s,type:"module"}]})(e,h,t)),super.addEventListener("message",()=>s(this),{once:!0}),super.postMessage(((e,t)=>{const s={};for(const e in t){const n=t[e];d(e)&&d(n)&&(s[e]=n)}return[e,s]})(a,t).concat(n))}get channel(){return h}});const{isArray:y}=Array;const{load:g,store:l,wait:w}=Atomics,{promise:f,resolve:v}=t(),L="broadcast";var A=((e,t)=>(addEventListener("message",t,{once:!0}),t=>e.then(([e,n,r])=>(postMessage(1),((e,t,s)=>(n,...r)=>(e.postMessage(n,...r),w(t,0,0),l(t,0,0),s.ondata(t.subarray(2,2+g(t,1)))))(r,new Int32Array(e),(e=>(addEventListener("message",async t=>{const{data:n}=t;if(y(n)&&n[0]===s){t.stopImmediatePropagation(),t.preventDefault();const[r,a]=n[1];postMessage([s,[r,await e.onsend(a)]])}}),e))({...n,...t}))))))(f,({data:[e,t,s]})=>v([e,t,new BroadcastChannel(s)])),b="importScripts"in globalThis?A:m;export{L as channel,b as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var a="eac8422c-ea74-4190-9b8c-7966827497f0";export{a as S};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var r=r=>{const n=new Int32Array(1);return()=>n[0]++};export{r as i};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as a}from"./with-resolvers-CHEvl4oe.js";import{n as s}from"./shared-array-buffer-cwdMr2mc.js";let e,t;if("importScripts"in globalThis){let s;const{promise:r,resolve:o}=a(),i=new URL(location).searchParams.get("reflected");e=i,s="message"===i?import("./message-CgNarJIa.js"):"broadcast"===i?import("./broadcast-CwqVSk2p.js"):"xhr"===i?import("./xhr-CYct95wr.js"):import("./async-Cn7CWifh.js"),t=async a=>{const{data:e,ports:t}=await r,{default:o}=await s,i=new Event("message");return i.data=e,i.ports=t,dispatchEvent(i),o(a)},addEventListener("message",o,{once:!0})}else s?"InstallTrigger"in globalThis?(e="broadcast",t=(await import("./broadcast-BPNfR9nK.js")).default):(e="message",t=(await import("./message-YPvgpfHS.js")).default):navigator.serviceWorker?(e="xhr",t=(await import("./xhr-C97Ssg1V.js")).default):(e="fallback",t=()=>{});var r=t;export{e as channel,r as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as s}from"./with-resolvers-CHEvl4oe.js";import{h as r}from"./shared-DdAq4SGF.js";import"./sender-23_Enxlo.js";import"./channel-BwDpH9fR.js";const{promise:e,resolve:o}=s(),a="message";var t=r(e,({data:[s,r],ports:[e]})=>o([s,r,e]));export{a as channel,t as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as s,S as e,a as t,h as r,u as a,p as n}from"./shared-D9sRqO2H.js";import"./with-resolvers-CHEvl4oe.js";import"./i32-C78nBJH2.js";import"./channel-BwDpH9fR.js";const o="message";var p=s(class extends e{constructor(s,e,p){const{port1:c,port2:i}=new MessageChannel,d=t(e);c.addEventListener(o,r(d,e,!0)),c.start(),super(...a(s,o,e)),super.addEventListener(o,()=>p(this),{once:!0}),super.postMessage(n(d,e),[i])}get channel(){return o}});export{p as default};
|
package/dist/message.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=Promise.withResolvers||function(){var e,t,s=new this((s,n)=>{e=s,t=n});return{resolve:e,reject:t,promise:s}};var t=e.bind(Promise),s="eac8422c-ea74-4190-9b8c-7966827497f0";const{isArray:n}=Array,r=e=>e;class a extends Worker{#e;#t;constructor(e,t){super(e,t),this.#e=(()=>{const e=new Int32Array(1);return()=>e[0]++})(),this.#t=new Map,t.onsend||(t.onsend=r),super.addEventListener("message",async e=>{const{data:r}=e;if(n(r)&&r[0]===s){e.stopImmediatePropagation(),e.preventDefault();const[s,n]=r[1],a=this.#t.get(s);this.#t.delete(s),a(await t.onsend(n))}})}send(e,...n){const r=this.#e(),{promise:a,resolve:o}=t();return this.#t.set(r,o),super.postMessage([s,[r,e]],...n),a}}const{notify:o,store:i}=Atomics,c=2*Int32Array.BYTES_PER_ELEMENT,d=e=>{switch(typeof e){case"symbol":case"function":return!1}return!0},u="message";var p=(e=>(s,n)=>{const{promise:r,resolve:a}=t();return new e(s,n,a),r})(class extends a{constructor(e,t,s){const{port1:n,port2:r}=new MessageChannel,a=(({initByteLength:e=1024,maxByteLength:t=8192})=>new SharedArrayBuffer(c+e,{maxByteLength:c+t}))(t);n.addEventListener(u,((e,t)=>{const s=new Int32Array(e);return async({data:n})=>{const r=await t.ondata(n),a=r.length,d=c+r.buffer.byteLength;e.byteLength<d&&e.grow(d),s.set(r,2),i(s,1,a),i(s,0,1),o(s,0)}})(a,t)),n.start(),super(...((e,t,s)=>{const n=new URL(e,location.href);return n.searchParams.set("reflected",t),[n,{...s,type:"module"}]})(e,u,t)),super.addEventListener(u,()=>s(this),{once:!0}),super.postMessage(((e,t)=>{const s={};for(const e in t){const n=t[e];d(e)&&d(n)&&(s[e]=n)}return[e,s]})(a,t),[r])}get channel(){return u}});const{isArray:g}=Array;const{load:h,store:m,wait:y}=Atomics,{promise:l,resolve:f}=t(),v="message";var w=((e,t)=>(addEventListener("message",t,{once:!0}),t=>e.then(([e,n,r])=>(postMessage(1),((e,t,s)=>(n,...r)=>(e.postMessage(n,...r),y(t,0,0),m(t,0,0),s.ondata(t.subarray(2,2+h(t,1)))))(r,new Int32Array(e),(e=>(addEventListener("message",async t=>{const{data:n}=t;if(g(n)&&n[0]===s){t.stopImmediatePropagation(),t.preventDefault();const[r,a]=n[1];postMessage([s,[r,await e.onsend(a)]])}}),e))({...n,...t}))))))(l,({data:[e,t],ports:[s]})=>f([e,t,s])),L="importScripts"in globalThis?w:p;export{v as channel,L as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{S as a}from"./channel-BwDpH9fR.js";const{isArray:s}=Array;var e=e=>(addEventListener("message",async t=>{const{data:n}=t;if(s(n)&&n[0]===a){t.stopImmediatePropagation(),t.preventDefault();const[s,o]=n[1];postMessage([a,[s,await e.onsend(o)]])}}),e);export{e as s};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as e}from"./with-resolvers-CHEvl4oe.js";import{i as t}from"./i32-C78nBJH2.js";import{S as s}from"./channel-BwDpH9fR.js";const{isArray:r}=Array,n=e=>e;class a extends Worker{#e;#t;constructor(e,a){super(e,a),this.#e=t(),this.#t=new Map,a.onsend||(a.onsend=n),super.addEventListener("message",async e=>{const{data:t}=e;if(r(t)&&t[0]===s){e.stopImmediatePropagation(),e.preventDefault();const[s,r]=t[1],n=this.#t.get(s);this.#t.delete(s),n(await a.onsend(r))}})}send(t,...r){const n=this.#e(),{promise:a,resolve:o}=e();return this.#t.set(n,o),super.postMessage([s,[n,t]],...r),a}}const{notify:o,store:i}=Atomics,c=2*Int32Array.BYTES_PER_ELEMENT,u=({initByteLength:e=1024,maxByteLength:t=8192})=>new SharedArrayBuffer(c+e,{maxByteLength:c+t}),h=t=>(s,r)=>{const{promise:n,resolve:a}=e();return new t(s,r,a),n},m=(e,t,s)=>{const r=new Int32Array(e);return async({data:n})=>{const a=await t.ondata(n),u=a.length,h=c+a.buffer.byteLength;e.byteLength<h&&e.grow(h),r.set(a,2),s?(i(r,1,u),i(r,0,1),o(r,0)):(r[1]=u,r[0]=1)}},p=e=>{switch(typeof e){case"symbol":case"function":return!1}return!0},d=(e,t)=>{const s={};for(const e in t){const r=t[e];p(e)&&p(r)&&(s[e]=r)}return[e,s]},y=(e,t,s)=>{const r=new URL(e,location.href);return r.searchParams.set("reflected",t),[r,{...s,type:"module"}]};export{a as S,u as a,h as b,m as h,c as m,d as p,y as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{s}from"./sender-23_Enxlo.js";const{load:e,store:a,wait:t}=Atomics,o=(o,r)=>(addEventListener("message",r,{once:!0}),r=>o.then(([o,n,d])=>(postMessage(1),((s,o,r)=>(n,...d)=>(s.postMessage(n,...d),t(o,0,0),a(o,0,0),r.ondata(o.subarray(2,2+e(o,1)))))(d,new Int32Array(o),s({...n,...r})))));export{o as h};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let t=!0;try{crypto.randomUUID()}catch(o){t=!1}const o=t?()=>crypto.randomUUID():()=>(Date.now()+Math.random()).toString(36);export{o as r};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let{SharedArrayBuffer:e}=globalThis,r=!0;try{new e(4,{maxByteLength:8})}catch(a){r=!1,e=class extends ArrayBuffer{get growable(){return super.resizable}grow(e){super.resize(e)}}}export{e as S,r as n};
|
package/dist/sw.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=Promise.withResolvers||function(){var e,t,n=new this((n,s)=>{e=n,t=s});return{resolve:e,reject:t,promise:n}};var t=e.bind(Promise);const[n,s]=((e=e=>e)=>{const n=new Map,s=(()=>{const e=new Int32Array(1);return()=>e[0]++})();return[()=>{let r;do{r=e(s())}while(n.has(r));const a=t();return n.set(r,a),[r,a.promise]},(e,t,s)=>{const r=n.get(e);n.delete(e),s?r?.reject(s):r?.resolve(t)}]})(),{protocol:r,host:a,pathname:o}=location,i=`${r}//${a}${o}`,c=new BroadcastChannel("eac8422c-ea74-4190-9b8c-7966827497f0");c.addEventListener("message",({data:[e,t]})=>{if("response"===e){const[e,n]=t;s(e,`[${n.join(",")}]`)}});const d=async e=>{const[t,s]=n();return c.postMessage(["request",[t,e]]),new Response(await s)};addEventListener("activate",e=>e.waitUntil(clients.claim())),addEventListener("fetch",async e=>{const{request:t}=e;"POST"===t.method&&t.url.startsWith(i)&&(e.stopImmediatePropagation(),e.respondWith(t.json().then(d)),e.preventDefault())}),addEventListener("install",()=>skipWaiting());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=(Promise.withResolvers||function(){var e,r,s=new this((s,i)=>{e=s,r=i});return{resolve:e,reject:r,promise:s}}).bind(Promise);export{e as w};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as e}from"./with-resolvers-CHEvl4oe.js";import{m as t,S as s,u as n,p as a,h as r}from"./shared-D9sRqO2H.js";import{S as o}from"./shared-array-buffer-cwdMr2mc.js";import{r as i}from"./shared-RFmxa5x4.js";import{S as c}from"./channel-BwDpH9fR.js";import"./i32-C78nBJH2.js";var l=({initByteLength:e=1024,maxByteLength:s=8192})=>new o(t+e,{maxByteLength:t+s});const d="async";let h=class extends s{constructor(e,t,s){const o=i(),c=new BroadcastChannel(o),h=l(t),p=new Int32Array(h),g=r(h,t,!1);c.addEventListener("message",async({data:[e,t]})=>{await g({data:t}),c.postMessage([e,p.slice(0,2+p[1])])}),super(...n(e,d,t)),super.addEventListener("message",()=>s(this),{once:!0}),super.postMessage(a(h,t).concat(o))}get channel(){return d}};const p=new Map,g=new BroadcastChannel(c);g.addEventListener("message",async({data:[e,t]})=>{if("request"===e){const[e,[s,n]]=t,a=p.get(n);if(a){const t=a.get(s);t&&(a.delete(s),g.postMessage(["response",[e,await t]]))}}});const{promise:u,resolve:m}=e();let f=!0;const v=(e,t)=>{let s,n=!0,{url:a}=t;e.getRegistration(a).then(s=>s??e.register(a,t)).then(function r(o){const{controller:i}=e;if(n=n&&!!i,s=o.installing||o.waiting||o.active,!s)return v(e,t);if("activated"===s.state){if(n){if(i.scriptURL===a)return m();o.unregister()}location.reload()}else s.addEventListener("statechange",()=>r(o),{once:!0})})};class w extends s{#e;constructor(t,s,o){if(f){f=!1;let{serviceWorker:e}=s;if(!e)return new h(t,s,o);"string"==typeof e&&(e={url:e}),e.url=new URL(e.url,location.href).href,v(navigator.serviceWorker,e)}const c=i(),d=new BroadcastChannel(c),g=l(s),u=new Map,m=new Int32Array(g),w=r(g,s,!1);p.set(c,u),d.addEventListener("message",async({data:[t,s]})=>{const{promise:n,resolve:a}=e();u.set(t,n),await w({data:s}),a(m.slice(0,2+m[1]))}),super(...n(t,"xhr",s)),super.addEventListener("message",()=>o(this),{once:!0}),super.postMessage(a(g,s).concat(c)),this.#e=c}terminate(){p.delete(this.#e),super.terminate()}get channel(){return"xhr"}}var y=(t,s)=>{const{promise:n,resolve:a}=e();return new w(t,s,a)instanceof h?n:u.then(()=>n)};export{y as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as e}from"./with-resolvers-CHEvl4oe.js";import{i as s}from"./i32-C78nBJH2.js";import{s as t}from"./sender-23_Enxlo.js";import"./channel-BwDpH9fR.js";const{parse:r,stringify:n}=JSON,{promise:o,resolve:a}=e();addEventListener("message",({data:[e,s,t]})=>a([e,s,t]),{once:!0});const p="xhr";var i=e=>o.then(([o,a,p])=>(postMessage(1),((e,t,o)=>{const a=new BroadcastChannel(e),p=s(),{serviceWorker:i}=o;return(s,...c)=>{const d=p();a.postMessage([d,s],...c);const m=new XMLHttpRequest;return m.open("POST",i,!1),m.setRequestHeader("Content-Type","application/json"),m.send(n([d,e])),t.set(r(m.responseText),0),o.ondata(t.subarray(2,2+t[1]))}})(p,new Int32Array(o),t({...a,...e}))));export{p as channel,i as default};
|
package/dist/xhr.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=Promise.withResolvers||function(){var e,t,s=new this((s,n)=>{e=s,t=n});return{resolve:e,reject:t,promise:s}};var t=e.bind(Promise),s=e=>{const t=new Int32Array(1);return()=>t[0]++},n="eac8422c-ea74-4190-9b8c-7966827497f0";const{isArray:r}=Array,a=e=>e;class o extends Worker{#e;#t;constructor(e,t){super(e,t),this.#e=s(),this.#t=new Map,t.onsend||(t.onsend=a),super.addEventListener("message",async e=>{const{data:s}=e;if(r(s)&&s[0]===n){e.stopImmediatePropagation(),e.preventDefault();const[n,r]=s[1],a=this.#t.get(n);this.#t.delete(n),a(await t.onsend(r))}})}send(e,...s){const r=this.#e(),{promise:a,resolve:o}=t();return this.#t.set(r,o),super.postMessage([n,[r,e]],...s),a}}let{SharedArrayBuffer:c}=globalThis;try{new c(4,{maxByteLength:8})}catch(e){c=class extends ArrayBuffer{get growable(){return super.resizable}grow(e){super.resize(e)}}}const i=2*Int32Array.BYTES_PER_ELEMENT,d=(e,t,s)=>{const n=new Int32Array(e);return async({data:s})=>{const r=await t.ondata(s),a=r.length,o=i+r.buffer.byteLength;e.byteLength<o&&e.grow(o),n.set(r,2),n[1]=a,n[0]=1}},l=e=>{switch(typeof e){case"symbol":case"function":return!1}return!0},u=(e,t)=>{const s={};for(const e in t){const n=t[e];l(e)&&l(n)&&(s[e]=n)}return[e,s]},p=(e,t,s)=>{const n=new URL(e,location.href);return n.searchParams.set("reflected",t),[n,{...s,type:"module"}]};var g=({initByteLength:e=1024,maxByteLength:t=8192})=>new c(i+e,{maxByteLength:i+t});let h=!0;try{crypto.randomUUID()}catch(e){h=!1}const y=h?()=>crypto.randomUUID():()=>(Date.now()+Math.random()).toString(36),w="async";let f=class extends o{constructor(e,t,s){const n=y(),r=new BroadcastChannel(n),a=g(t),o=new Int32Array(a),c=d(a,t);r.addEventListener("message",async({data:[e,t]})=>{await c({data:t}),r.postMessage([e,o.slice(0,2+o[1])])}),super(...p(e,w,t)),super.addEventListener("message",()=>s(this),{once:!0}),super.postMessage(u(a,t).concat(n))}get channel(){return w}};const m=new Map,v=new BroadcastChannel(n);v.addEventListener("message",async({data:[e,t]})=>{if("request"===e){const[e,[s,n]]=t,r=m.get(n);if(r){const t=r.get(s);t&&(r.delete(s),v.postMessage(["response",[e,await t]]))}}});const{promise:L,resolve:x}=t();let E=!0;const M=(e,t)=>{let s,n=!0,{url:r}=t;e.getRegistration(r).then(s=>s??e.register(r,t)).then(function a(o){const{controller:c}=e;if(n=n&&!!c,s=o.installing||o.waiting||o.active,!s)return M(e,t);if("activated"===s.state){if(n){if(c.scriptURL===r)return x();o.unregister()}location.reload()}else s.addEventListener("statechange",()=>a(o),{once:!0})})};let A=class extends o{#s;constructor(e,s,n){if(E){E=!1;let{serviceWorker:t}=s;if(!t)return new f(e,s,n);"string"==typeof t&&(t={url:t}),t.url=new URL(t.url,location.href).href,M(navigator.serviceWorker,t)}const r=y(),a=new BroadcastChannel(r),o=g(s),c=new Map,i=new Int32Array(o),l=d(o,s);m.set(r,c),a.addEventListener("message",async({data:[e,s]})=>{const{promise:n,resolve:r}=t();c.set(e,n),await l({data:s}),r(i.slice(0,2+i[1]))}),super(...p(e,"xhr",s)),super.addEventListener("message",()=>n(this),{once:!0}),super.postMessage(u(o,s).concat(r)),this.#s=r}terminate(){m.delete(this.#s),super.terminate()}get channel(){return"xhr"}};const{isArray:b}=Array;const{parse:B,stringify:I}=JSON,{promise:q,resolve:R}=t();addEventListener("message",({data:[e,t,s]})=>R([e,t,s]),{once:!0});const P="xhr";var T="importScripts"in globalThis?e=>q.then(([t,r,a])=>(postMessage(1),((e,t,n)=>{const r=new BroadcastChannel(e),a=s(),{serviceWorker:o}=n;return(s,...c)=>{const i=a();r.postMessage([i,s],...c);const d=new XMLHttpRequest;return d.open("POST",o,!1),d.setRequestHeader("Content-Type","application/json"),d.send(I([i,e])),t.set(B(d.responseText),0),n.ondata(t.subarray(2,2+t[1]))}})(a,new Int32Array(t),(e=>(addEventListener("message",async t=>{const{data:s}=t;if(b(s)&&s[0]===n){t.stopImmediatePropagation(),t.preventDefault();const[r,a]=s[1];postMessage([n,[r,await e.onsend(a)]])}}),e))({...r,...e})))):(e,s)=>{const{promise:n,resolve:r}=t();return new A(e,s,r)instanceof f?n:L.then(()=>n)};export{P as channel,T as default};
|
package/package.json
CHANGED
|
@@ -1,16 +1,93 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reflected",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A primitive to allow workers to call synchronously any functionality exposed on the main thread.",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./src/index.js",
|
|
8
|
+
"types": "./types/index.d.ts"
|
|
9
|
+
},
|
|
10
|
+
"./async": {
|
|
11
|
+
"import": "./src/async.js",
|
|
12
|
+
"types": "./types/async.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./broadcast": {
|
|
15
|
+
"import": "./src/broadcast.js",
|
|
16
|
+
"types": "./types/broadcast.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./message": {
|
|
19
|
+
"import": "./src/message.js",
|
|
20
|
+
"types": "./types/message.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./xhr": {
|
|
23
|
+
"import": "./src/xhr.js",
|
|
24
|
+
"types": "./types/xhr.d.ts"
|
|
25
|
+
},
|
|
26
|
+
"./main/async": {
|
|
27
|
+
"import": "./src/main/async.js",
|
|
28
|
+
"types": "./types/main/async.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"./main/broadcast": {
|
|
31
|
+
"import": "./src/main/broadcast.js",
|
|
32
|
+
"types": "./types/main/broadcast.d.ts"
|
|
33
|
+
},
|
|
34
|
+
"./main/message": {
|
|
35
|
+
"import": "./src/main/message.js",
|
|
36
|
+
"types": "./types/main/message.d.ts"
|
|
37
|
+
},
|
|
38
|
+
"./main/xhr": {
|
|
39
|
+
"import": "./src/main/xhr.js",
|
|
40
|
+
"types": "./types/main/xhr.d.ts"
|
|
41
|
+
},
|
|
42
|
+
"./worker/async": {
|
|
43
|
+
"import": "./src/worker/async.js",
|
|
44
|
+
"types": "./types/worker/async.d.ts"
|
|
45
|
+
},
|
|
46
|
+
"./worker/broadcast": {
|
|
47
|
+
"import": "./src/worker/broadcast.js",
|
|
48
|
+
"types": "./types/worker/broadcast.d.ts"
|
|
49
|
+
},
|
|
50
|
+
"./worker/message": {
|
|
51
|
+
"import": "./src/worker/message.js",
|
|
52
|
+
"types": "./types/worker/message.d.ts"
|
|
53
|
+
},
|
|
54
|
+
"./worker/xhr": {
|
|
55
|
+
"import": "./src/worker/xhr.js",
|
|
56
|
+
"types": "./types/worker/xhr.d.ts"
|
|
57
|
+
},
|
|
58
|
+
"./package.json": "./package.json"
|
|
59
|
+
},
|
|
6
60
|
"scripts": {
|
|
7
|
-
"
|
|
61
|
+
"build": "rm -rf dist && rollup -c rollup.js && cp dist/sw.js test/sw.js && npm run types",
|
|
62
|
+
"types": "tsc --allowJs --checkJs --lib dom,esnext --module nodeNext --target esnext -d --emitDeclarationOnly --outDir ./types ./src/*.js ./src/*/*.js"
|
|
8
63
|
},
|
|
9
64
|
"keywords": [],
|
|
10
|
-
"author": "",
|
|
11
|
-
"license": "
|
|
12
|
-
"type": "
|
|
65
|
+
"author": "Andrea Giammarchi",
|
|
66
|
+
"license": "MIT",
|
|
67
|
+
"type": "module",
|
|
68
|
+
"types": "./types/index.d.ts",
|
|
69
|
+
"main": "./dist/index.js",
|
|
70
|
+
"module": "./src/index.js",
|
|
13
71
|
"dependencies": {
|
|
14
|
-
"@webreflection/utils": "^0.1.2"
|
|
15
|
-
|
|
72
|
+
"@webreflection/utils": "^0.1.2",
|
|
73
|
+
"next-resolver": "^0.1.6",
|
|
74
|
+
"typescript": "^5.9.3",
|
|
75
|
+
"weak-id": "^0.2.1"
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
79
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
80
|
+
"rollup": "^4.57.1"
|
|
81
|
+
},
|
|
82
|
+
"directories": {
|
|
83
|
+
"test": "test"
|
|
84
|
+
},
|
|
85
|
+
"repository": {
|
|
86
|
+
"type": "git",
|
|
87
|
+
"url": "git+https://github.com/WebReflection/reflected.git"
|
|
88
|
+
},
|
|
89
|
+
"bugs": {
|
|
90
|
+
"url": "https://github.com/WebReflection/reflected/issues"
|
|
91
|
+
},
|
|
92
|
+
"homepage": "https://github.com/WebReflection/reflected#readme"
|
|
16
93
|
}
|
package/rollup.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
2
|
+
import terser from '@rollup/plugin-terser';
|
|
3
|
+
|
|
4
|
+
import { writeFileSync } from 'fs';
|
|
5
|
+
|
|
6
|
+
writeFileSync(`./src/channel.js`, `export default '${crypto.randomUUID()}';`);
|
|
7
|
+
|
|
8
|
+
const plugins = [nodeResolve()].concat(process.env.NO_MIN ? [] : [terser()]);
|
|
9
|
+
|
|
10
|
+
export default [
|
|
11
|
+
{
|
|
12
|
+
plugins,
|
|
13
|
+
input: './src/index.js',
|
|
14
|
+
output: {
|
|
15
|
+
esModule: true,
|
|
16
|
+
dir: './dist'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
plugins,
|
|
21
|
+
input: './src/broadcast.js',
|
|
22
|
+
output: {
|
|
23
|
+
esModule: true,
|
|
24
|
+
dir: './dist'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
plugins,
|
|
29
|
+
input: './src/message.js',
|
|
30
|
+
output: {
|
|
31
|
+
esModule: true,
|
|
32
|
+
dir: './dist'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
plugins,
|
|
37
|
+
input: './src/xhr.js',
|
|
38
|
+
output: {
|
|
39
|
+
esModule: true,
|
|
40
|
+
dir: './dist'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
plugins,
|
|
45
|
+
input: './src/async.js',
|
|
46
|
+
output: {
|
|
47
|
+
esModule: true,
|
|
48
|
+
dir: './dist'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
plugins,
|
|
53
|
+
input: './src/service/worker.js',
|
|
54
|
+
output: {
|
|
55
|
+
esModule: true,
|
|
56
|
+
file: './dist/sw.js'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
];
|
package/src/async.js
ADDED
package/src/broadcast.js
ADDED
package/src/channel.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'eac8422c-ea74-4190-9b8c-7966827497f0';
|
package/src/index.js
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import withResolvers from '@webreflection/utils/with-resolvers';
|
|
2
|
+
import { native } from '@webreflection/utils/shared-array-buffer';
|
|
3
3
|
|
|
4
|
+
/** @type {string} */
|
|
5
|
+
let channel;
|
|
6
|
+
|
|
7
|
+
/** @type {Function} */
|
|
4
8
|
let module;
|
|
5
9
|
|
|
6
10
|
if ('importScripts' in globalThis) {
|
|
7
11
|
let get;
|
|
8
12
|
const { promise, resolve } = withResolvers();
|
|
13
|
+
// @ts-ignore
|
|
9
14
|
const reflected = new URL(location).searchParams.get('reflected');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
else if (reflected === '
|
|
15
|
+
channel = reflected;
|
|
16
|
+
if (reflected === 'message') get = import(/* webpackIgnore: true */'./worker/message.js');
|
|
17
|
+
else if (reflected === 'broadcast') get = import(/* webpackIgnore: true */'./worker/broadcast.js');
|
|
18
|
+
else if (reflected === 'xhr') get = import(/* webpackIgnore: true */'./worker/xhr.js');
|
|
19
|
+
else get = import(/* webpackIgnore: true */'./worker/async.js');
|
|
13
20
|
module = async options => {
|
|
14
21
|
const { data, ports } = await promise;
|
|
15
22
|
const { default: reflect } = await get;
|
|
16
23
|
const event = new Event('message');
|
|
24
|
+
// @ts-ignore
|
|
17
25
|
event.data = data;
|
|
26
|
+
// @ts-ignore
|
|
18
27
|
event.ports = ports;
|
|
19
28
|
dispatchEvent(event);
|
|
20
29
|
return reflect(options);
|
|
@@ -22,13 +31,24 @@ if ('importScripts' in globalThis) {
|
|
|
22
31
|
addEventListener('message', resolve, { once: true });
|
|
23
32
|
}
|
|
24
33
|
else if (native) {
|
|
25
|
-
if ('InstallTrigger' in globalThis)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
if ('InstallTrigger' in globalThis) {
|
|
35
|
+
channel = 'broadcast';
|
|
36
|
+
module = (await import(/* webpackIgnore: true */'./main/broadcast.js')).default;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
channel = 'message';
|
|
40
|
+
module = (await import(/* webpackIgnore: true */'./main/message.js')).default;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (navigator.serviceWorker) {
|
|
44
|
+
channel = 'xhr';
|
|
45
|
+
module = (await import(/* webpackIgnore: true */'./main/xhr.js')).default;
|
|
29
46
|
}
|
|
30
47
|
else {
|
|
31
|
-
|
|
48
|
+
channel = 'fallback';
|
|
49
|
+
module = () => {};
|
|
32
50
|
}
|
|
33
51
|
|
|
52
|
+
export { channel };
|
|
53
|
+
|
|
34
54
|
export default module;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Sender from './sender.js';
|
|
2
|
+
import SAB from './sab.js';
|
|
3
|
+
import { bootstrap, handler, post, url } from './shared.js';
|
|
4
|
+
import { 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, data] }) => {
|
|
16
|
+
await handle({ data });
|
|
17
|
+
bc.postMessage([id, i32a.slice(0, 2 + 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);
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SharedArrayBuffer } from '@webreflection/utils/shared-array-buffer';
|
|
2
|
+
|
|
3
|
+
import { minByteLength } from './shared.js';
|
|
4
|
+
|
|
5
|
+
export default ({
|
|
6
|
+
initByteLength = 1024,
|
|
7
|
+
maxByteLength = (1024 * 8)
|
|
8
|
+
}) =>
|
|
9
|
+
new SharedArrayBuffer(
|
|
10
|
+
minByteLength + initByteLength,
|
|
11
|
+
{ maxByteLength: minByteLength + maxByteLength }
|
|
12
|
+
);
|
|
@@ -0,0 +1,38 @@
|
|
|
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[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
|
+
}
|