promise-worker-bi 5.0.2 → 6.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 +45 -39
- package/dist/index.d.ts +54 -34
- package/dist/index.js +281 -373
- package/package.json +19 -32
package/README.md
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
# promise-worker-bi
|
|
1
|
+
# promise-worker-bi
|
|
2
|
+
|
|
3
|
+
[](https://github.com/dumbmatter/promise-worker-bi/actions/workflows/nodejs.yml)
|
|
4
|
+
[](https://github.com/dumbmatter/promise-worker-bi)
|
|
5
|
+
[](https://github.com/dumbmatter/promise-worker-bi)
|
|
6
|
+
[](https://www.npmjs.com/package/promise-worker-bi)
|
|
7
|
+
[](https://www.npmjs.com/package/promise-worker-bi)
|
|
2
8
|
|
|
3
9
|
A small (~2 kB min+gz) and performant library for communicating with web workers and shared workers, using promises. Post a message from the browser to the worker, get a promise that resolves to the response. Post a message from the worker to the browser, get a promise that resolves to the response. And with shared workers, you can either broadcast to all browser tabs or send a message to a specific tab.
|
|
4
10
|
|
|
@@ -21,14 +27,14 @@ const promiseWorker = new PWBHost(worker);
|
|
|
21
27
|
|
|
22
28
|
// Only needed if you send messages from the worker to the host
|
|
23
29
|
promiseWorker.register((message) => {
|
|
24
|
-
|
|
30
|
+
return "pong2";
|
|
25
31
|
});
|
|
26
32
|
|
|
27
33
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
const response = await promiseWorker.postMessage("ping");
|
|
35
|
+
// handle response 'pong'
|
|
30
36
|
} catch (error) {
|
|
31
|
-
|
|
37
|
+
// handle error
|
|
32
38
|
}
|
|
33
39
|
```
|
|
34
40
|
|
|
@@ -42,14 +48,14 @@ const promiseWorker = new PWBWorker();
|
|
|
42
48
|
|
|
43
49
|
// Only needed if you send messages from the host to the worker
|
|
44
50
|
promiseWorker.register((message) => {
|
|
45
|
-
|
|
51
|
+
return "pong";
|
|
46
52
|
});
|
|
47
53
|
|
|
48
54
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
const response = await promiseWorker.postMessage("ping2");
|
|
56
|
+
// handle response 'pong2'
|
|
51
57
|
} catch (error) {
|
|
52
|
-
|
|
58
|
+
// handle error
|
|
53
59
|
}
|
|
54
60
|
```
|
|
55
61
|
|
|
@@ -61,15 +67,15 @@ The message you send can be any object, array, string, number, etc. - anything t
|
|
|
61
67
|
|
|
62
68
|
```js
|
|
63
69
|
await promiseWorker.postMessage({
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
hello: "world",
|
|
71
|
+
answer: 42,
|
|
72
|
+
"this is fun": true,
|
|
67
73
|
});
|
|
68
74
|
```
|
|
69
75
|
|
|
70
76
|
```js
|
|
71
77
|
promiseWorker.register((message) => {
|
|
72
|
-
|
|
78
|
+
console.log(message); // { hello: 'world', answer: 42, 'this is fun': true }
|
|
73
79
|
});
|
|
74
80
|
```
|
|
75
81
|
|
|
@@ -79,7 +85,7 @@ The registered handler can return either a Promise or a normal value:
|
|
|
79
85
|
|
|
80
86
|
```js
|
|
81
87
|
promiseWorker.register(async () => {
|
|
82
|
-
|
|
88
|
+
"much async, very promise";
|
|
83
89
|
});
|
|
84
90
|
```
|
|
85
91
|
|
|
@@ -94,15 +100,15 @@ Any thrown errors or asynchronous rejections during a response will be propagate
|
|
|
94
100
|
|
|
95
101
|
```js
|
|
96
102
|
promiseWorker.register((message) => {
|
|
97
|
-
|
|
103
|
+
throw new Error("naughty!");
|
|
98
104
|
});
|
|
99
105
|
```
|
|
100
106
|
|
|
101
107
|
```js
|
|
102
108
|
try {
|
|
103
|
-
|
|
109
|
+
await promiseWorker.postMessage("whoops");
|
|
104
110
|
} catch (error) {
|
|
105
|
-
|
|
111
|
+
console.log(error.message); // 'naughty!'
|
|
106
112
|
}
|
|
107
113
|
```
|
|
108
114
|
|
|
@@ -114,7 +120,7 @@ Therefore, promise-worker-bi includes a unified API that works in Web Workers an
|
|
|
114
120
|
|
|
115
121
|
```js
|
|
116
122
|
promiseWorker.registerError((error) => {
|
|
117
|
-
|
|
123
|
+
console.log("Error inside worker!", err);
|
|
118
124
|
});
|
|
119
125
|
```
|
|
120
126
|
|
|
@@ -130,21 +136,21 @@ If you need to send messages of multiple types to the worker, just add some type
|
|
|
130
136
|
|
|
131
137
|
```js
|
|
132
138
|
const response1 = await promiseWorker.postMessage({
|
|
133
|
-
|
|
139
|
+
type: "en",
|
|
134
140
|
});
|
|
135
141
|
|
|
136
142
|
const response2 = await promiseWorker.postMessage({
|
|
137
|
-
|
|
143
|
+
type: "en",
|
|
138
144
|
});
|
|
139
145
|
```
|
|
140
146
|
|
|
141
147
|
```js
|
|
142
148
|
promiseWorker.register((message) => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
if (message.type === "en") {
|
|
150
|
+
return "Hello!";
|
|
151
|
+
} else if (message.type === "fr") {
|
|
152
|
+
return "Bonjour!";
|
|
153
|
+
}
|
|
148
154
|
});
|
|
149
155
|
```
|
|
150
156
|
|
|
@@ -162,14 +168,14 @@ const worker = new SharedWorker("worker.js");
|
|
|
162
168
|
const promiseWorker = new PWBHost(worker);
|
|
163
169
|
|
|
164
170
|
promiseWorker.register((message) => {
|
|
165
|
-
|
|
171
|
+
console.log(message);
|
|
166
172
|
});
|
|
167
173
|
|
|
168
174
|
// setTimeout is just to give you enough time to open main.js and main2.js in
|
|
169
175
|
// two separate tabs.
|
|
170
176
|
setTimeout(async () => {
|
|
171
|
-
|
|
172
|
-
|
|
177
|
+
const response = await promiseWorker.postMessage("broadcast");
|
|
178
|
+
console.log("Echoed response:", response);
|
|
173
179
|
}, 1000);
|
|
174
180
|
```
|
|
175
181
|
|
|
@@ -199,13 +205,13 @@ import { PWBWorker } from "promise-worker-bi";
|
|
|
199
205
|
const promiseWorker = new PWBWorker();
|
|
200
206
|
|
|
201
207
|
promiseWorker.register((message, hostID) => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
if (message === "broadcast") {
|
|
209
|
+
promiseWorker.postMessage("to all tabs");
|
|
210
|
+
} else {
|
|
211
|
+
promiseWorker.postMessage(`hello host ${hostID}`, hostID);
|
|
212
|
+
}
|
|
207
213
|
|
|
208
|
-
|
|
214
|
+
return message;
|
|
209
215
|
});
|
|
210
216
|
```
|
|
211
217
|
|
|
@@ -244,12 +250,12 @@ If you want to respond to a message by sending a transferable object back, such
|
|
|
244
250
|
|
|
245
251
|
```js
|
|
246
252
|
promiseWorker.register(async (message) => {
|
|
247
|
-
|
|
253
|
+
const processedMessage = await processMessage(message);
|
|
248
254
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
return {
|
|
256
|
+
message: processedMessage,
|
|
257
|
+
_PWB_TRANSFER: [processedMessage.someTransferableProprty],
|
|
258
|
+
};
|
|
253
259
|
});
|
|
254
260
|
```
|
|
255
261
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,38 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
type
|
|
1
|
+
//#region src/fakeError.d.ts
|
|
2
|
+
type FakeError = {
|
|
3
|
+
name: string;
|
|
4
|
+
message: string;
|
|
5
|
+
stack?: string;
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/message.d.ts
|
|
9
|
+
declare const MSGTYPE_QUERY = 0;
|
|
10
|
+
declare const MSGTYPE_RESPONSE = 1;
|
|
11
|
+
declare const MSGTYPE_HOST_ID = 2;
|
|
12
|
+
declare const MSGTYPE_HOST_LOCK = 3;
|
|
13
|
+
declare const MSGTYPE_WORKER_ERROR = 4;
|
|
14
|
+
type QueryMessage = [typeof MSGTYPE_QUERY, number, unknown] | [typeof MSGTYPE_QUERY, number, unknown, number | undefined];
|
|
15
|
+
type ResponseMessage = [typeof MSGTYPE_RESPONSE, number, FakeError] | [typeof MSGTYPE_RESPONSE, number, null, unknown];
|
|
16
|
+
type HostIdMessage = [typeof MSGTYPE_HOST_ID, number];
|
|
17
|
+
type HostLockMessage = [typeof MSGTYPE_HOST_LOCK, number, string];
|
|
18
|
+
type WorkerErrorMessage = [typeof MSGTYPE_WORKER_ERROR, FakeError];
|
|
19
|
+
type Message = QueryMessage | ResponseMessage | HostIdMessage | HostLockMessage | WorkerErrorMessage;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/PWBBase.d.ts
|
|
22
|
+
type QueryCallback = (a: unknown, b: number | undefined) => any;
|
|
3
23
|
declare abstract class PWBBase {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
_onMessageCommon(e: MessageEvent): {
|
|
13
|
-
message: any;
|
|
14
|
-
type: number;
|
|
15
|
-
} | void;
|
|
24
|
+
protected _callbacks: Map<number, (a: Error | null, b: unknown) => void>;
|
|
25
|
+
protected _queryCallback: QueryCallback;
|
|
26
|
+
constructor();
|
|
27
|
+
register(cb: QueryCallback): void;
|
|
28
|
+
protected abstract _postMessage(obj: Message, hostID?: number | undefined, transfer?: Transferable[] | undefined): void;
|
|
29
|
+
private _postResponse;
|
|
30
|
+
private _handleQuery;
|
|
31
|
+
protected _onMessageCommon(e: MessageEvent): HostIdMessage | HostLockMessage | WorkerErrorMessage | undefined;
|
|
16
32
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/PWBHost.d.ts
|
|
35
|
+
type ErrorCallback = (a: Error) => void;
|
|
36
|
+
export declare class PWBHost extends PWBBase {
|
|
37
|
+
private _errorCallback;
|
|
38
|
+
private _hostID;
|
|
39
|
+
private _hostIDQueue;
|
|
40
|
+
private _worker;
|
|
41
|
+
constructor(worker: SharedWorker | Worker);
|
|
42
|
+
registerError(cb: ErrorCallback): void;
|
|
43
|
+
protected _postMessage(obj: QueryMessage | ResponseMessage | HostLockMessage, _hostID?: unknown, transfer?: Transferable[] | undefined): void;
|
|
44
|
+
postMessage(userMessage: unknown, _hostID?: undefined, transfer?: Transferable[] | undefined): Promise<any>;
|
|
45
|
+
private _onMessage;
|
|
27
46
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/PWBWorker.d.ts
|
|
49
|
+
export declare class PWBWorker extends PWBBase {
|
|
50
|
+
private _hosts;
|
|
51
|
+
private _maxHostID;
|
|
52
|
+
private _sharedWorker;
|
|
53
|
+
constructor();
|
|
54
|
+
protected _postMessage(message: QueryMessage | ResponseMessage | HostIdMessage | WorkerErrorMessage, targetHostID?: number | undefined, transfer?: Transferable[] | undefined): void;
|
|
55
|
+
postMessage(userMessage: unknown, targetHostID?: number | undefined, transfer?: Transferable[] | undefined): Promise<unknown>;
|
|
56
|
+
private _onMessage;
|
|
37
57
|
}
|
|
38
|
-
|
|
58
|
+
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,377 +1,285 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// Inlined from https://github.com/then/is-promise
|
|
10
|
-
const isPromise = obj => !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
|
|
11
|
-
const toFakeError = error => {
|
|
12
|
-
const fakeError = {
|
|
13
|
-
name: error.name,
|
|
14
|
-
message: error.message
|
|
15
|
-
};
|
|
16
|
-
if (typeof error.stack === "string") {
|
|
17
|
-
fakeError.stack = error.stack;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// These are non-standard properties, I think only in some versions of Firefox
|
|
21
|
-
// @ts-expect-error
|
|
22
|
-
if (typeof error.fileName === "string") {
|
|
23
|
-
// @ts-expect-error
|
|
24
|
-
fakeError.fileName = error.fileName;
|
|
25
|
-
}
|
|
26
|
-
// @ts-expect-error
|
|
27
|
-
if (typeof error.columnNumber === "number") {
|
|
28
|
-
// @ts-expect-error
|
|
29
|
-
fakeError.columnNumber = error.columnNumber;
|
|
30
|
-
}
|
|
31
|
-
// @ts-expect-error
|
|
32
|
-
if (typeof error.lineNumber === "number") {
|
|
33
|
-
// @ts-expect-error
|
|
34
|
-
fakeError.lineNumber = error.lineNumber;
|
|
35
|
-
}
|
|
36
|
-
return fakeError;
|
|
1
|
+
//#region src/fakeError.ts
|
|
2
|
+
const isFakeError = (x) => {
|
|
3
|
+
if (typeof x !== "object" || x === null) return false;
|
|
4
|
+
const candidate = x;
|
|
5
|
+
if (typeof candidate.name !== "string" || typeof candidate.message !== "string") return false;
|
|
6
|
+
if (candidate.stack !== void 0 && typeof candidate.stack !== "string") return false;
|
|
7
|
+
return true;
|
|
37
8
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
9
|
+
const toFakeError = (error) => {
|
|
10
|
+
const fakeError = {
|
|
11
|
+
name: error.name,
|
|
12
|
+
message: error.message
|
|
13
|
+
};
|
|
14
|
+
if (typeof error.stack === "string") fakeError.stack = error.stack;
|
|
15
|
+
return fakeError;
|
|
43
16
|
};
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
console.error("Error in Worker:");
|
|
47
|
-
console.error(err); // Safari needs it on new line
|
|
17
|
+
const fromFakeError = (fakeError) => {
|
|
18
|
+
return Object.assign(/* @__PURE__ */ new Error(), fakeError);
|
|
48
19
|
};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
self.addEventListener("error", e => {
|
|
315
|
-
logError(e.error);
|
|
316
|
-
this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)]);
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
_postMessage(obj, targetHostID, transfer) {
|
|
321
|
-
// console.log('_postMessage', obj, targetHostID);
|
|
322
|
-
if (this._workerType === "SharedWorker") {
|
|
323
|
-
// If targetHostID has been deleted, this will do nothing, which is fine I think
|
|
324
|
-
this._hosts.forEach(({
|
|
325
|
-
port
|
|
326
|
-
}, hostID) => {
|
|
327
|
-
if (targetHostID === undefined || targetHostID === hostID) {
|
|
328
|
-
// @ts-expect-error TypeScript thinks transfer can't be undefined
|
|
329
|
-
port.postMessage(obj, transfer);
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
} else if (this._workerType === "Worker") {
|
|
333
|
-
// @ts-expect-error TypeScript thinks self is window, which has a different postMessage call signature. In a worker, this is correct.
|
|
334
|
-
self.postMessage(obj, transfer);
|
|
335
|
-
} else {
|
|
336
|
-
throw new Error("WTF");
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
postMessage(userMessage, targetHostID, transfer) {
|
|
340
|
-
// console.log('postMessage', userMessage, targetHostID);
|
|
341
|
-
const actuallyPostMessage = (resolve, reject) => {
|
|
342
|
-
const messageID = messageIDs;
|
|
343
|
-
messageIDs += 1;
|
|
344
|
-
const messageToSend = [MSGTYPE_QUERY, messageID, userMessage];
|
|
345
|
-
this._callbacks.set(messageID, (error, result) => {
|
|
346
|
-
if (error) {
|
|
347
|
-
reject(error);
|
|
348
|
-
} else {
|
|
349
|
-
resolve(result);
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
this._postMessage(messageToSend, targetHostID, transfer);
|
|
353
|
-
};
|
|
354
|
-
return new Promise((resolve, reject) => {
|
|
355
|
-
actuallyPostMessage(resolve, reject);
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
_onMessage(e) {
|
|
359
|
-
const common = this._onMessageCommon(e);
|
|
360
|
-
if (!common) {
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const {
|
|
364
|
-
message,
|
|
365
|
-
type
|
|
366
|
-
} = common;
|
|
367
|
-
if (type === MSGTYPE_HOST_CLOSE) {
|
|
368
|
-
if (typeof message[2] !== "number") {
|
|
369
|
-
throw new Error("Invalid hostID");
|
|
370
|
-
}
|
|
371
|
-
const hostID = message[2];
|
|
372
|
-
this._hosts.delete(hostID);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
20
|
+
const parseMessage = (message) => {
|
|
21
|
+
if (!Array.isArray(message) || message.length < 2 || message.length > 4) return;
|
|
22
|
+
const type = message[0];
|
|
23
|
+
if (type === 0) {
|
|
24
|
+
if (typeof message[1] !== "number") throw new Error("Invalid messageID");
|
|
25
|
+
if (typeof message[3] !== "number" && message[3] !== void 0) throw new Error("Invalid hostID");
|
|
26
|
+
return message;
|
|
27
|
+
}
|
|
28
|
+
if (type === 1) {
|
|
29
|
+
if (typeof message[1] !== "number") throw new Error("Invalid messageID");
|
|
30
|
+
if (message[2] !== null && !isFakeError(message[2])) throw new Error("Invalid error");
|
|
31
|
+
return message;
|
|
32
|
+
}
|
|
33
|
+
if (type === 2) {
|
|
34
|
+
if (typeof message[1] !== "number") throw new Error("Invalid hostID");
|
|
35
|
+
return message;
|
|
36
|
+
}
|
|
37
|
+
if (type === 3) {
|
|
38
|
+
if (typeof message[1] !== "number") throw new Error("Invalid hostID");
|
|
39
|
+
if (typeof message[2] !== "string") throw new Error("Invalid lockId");
|
|
40
|
+
return message;
|
|
41
|
+
}
|
|
42
|
+
if (type === 4) {
|
|
43
|
+
if (!isFakeError(message[1])) throw new Error("Invalid error");
|
|
44
|
+
return message;
|
|
45
|
+
}
|
|
46
|
+
throw new Error("Invalid message type");
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/PWBBase.ts
|
|
50
|
+
const isPromise = (obj) => !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
|
|
51
|
+
const logError = (err) => {
|
|
52
|
+
console.error("Error in Worker:");
|
|
53
|
+
console.error(err);
|
|
54
|
+
};
|
|
55
|
+
const isSharedWorker = (worker) => {
|
|
56
|
+
return worker.port !== void 0;
|
|
57
|
+
};
|
|
58
|
+
var PWBBase = class {
|
|
59
|
+
_callbacks;
|
|
60
|
+
_queryCallback;
|
|
61
|
+
constructor() {
|
|
62
|
+
this._callbacks = /* @__PURE__ */ new Map();
|
|
63
|
+
this._queryCallback = () => {};
|
|
64
|
+
this._onMessage = this._onMessage.bind(this);
|
|
65
|
+
}
|
|
66
|
+
register(cb) {
|
|
67
|
+
this._queryCallback = cb;
|
|
68
|
+
}
|
|
69
|
+
_postResponse(messageID, error, result, hostID) {
|
|
70
|
+
if (error) {
|
|
71
|
+
logError(error);
|
|
72
|
+
this._postMessage([
|
|
73
|
+
1,
|
|
74
|
+
messageID,
|
|
75
|
+
toFakeError(error)
|
|
76
|
+
], hostID);
|
|
77
|
+
} else if (typeof result === "object" && result !== null && Object.hasOwn(result, "message") && Object.hasOwn(result, "_PWB_TRANSFER")) this._postMessage([
|
|
78
|
+
1,
|
|
79
|
+
messageID,
|
|
80
|
+
null,
|
|
81
|
+
result.message
|
|
82
|
+
], hostID, result._PWB_TRANSFER);
|
|
83
|
+
else this._postMessage([
|
|
84
|
+
1,
|
|
85
|
+
messageID,
|
|
86
|
+
null,
|
|
87
|
+
result
|
|
88
|
+
], hostID);
|
|
89
|
+
}
|
|
90
|
+
_handleQuery(message) {
|
|
91
|
+
const messageID = message[1];
|
|
92
|
+
const query = message[2];
|
|
93
|
+
const hostID = message[3];
|
|
94
|
+
try {
|
|
95
|
+
const result = this._queryCallback(query, hostID);
|
|
96
|
+
if (!isPromise(result)) this._postResponse(messageID, null, result, hostID);
|
|
97
|
+
else result.then((finalResult) => {
|
|
98
|
+
this._postResponse(messageID, null, finalResult, hostID);
|
|
99
|
+
}, (finalError) => {
|
|
100
|
+
this._postResponse(messageID, finalError, hostID);
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
this._postResponse(messageID, err);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
_onMessageCommon(e) {
|
|
107
|
+
const message = parseMessage(e.data);
|
|
108
|
+
if (!message) return;
|
|
109
|
+
if (message[0] === 0) {
|
|
110
|
+
this._handleQuery(message);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (message[0] === 1) {
|
|
114
|
+
const messageID = message[1];
|
|
115
|
+
const error = message[2] === null ? null : fromFakeError(message[2]);
|
|
116
|
+
const callback = this._callbacks.get(messageID);
|
|
117
|
+
if (callback === void 0) return;
|
|
118
|
+
this._callbacks.delete(messageID);
|
|
119
|
+
callback(error, message[3]);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
return message;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/PWBHost.ts
|
|
127
|
+
let nextMessageID$1 = 0;
|
|
128
|
+
var PWBHost = class extends PWBBase {
|
|
129
|
+
_errorCallback;
|
|
130
|
+
_hostID;
|
|
131
|
+
_hostIDQueue;
|
|
132
|
+
_worker;
|
|
133
|
+
constructor(worker) {
|
|
134
|
+
super();
|
|
135
|
+
if (!isSharedWorker(worker)) worker.addEventListener("message", this._onMessage);
|
|
136
|
+
else {
|
|
137
|
+
worker.port.addEventListener("message", this._onMessage);
|
|
138
|
+
worker.port.start();
|
|
139
|
+
}
|
|
140
|
+
this._worker = worker;
|
|
141
|
+
this._hostIDQueue = [];
|
|
142
|
+
}
|
|
143
|
+
registerError(cb) {
|
|
144
|
+
this._errorCallback = cb;
|
|
145
|
+
this._worker.addEventListener("error", (e) => {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
e.stopPropagation();
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
_postMessage(obj, _hostID, transfer) {
|
|
151
|
+
if (isSharedWorker(this._worker)) {
|
|
152
|
+
if (transfer) this._worker.port.postMessage(obj, transfer);
|
|
153
|
+
else this._worker.port.postMessage(obj);
|
|
154
|
+
} else if (transfer) this._worker.postMessage(obj, transfer);
|
|
155
|
+
else this._worker.postMessage(obj);
|
|
156
|
+
}
|
|
157
|
+
postMessage(userMessage, _hostID, transfer) {
|
|
158
|
+
const actuallyPostMessage = (resolve, reject) => {
|
|
159
|
+
const messageID = nextMessageID$1;
|
|
160
|
+
nextMessageID$1 += 1;
|
|
161
|
+
const messageToSend = [
|
|
162
|
+
0,
|
|
163
|
+
messageID,
|
|
164
|
+
userMessage,
|
|
165
|
+
this._hostID
|
|
166
|
+
];
|
|
167
|
+
this._callbacks.set(messageID, (error, result) => {
|
|
168
|
+
if (error) reject(error);
|
|
169
|
+
else resolve(result);
|
|
170
|
+
});
|
|
171
|
+
this._postMessage(messageToSend, void 0, transfer);
|
|
172
|
+
};
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
if (this._hostIDQueue !== void 0) this._hostIDQueue.push(() => {
|
|
175
|
+
actuallyPostMessage(resolve, reject);
|
|
176
|
+
});
|
|
177
|
+
else actuallyPostMessage(resolve, reject);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
_onMessage(e) {
|
|
181
|
+
const message = this._onMessageCommon(e);
|
|
182
|
+
if (!message) return;
|
|
183
|
+
if (message[0] === 2) {
|
|
184
|
+
if (this._hostID !== void 0) throw new Error("Received duplicate hostID message");
|
|
185
|
+
const hostID = message[1];
|
|
186
|
+
this._hostID = hostID;
|
|
187
|
+
if (this._hostIDQueue !== void 0) {
|
|
188
|
+
for (const cb of this._hostIDQueue) setTimeout(() => {
|
|
189
|
+
cb();
|
|
190
|
+
}, 0);
|
|
191
|
+
this._hostIDQueue = void 0;
|
|
192
|
+
}
|
|
193
|
+
const lockId = `pwb-${Math.random()}`;
|
|
194
|
+
navigator.locks.request(lockId, async () => {
|
|
195
|
+
this._postMessage([
|
|
196
|
+
3,
|
|
197
|
+
hostID,
|
|
198
|
+
lockId
|
|
199
|
+
]);
|
|
200
|
+
return new Promise(() => {});
|
|
201
|
+
});
|
|
202
|
+
} else if (message[0] === 4) {
|
|
203
|
+
if (message[1] !== null) {
|
|
204
|
+
const error = fromFakeError(message[1]);
|
|
205
|
+
if (this._errorCallback !== void 0) this._errorCallback(error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/PWBWorker.ts
|
|
212
|
+
let nextMessageID = 0;
|
|
213
|
+
var PWBWorker = class extends PWBBase {
|
|
214
|
+
_hosts = /* @__PURE__ */ new Map();
|
|
215
|
+
_maxHostID = -1;
|
|
216
|
+
_sharedWorker;
|
|
217
|
+
constructor() {
|
|
218
|
+
super();
|
|
219
|
+
if (typeof SharedWorkerGlobalScope !== "undefined" && self instanceof SharedWorkerGlobalScope) {
|
|
220
|
+
this._sharedWorker = true;
|
|
221
|
+
self.addEventListener("connect", (e) => {
|
|
222
|
+
const port = e.ports[0];
|
|
223
|
+
port.addEventListener("message", (e2) => this._onMessage(e2));
|
|
224
|
+
port.start();
|
|
225
|
+
this._maxHostID += 1;
|
|
226
|
+
const hostID = this._maxHostID;
|
|
227
|
+
this._hosts.set(hostID, { port });
|
|
228
|
+
this._postMessage([2, hostID], hostID);
|
|
229
|
+
});
|
|
230
|
+
self.addEventListener("error", (e) => {
|
|
231
|
+
logError(e.error);
|
|
232
|
+
const hostID = this._hosts.keys().next().value;
|
|
233
|
+
if (hostID !== void 0) this._postMessage([4, toFakeError(e.error)], hostID);
|
|
234
|
+
});
|
|
235
|
+
} else {
|
|
236
|
+
this._sharedWorker = false;
|
|
237
|
+
self.addEventListener("message", this._onMessage);
|
|
238
|
+
this._postMessage([2, 0], 0);
|
|
239
|
+
self.addEventListener("error", (e) => {
|
|
240
|
+
logError(e.error);
|
|
241
|
+
this._postMessage([4, toFakeError(e.error)]);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
_postMessage(message, targetHostID, transfer) {
|
|
246
|
+
if (this._sharedWorker) {
|
|
247
|
+
for (const [hostID, { port }] of this._hosts) if (targetHostID === void 0 || targetHostID === hostID) {
|
|
248
|
+
if (transfer) port.postMessage(message, transfer);
|
|
249
|
+
else port.postMessage(message);
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
const _self = self;
|
|
253
|
+
if (transfer) _self.postMessage(message, transfer);
|
|
254
|
+
else _self.postMessage(message);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
postMessage(userMessage, targetHostID, transfer) {
|
|
258
|
+
const actuallyPostMessage = (resolve, reject) => {
|
|
259
|
+
const messageID = nextMessageID;
|
|
260
|
+
nextMessageID += 1;
|
|
261
|
+
const messageToSend = [
|
|
262
|
+
0,
|
|
263
|
+
messageID,
|
|
264
|
+
userMessage
|
|
265
|
+
];
|
|
266
|
+
this._callbacks.set(messageID, (error, result) => {
|
|
267
|
+
if (error) reject(error);
|
|
268
|
+
else resolve(result);
|
|
269
|
+
});
|
|
270
|
+
this._postMessage(messageToSend, targetHostID, transfer);
|
|
271
|
+
};
|
|
272
|
+
return new Promise((resolve, reject) => {
|
|
273
|
+
actuallyPostMessage(resolve, reject);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
_onMessage(e) {
|
|
277
|
+
const message = this._onMessageCommon(e);
|
|
278
|
+
if (!message) return;
|
|
279
|
+
if (message[0] === 3) navigator.locks.request(message[2], () => {
|
|
280
|
+
if (this._hosts.size > 1) this._hosts.delete(message[1]);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
//#endregion
|
|
377
285
|
export { PWBHost, PWBWorker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "promise-worker-bi",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0-beta.0",
|
|
4
4
|
"description": "Promise-based messaging for Web Workers and Shared Workers",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -12,13 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"scripts": {
|
|
15
|
-
"prepack": "
|
|
16
|
-
"build": "
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"prettier": "prettier --write 'src/*.ts' && prettier --write 'test/*.js' && prettier --write 'scripts/*.js'",
|
|
20
|
-
"karma": "node --run build-test && karma start",
|
|
21
|
-
"test": "tsc --noEmit && node --run lint && node --run karma",
|
|
15
|
+
"prepack": "pnpm run build",
|
|
16
|
+
"build": "tsdown",
|
|
17
|
+
"lint": "pnpm run build && tsc && eslint .",
|
|
18
|
+
"test": "pnpm run build && vitest run",
|
|
22
19
|
"prepare": "husky"
|
|
23
20
|
},
|
|
24
21
|
"repository": {
|
|
@@ -40,36 +37,26 @@
|
|
|
40
37
|
},
|
|
41
38
|
"homepage": "https://github.com/dumbmatter/promise-worker-bi",
|
|
42
39
|
"devDependencies": {
|
|
43
|
-
"@babel/core": "^7.29.0",
|
|
44
|
-
"@babel/preset-typescript": "^7.28.5",
|
|
45
40
|
"@eslint/js": "^10.0.1",
|
|
46
|
-
"@
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
49
|
-
"
|
|
50
|
-
"eslint": "^
|
|
51
|
-
"
|
|
52
|
-
"globals": "^17.4.0",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.69.0",
|
|
42
|
+
"@typescript-eslint/parser": "^8.69.0",
|
|
43
|
+
"@vitest/browser-playwright": "^5.0.0",
|
|
44
|
+
"eslint": "^10.10.0",
|
|
45
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
46
|
+
"globals": "^17.12.0",
|
|
53
47
|
"husky": "^9.1.7",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"prettier": "^3.8.1",
|
|
62
|
-
"rollup": "^4.59.0",
|
|
63
|
-
"rollup-plugin-node-builtins": "^2.1.2",
|
|
64
|
-
"rollup-plugin-node-globals": "^1.4.0",
|
|
65
|
-
"tinyglobby": "^0.2.15",
|
|
66
|
-
"typescript": "^5.9.3",
|
|
67
|
-
"typescript-eslint": "^8.56.1"
|
|
48
|
+
"lint-staged": "^17.5.0",
|
|
49
|
+
"oxfmt": "^0.66.0",
|
|
50
|
+
"playwright": "^1.63.0",
|
|
51
|
+
"tsdown": "^0.23.0",
|
|
52
|
+
"typescript": "^6.0.3",
|
|
53
|
+
"typescript-eslint": "^8.69.0",
|
|
54
|
+
"vitest": "^5.0.0"
|
|
68
55
|
},
|
|
69
56
|
"files": [
|
|
70
57
|
"dist"
|
|
71
58
|
],
|
|
72
59
|
"lint-staged": {
|
|
73
|
-
"
|
|
60
|
+
"*": "oxfmt --no-error-on-unmatched-pattern"
|
|
74
61
|
}
|
|
75
62
|
}
|