reflected 0.1.1 → 0.1.3

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 CHANGED
@@ -135,6 +135,33 @@ const value = await worker.send({ any: 'payload' });
135
135
 
136
136
  Test [live](https://webreflection.github.io/reflected/test/README/) or read the [main thread](./test/README/index.js) and [worker thread](./test/README/worker.js) code.
137
137
 
138
+ Latest [ffi](https://webreflection.github.io/reflected/test/ffi/) should allow workers to drive the main thread without even needing SharedArrayBuffer but of course, if *SharedArrayBuffer* is available, these will be much faster.
139
+
140
+ ### reflected/ffi
141
+
142
+ This module also exports a bare-minimum way to directly drive, whenever the *channel* is **not async**, the main thread from a worker.
143
+
144
+ ```js
145
+ // main.js module
146
+ import reflect from 'reflected/ffi/main';
147
+
148
+ // returns a worker with a special `ffi` field/namespace
149
+ // directly from reflected-ffi project
150
+ const worker = await reflect('./worker.js', { serviceWorker: './sw.js' });
151
+
152
+
153
+ // worker.js module
154
+ import reflect from 'reflected/ffi/worker';
155
+
156
+ // retrieve the reflected-ffi namespace as it is
157
+ const ffi = await worker();
158
+
159
+ // will directly append a text node to the main thread body
160
+ ffi.global.document.body.append('it worked 🥳');
161
+ ```
162
+
163
+ To know more about *reflected-ffi* module and features, please visit [the related project](https://github.com/WebReflection/reflected-ffi/#readme).
164
+
138
165
 
139
166
  ### Extras
140
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reflected",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A primitive to allow workers to call synchronously any functionality exposed on the main thread.",
5
5
  "exports": {
6
6
  ".": {
package/src/ffi/main.js CHANGED
@@ -4,22 +4,27 @@ import main from '../index.js';
4
4
 
5
5
  const { assign } = Object;
6
6
 
7
+ /**
8
+ * @param {string} url
9
+ * @param {import('../index.js').MainOptions & import('reflected-ffi/local').LocalOptions} options
10
+ */
7
11
  export default async (url, options) => {
8
12
  const ffi = local({
9
13
  timeout: 0,
10
14
  buffer: true,
11
15
  ...options,
16
+ // @ts-ignore
12
17
  reflect: (...args) => worker.send(args),
13
18
  });
14
19
 
15
- const worker = await main(
20
+ const worker = /** @type {Worker} */(await main(
16
21
  url,
17
22
  {
18
23
  ...options,
19
24
  // @ts-ignore
20
25
  onsync: args => ffi.reflect(...args),
21
26
  }
22
- );
27
+ ));
23
28
 
24
29
  const { terminate } = worker;
25
30
  return assign(worker, {
package/src/ffi/worker.js CHANGED
@@ -2,6 +2,9 @@ import remote from 'reflected-ffi/remote';
2
2
 
3
3
  import worker from '../index.js';
4
4
 
5
+ /**
6
+ * @param {import('../index.js').WorkerOptions & import('reflected-ffi/remote').RemoteOptions} options
7
+ */
5
8
  export default async options => {
6
9
  const reflected = await worker({
7
10
  ...options,
package/test/ffi/index.js CHANGED
@@ -2,5 +2,7 @@ import worker from '../../dist/ffi/main.js';
2
2
 
3
3
  const w = await worker('./worker.js', { serviceWorker: './sw.js' });
4
4
 
5
+ document.body.append('channel: ', w.channel, ' - ');
6
+
5
7
  console.log(w);
6
8
 
package/test/ffi/sw.js CHANGED
@@ -1,154 +1 @@
1
- var CHANNEL = 'fc260aad-4404-43b8-ae9d-2c06554bb294';
2
-
3
- //@ts-check
4
-
5
- /**
6
- * @template T
7
- * @typedef {{promise: Promise<T>, resolve: (value: T) => void, reject: (reason?: any) => void}} Resolvers
8
- */
9
-
10
- // fallback for Android WebView
11
- //@ts-ignore
12
- const withResolvers = Promise.withResolvers || function withResolvers() {
13
- var a, b, c = new this((resolve, reject) => {
14
- a = resolve;
15
- b = reject;
16
- });
17
- return {resolve: a, reject: b, promise: c};
18
- };
19
-
20
- /**
21
- * @template T
22
- * @type {() => Resolvers<T>}
23
- */
24
- var withResolvers$1 = withResolvers.bind(Promise);
25
-
26
- // @ts-check
27
-
28
- /**
29
- * @param {number} [start]
30
- * @returns {() => number}
31
- */
32
- var i32 = start => {
33
- const i32 = new Int32Array(1);
34
- return () => i32[0]++;
35
- };
36
-
37
- //@ts-check
38
-
39
-
40
- /**
41
- * @template V
42
- * @callback Resolve
43
- * @param {V?} [value]
44
- * @returns {void}
45
- */
46
-
47
- /**
48
- * @callback Reject
49
- * @param {any?} [error]
50
- * @returns {void}
51
- */
52
-
53
- /**
54
- * @template V
55
- * @typedef {object} Resolvers
56
- * @prop {Promise<V>} promise
57
- * @prop {Resolve<V>} resolve
58
- * @prop {Reject} reject
59
- */
60
-
61
- /**
62
- * @template K,V
63
- * @typedef {() => [K, Promise<V>]} Next
64
- */
65
-
66
- /**
67
- * @template K,V
68
- * @callback Resolver
69
- * @param {K} uid
70
- * @param {V?} [value]
71
- * @param {any?} [error]
72
- */
73
-
74
- /**
75
- * @template K,V
76
- * @typedef {[Next<K,V>, Resolver<K,V>]} NextResolver
77
- */
78
-
79
- /**
80
- * @template K,V
81
- * @param {(id: number) => K} [as]
82
- * @returns
83
- */
84
- var nextResolver = (as = (id => /** @type {K} */(id))) => {
85
- /** @type {Map<K,Resolvers<V>>} */
86
- const map = new Map;
87
- const next = i32();
88
- return /** @type {NextResolver<K,V>} */([
89
- /** @type {Next<K,V>} */
90
- () => {
91
- let uid;
92
- do { uid = as(next()); }
93
- while (map.has(uid));
94
- const wr = /** @type {Resolvers<V>} */(/** @type {unknown} */(withResolvers$1()));
95
- map.set(uid, wr);
96
- return [uid, wr.promise];
97
- },
98
- /** @type {Resolver<K,V>} */
99
- (uid, value, error) => {
100
- const wr = map.get(uid);
101
- map.delete(uid);
102
- if (error) wr?.reject(error);
103
- else wr?.resolve(value);
104
- },
105
- ]);
106
- };
107
-
108
- const [next, resolve] = nextResolver();
109
-
110
- const { protocol, host, pathname } = location;
111
- const url = `${protocol}//${host}${pathname}`;
112
-
113
- const bc = new BroadcastChannel(CHANNEL);
114
- bc.addEventListener('message', ({ data: [op, details] }) => {
115
- if (op === 'response') {
116
- const [uid, payload] = details;
117
- resolve(uid, `[${payload.join(',')}]`);
118
- }
119
- });
120
-
121
- const response = {
122
- status: 200,
123
- statusText: 'OK',
124
- headers: new Headers({
125
- 'Cache-Control': 'no-cache, must-revalidate',
126
- 'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
127
- 'Content-type': 'application/json',
128
- })
129
- };
130
-
131
- const respond = async details => {
132
- const [uid, promise] = next();
133
- bc.postMessage(['request', [uid, details]]);
134
- return new Response(await promise, response);
135
- };
136
-
137
- // @ts-ignore
138
- const activate = event => event.waitUntil(clients.claim());
139
-
140
- const fetch = async event => {
141
- const { request: r } = event;
142
- if (r.method === 'POST' && r.url.startsWith(url)) {
143
- event.stopImmediatePropagation();
144
- event.respondWith(r.json().then(respond));
145
- event.preventDefault();
146
- }
147
- };
148
-
149
- // @ts-ignore
150
- const install = () => skipWaiting();
151
-
152
- addEventListener('activate', activate);
153
- addEventListener('fetch', fetch);
154
- addEventListener('install', install);
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 a;do{a=e(s())}while(n.has(a));const o=t();return n.set(a,o),[a,o.promise]},(e,t,s)=>{const a=n.get(e);n.delete(e),s?a?.reject(s):a?.resolve(t)}]})(),{protocol:a,host:o,pathname:r}=location,i=`${a}//${o}${r}`,c=new BroadcastChannel("fc260aad-4404-43b8-ae9d-2c06554bb294");c.addEventListener("message",({data:[e,t]})=>{if("response"===e){const[e,n]=t;s(e,`[${n.join(",")}]`)}});const d={status:200,statusText:"OK",headers:new Headers({"Cache-Control":"no-cache, must-revalidate",Expires:"Mon, 26 Jul 1997 05:00:00 GMT","Content-type":"application/json"})},l=async e=>{const[t,s]=n();return c.postMessage(["request",[t,e]]),new Response(await s,d)};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(l)),e.preventDefault())}),addEventListener("install",()=>skipWaiting());
@@ -1,2 +1,18 @@
1
- declare function _default(url: any, options: any): Promise<any>;
1
+ declare function _default(url: string, options: import("../index.js").MainOptions & import("reflected-ffi/local").LocalOptions): Promise<Worker & {
2
+ ffi: {
3
+ assign: {
4
+ <T extends {}, U>(target: T, source: U): T & U;
5
+ <T extends {}, U, V>(target: T, source1: U, source2: V): T & U & V;
6
+ <T extends {}, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
7
+ (target: object, ...sources: any[]): any;
8
+ };
9
+ gather: (target: any, ...keys: (string | symbol)[][]) => any[];
10
+ query: (target: any, path: string) => any;
11
+ direct<T extends WeakKey>(value: T): T;
12
+ evaluate: (callback: Function, ...args: any[]) => any;
13
+ reflect(method: number, uid: number | null, ...args: any[]): any;
14
+ terminate(): void;
15
+ };
16
+ terminate(): void;
17
+ }>;
2
18
  export default _default;
@@ -1,4 +1,4 @@
1
- declare function _default(options: any): Promise<{
1
+ declare function _default(options: import("../index.js").WorkerOptions & import("reflected-ffi/remote").RemoteOptions): Promise<{
2
2
  global: unknown;
3
3
  isProxy: (value: any) => boolean;
4
4
  assign<T extends {}, U>(target: T, source: U): T & U;