promise-worker-bi 4.1.1 → 5.0.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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- declare type ErrorCallback = (a: Error) => void;
2
- declare type QueryCallback = (a: any[], b: number | undefined) => any;
1
+ type ErrorCallback = (a: Error) => void;
2
+ type QueryCallback = (a: any[], b: number | undefined) => any;
3
3
  declare abstract class PWBBase {
4
4
  _callbacks: Map<number, (a: Error | null, b: any) => void>;
5
5
  _queryCallback: QueryCallback;
@@ -4,96 +4,82 @@ const MSGTYPE_RESPONSE = 1;
4
4
  const MSGTYPE_HOST_ID = 2;
5
5
  const MSGTYPE_HOST_CLOSE = 3;
6
6
  const MSGTYPE_WORKER_ERROR = 4;
7
- const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID, MSGTYPE_HOST_CLOSE, MSGTYPE_WORKER_ERROR]; // Inlined from https://github.com/then/is-promise
7
+ const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID, MSGTYPE_HOST_CLOSE, MSGTYPE_WORKER_ERROR];
8
8
 
9
+ // Inlined from https://github.com/then/is-promise
9
10
  const isPromise = obj => !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
10
-
11
11
  const toFakeError = error => {
12
12
  const fakeError = {
13
13
  name: error.name,
14
14
  message: error.message
15
15
  };
16
-
17
16
  if (typeof error.stack === "string") {
18
17
  fakeError.stack = error.stack;
19
- } // These are non-standard properties, I think only in some versions of Firefox
20
- // @ts-expect-error
21
-
18
+ }
22
19
 
20
+ // These are non-standard properties, I think only in some versions of Firefox
21
+ // @ts-expect-error
23
22
  if (typeof error.fileName === "string") {
24
23
  // @ts-expect-error
25
24
  fakeError.fileName = error.fileName;
26
- } // @ts-expect-error
27
-
28
-
25
+ }
26
+ // @ts-expect-error
29
27
  if (typeof error.columnNumber === "number") {
30
28
  // @ts-expect-error
31
29
  fakeError.columnNumber = error.columnNumber;
32
- } // @ts-expect-error
33
-
34
-
30
+ }
31
+ // @ts-expect-error
35
32
  if (typeof error.lineNumber === "number") {
36
33
  // @ts-expect-error
37
34
  fakeError.lineNumber = error.lineNumber;
38
35
  }
39
-
40
36
  return fakeError;
41
- }; // Object rather than FakeError for convenience
42
-
37
+ };
43
38
 
39
+ // Object rather than FakeError for convenience
44
40
  const fromFakeError = fakeError => {
45
41
  const error = new Error();
46
42
  return Object.assign(error, fakeError);
47
43
  };
48
-
49
44
  const logError = err => {
50
45
  // Logging in the console makes debugging in the worker easier
51
-
52
- /* eslint-disable no-console */
53
46
  console.error("Error in Worker:");
54
47
  console.error(err); // Safari needs it on new line
55
-
56
- /* eslint-enable no-console */
57
48
  };
58
-
59
49
  class PWBBase {
60
50
  constructor() {
61
51
  // console.log('constructor', worker);
62
- this._callbacks = new Map(); // eslint-disable-next-line @typescript-eslint/no-empty-function
63
-
64
- this._queryCallback = () => {}; // @ts-expect-error
65
-
52
+ this._callbacks = new Map();
53
+ this._queryCallback = () => {};
66
54
 
55
+ // @ts-expect-error
67
56
  this._onMessage = this._onMessage.bind(this);
68
57
  }
69
-
70
58
  register(cb) {
71
59
  // console.log('register', cb);
72
60
  this._queryCallback = cb;
73
- } // From worker, 2nd param could be hostID if sending to specific host. From UI, 2nd param could be an array of transferable objects
61
+ }
74
62
 
63
+ // From worker, 2nd param could be hostID if sending to specific host. From UI, 2nd param could be an array of transferable objects
75
64
 
76
65
  _postResponse(messageID, error, result, hostID) {
77
66
  // console.log('_postResponse', messageID, error, result);
78
67
  if (error) {
79
68
  logError(error);
80
-
81
69
  this._postMessage([MSGTYPE_RESPONSE, messageID, toFakeError(error)], hostID);
82
70
  } else {
83
71
  // Hackily identify when message contains transferable objects
84
- if (typeof result === "object" && result !== null && result.hasOwnProperty("message") && result.hasOwnProperty("_PWB_TRANSFER")) {
72
+ if (typeof result === "object" && result !== null && Object.hasOwn(result, "message") && Object.hasOwn(result, "_PWB_TRANSFER")) {
85
73
  this._postMessage([MSGTYPE_RESPONSE, messageID, null, result.message], hostID, result._PWB_TRANSFER);
86
74
  } else {
87
75
  this._postMessage([MSGTYPE_RESPONSE, messageID, null, result], hostID);
88
76
  }
89
77
  }
90
78
  }
91
-
92
79
  _handleQuery(messageID, query, hostID) {
93
80
  // console.log('_handleQuery', messageID, query);
94
81
  try {
95
82
  const result = this._queryCallback(query, hostID);
96
-
97
83
  if (!isPromise(result)) {
98
84
  this._postResponse(messageID, null, result, hostID);
99
85
  } else {
@@ -106,78 +92,61 @@ class PWBBase {
106
92
  } catch (err) {
107
93
  this._postResponse(messageID, err);
108
94
  }
109
- } // Either return messageID and type if further processing is needed, or undefined otherwise
110
-
95
+ }
111
96
 
97
+ // Either return messageID and type if further processing is needed, or undefined otherwise
112
98
  _onMessageCommon(e) {
113
- // eslint-disable-line no-undef
114
99
  // console.log('_onMessage', e.data);
115
100
  const message = e.data;
116
-
117
101
  if (!Array.isArray(message) || message.length < 3 || message.length > 4) {
118
102
  return; // Ignore - this message is not for us
119
103
  }
120
-
121
104
  if (typeof message[0] !== "number" || MSGTYPES.indexOf(message[0]) < 0) {
122
105
  throw new Error("Invalid messageID");
123
106
  }
124
-
125
107
  const type = message[0];
126
-
127
108
  if (typeof message[1] !== "number") {
128
109
  throw new Error("Invalid messageID");
129
110
  }
130
-
131
111
  const messageID = message[1];
132
-
133
112
  if (type === MSGTYPE_QUERY) {
134
113
  const query = message[2];
135
-
136
114
  if (typeof message[3] !== "number" && message[3] !== undefined) {
137
115
  throw new Error("Invalid hostID");
138
116
  }
139
-
140
117
  const hostID = message[3];
141
-
142
118
  this._handleQuery(messageID, query, hostID);
143
-
144
119
  return;
145
120
  }
146
-
147
121
  if (type === MSGTYPE_RESPONSE) {
148
122
  if (message[2] !== null && typeof message[2] !== "object") {
149
123
  throw new Error("Invalid error");
150
124
  }
151
-
152
125
  const error = message[2] === null ? null : fromFakeError(message[2]);
153
126
  const result = message[3];
154
-
155
127
  const callback = this._callbacks.get(messageID);
156
-
157
128
  if (callback === undefined) {
158
129
  // Ignore - user might have created multiple PromiseWorkers.
159
130
  // This message is not for us.
160
131
  return;
161
132
  }
162
-
163
133
  this._callbacks.delete(messageID);
164
-
165
134
  callback(error, result);
166
135
  return;
167
136
  }
168
-
169
137
  return {
170
138
  message,
171
139
  type
172
140
  };
173
141
  }
174
-
175
142
  }
176
-
177
143
  class PWBHost extends PWBBase {
178
144
  // Only defined on host
145
+
179
146
  constructor(worker) {
180
- super(); // The following if statement used to check `worker instanceof Worker` but I have recieved
147
+ super();
148
+
149
+ // The following if statement used to check `worker instanceof Worker` but I have recieved
181
150
  // reports that in some weird cases, Safari will inappropriately return false for that, even
182
151
  // in obvious cases like:
183
152
  //
@@ -187,21 +156,23 @@ class PWBHost extends PWBBase {
187
156
  //
188
157
  // So instead, let's do this test for worker.port which only exists on shared workers.
189
158
  // @ts-expect-error
190
-
191
159
  if (worker.port === undefined) {
192
- this._workerType = "Worker"; // @ts-expect-error
160
+ this._workerType = "Worker";
193
161
 
162
+ // @ts-expect-error
194
163
  worker.addEventListener("message", this._onMessage);
195
164
  } else {
196
- this._workerType = "SharedWorker"; // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
165
+ this._workerType = "SharedWorker";
197
166
 
198
- worker.port.addEventListener("message", this._onMessage); // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
167
+ // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
168
+ worker.port.addEventListener("message", this._onMessage);
169
+ // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
170
+ worker.port.start();
199
171
 
200
- worker.port.start(); // Handle tab close. This isn't perfect, but there is no perfect method
172
+ // Handle tab close. This isn't perfect, but there is no perfect method
201
173
  // http://stackoverflow.com/q/13662089/786644 and this should work like
202
174
  // 99% of the time. It is a memory leak if it fails, but for most use
203
175
  // cases, it shouldn't be noticeable.
204
-
205
176
  window.addEventListener("beforeunload", () => {
206
177
  // Prevent firing if we don't know hostID yet
207
178
  if (this._hostID !== undefined) {
@@ -209,22 +180,20 @@ class PWBHost extends PWBBase {
209
180
  }
210
181
  });
211
182
  }
212
-
213
183
  this._worker = worker;
214
184
  this._hostIDQueue = [];
215
185
  }
216
-
217
186
  registerError(cb) {
218
187
  // console.log('registerError', cb);
219
- this._errorCallback = cb; // Some browsers (Firefox) call onerror on every host, while others
220
- // (Chrome) do nothing. Let's disable that everywhere, for consistency.
188
+ this._errorCallback = cb;
221
189
 
190
+ // Some browsers (Firefox) call onerror on every host, while others
191
+ // (Chrome) do nothing. Let's disable that everywhere, for consistency.
222
192
  this._worker.addEventListener("error", e => {
223
193
  e.preventDefault();
224
194
  e.stopPropagation();
225
195
  });
226
196
  }
227
-
228
197
  _postMessage(obj, _hostID, transfer) {
229
198
  // console.log('_postMessage', obj, _hostID, transfer);
230
199
  if (this._workerType === "Worker") {
@@ -237,14 +206,12 @@ class PWBHost extends PWBBase {
237
206
  throw new Error("WTF");
238
207
  }
239
208
  }
240
-
241
209
  postMessage(userMessage, _hostID, transfer) {
242
210
  // console.log('postMessage', userMessage, _hostID, transfer);
243
211
  const actuallyPostMessage = (resolve, reject) => {
244
212
  const messageID = messageIDs;
245
213
  messageIDs += 1;
246
214
  const messageToSend = [MSGTYPE_QUERY, messageID, userMessage, this._hostID];
247
-
248
215
  this._callbacks.set(messageID, (error, result) => {
249
216
  if (error) {
250
217
  reject(error);
@@ -252,10 +219,8 @@ class PWBHost extends PWBBase {
252
219
  resolve(result);
253
220
  }
254
221
  });
255
-
256
222
  this._postMessage(messageToSend, undefined, transfer);
257
223
  };
258
-
259
224
  return new Promise((resolve, reject) => {
260
225
  // Don't send a message until hostID is known, otherwise it's a race
261
226
  // condition and sometimes hostID will be undefined.
@@ -268,25 +233,19 @@ class PWBHost extends PWBBase {
268
233
  }
269
234
  });
270
235
  }
271
-
272
236
  _onMessage(e) {
273
237
  const common = this._onMessageCommon(e);
274
-
275
238
  if (!common) {
276
239
  return;
277
240
  }
278
-
279
241
  const message = common.message,
280
- type = common.type;
281
-
242
+ type = common.type;
282
243
  if (type === MSGTYPE_HOST_ID) {
283
244
  if (message[2] !== undefined && typeof message[2] !== "number") {
284
245
  throw new Error("Invalid hostID");
285
246
  }
286
-
287
247
  const hostID = message[2];
288
248
  this._hostID = hostID;
289
-
290
249
  if (this._hostIDQueue !== undefined) {
291
250
  this._hostIDQueue.forEach(func => {
292
251
  // Not entirely sure why setTimeout is needed, might be just for unit tests
@@ -294,74 +253,68 @@ class PWBHost extends PWBBase {
294
253
  func();
295
254
  }, 0);
296
255
  });
297
-
298
256
  this._hostIDQueue = undefined; // Never needed again after initial setup
299
257
  }
300
258
  } else if (type === MSGTYPE_WORKER_ERROR) {
301
259
  if (message[2] !== undefined && message[2] !== null && typeof message[2] === "object") {
302
260
  const error = fromFakeError(message[2]);
303
-
304
261
  if (this._errorCallback !== undefined) {
305
262
  this._errorCallback(error);
306
263
  }
307
264
  }
308
265
  }
309
266
  }
310
-
311
267
  }
312
-
313
268
  class PWBWorker extends PWBBase {
314
269
  constructor() {
315
- super(); // Only actually used for SharedWorker
270
+ super();
316
271
 
272
+ // Only actually used for SharedWorker
317
273
  this._hosts = new Map();
318
274
  this._maxHostID = -1;
319
-
320
- if ( // @ts-expect-error
321
- typeof SharedWorkerGlobalScope !== "undefined" && // @ts-expect-error
275
+ if (
276
+ // @ts-expect-error
277
+ typeof SharedWorkerGlobalScope !== "undefined" &&
278
+ // @ts-expect-error
322
279
  self instanceof SharedWorkerGlobalScope) {
323
280
  this._workerType = "SharedWorker";
324
281
  self.addEventListener("connect", e => {
325
282
  // @ts-expect-error
326
283
  const port = e.ports[0];
327
- port.addEventListener("message", e2 => this._onMessage(e2)); // eslint-disable-line no-undef
328
-
284
+ port.addEventListener("message", e2 => this._onMessage(e2));
329
285
  port.start();
330
286
  this._maxHostID += 1;
331
287
  const hostID = this._maxHostID;
332
-
333
288
  this._hosts.set(hostID, {
334
289
  port
335
- }); // Send back hostID to this host, otherwise it has no way to know it
336
-
290
+ });
337
291
 
292
+ // Send back hostID to this host, otherwise it has no way to know it
338
293
  this._postMessage([MSGTYPE_HOST_ID, -1, hostID], hostID);
339
294
  });
340
295
  self.addEventListener("error", e => {
341
- logError(e.error); // Just send to first host, so as to not duplicate error tracking
296
+ logError(e.error);
342
297
 
298
+ // Just send to first host, so as to not duplicate error tracking
343
299
  const hostID = this._hosts.keys().next().value;
344
-
345
300
  if (hostID !== undefined) {
346
301
  this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)], hostID);
347
302
  }
348
303
  });
349
304
  } else {
350
305
  this._workerType = "Worker";
351
- self.addEventListener("message", this._onMessage); // Since this is not a Shared Worker, hostID is always 0 so it's not strictly required to
306
+ self.addEventListener("message", this._onMessage);
307
+
308
+ // Since this is not a Shared Worker, hostID is always 0 so it's not strictly required to
352
309
  // send this back, but it makes the API a bit more consistent if there is the same
353
310
  // initialization handshake in both cases.
354
-
355
311
  this._postMessage([MSGTYPE_HOST_ID, -1, 0], 0);
356
-
357
312
  self.addEventListener("error", e => {
358
313
  logError(e.error);
359
-
360
314
  this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)]);
361
315
  });
362
316
  }
363
317
  }
364
-
365
318
  _postMessage(obj, targetHostID, transfer) {
366
319
  // console.log('_postMessage', obj, targetHostID);
367
320
  if (this._workerType === "SharedWorker") {
@@ -381,14 +334,12 @@ class PWBWorker extends PWBBase {
381
334
  throw new Error("WTF");
382
335
  }
383
336
  }
384
-
385
337
  postMessage(userMessage, targetHostID, transfer) {
386
338
  // console.log('postMessage', userMessage, targetHostID);
387
339
  const actuallyPostMessage = (resolve, reject) => {
388
340
  const messageID = messageIDs;
389
341
  messageIDs += 1;
390
342
  const messageToSend = [MSGTYPE_QUERY, messageID, userMessage];
391
-
392
343
  this._callbacks.set(messageID, (error, result) => {
393
344
  if (error) {
394
345
  reject(error);
@@ -396,36 +347,27 @@ class PWBWorker extends PWBBase {
396
347
  resolve(result);
397
348
  }
398
349
  });
399
-
400
350
  this._postMessage(messageToSend, targetHostID, transfer);
401
351
  };
402
-
403
352
  return new Promise((resolve, reject) => {
404
353
  actuallyPostMessage(resolve, reject);
405
354
  });
406
355
  }
407
-
408
356
  _onMessage(e) {
409
357
  const common = this._onMessageCommon(e);
410
-
411
358
  if (!common) {
412
359
  return;
413
360
  }
414
-
415
361
  const message = common.message,
416
- type = common.type;
417
-
362
+ type = common.type;
418
363
  if (type === MSGTYPE_HOST_CLOSE) {
419
364
  if (typeof message[2] !== "number") {
420
365
  throw new Error("Invalid hostID");
421
366
  }
422
-
423
367
  const hostID = message[2];
424
-
425
368
  this._hosts.delete(hostID);
426
369
  }
427
370
  }
428
-
429
371
  }
430
372
 
431
373
  export { PWBHost, PWBWorker };
package/package.json CHANGED
@@ -1,75 +1,76 @@
1
1
  {
2
- "name": "promise-worker-bi",
3
- "version": "4.1.1",
4
- "description": "Promise-based messaging for Web Workers and Shared Workers",
5
- "main": "./dist/commonjs.js",
6
- "types": "./dist/index.d.ts",
7
- "exports": {
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/esmodules.mjs",
11
- "require": "./dist/commonjs.js"
12
- }
13
- },
14
- "scripts": {
15
- "prepublish": "yarn run build",
16
- "build": "rm -rf dist && rollup -c && yarn run tsc",
17
- "build-test": "yarn run build && node scripts/build-test.js",
18
- "lint": "eslint src/*.ts test/*.js scripts/*.js",
19
- "prettier": "prettier --write 'src/*.ts' && prettier --write 'test/*.js' && prettier --write 'scripts/*.js'",
20
- "karma": "yarn run build-test && karma start",
21
- "test": "yarn run tsc && yarn run lint && yarn run karma",
22
- "prepare": "husky install"
23
- },
24
- "repository": {
25
- "type": "git",
26
- "url": "git+https://github.com/dumbmatter/promise-worker-bi.git"
27
- },
28
- "keywords": [
29
- "promise",
30
- "shared worker",
31
- "sharedworker",
32
- "web worker",
33
- "webworker",
34
- "worker"
35
- ],
36
- "author": "Jeremy Scheff <jdscheff@gmail.com>",
37
- "license": "Apache-2.0",
38
- "bugs": {
39
- "url": "https://github.com/dumbmatter/promise-worker-bi/issues"
40
- },
41
- "homepage": "https://github.com/dumbmatter/promise-worker-bi",
42
- "devDependencies": {
43
- "@babel/core": "^7.19.3",
44
- "@babel/plugin-transform-destructuring": "^7.18.13",
45
- "@babel/preset-typescript": "^7.18.6",
46
- "@typescript-eslint/eslint-plugin": "^5.39.0",
47
- "@typescript-eslint/parser": "^5.39.0",
48
- "eslint": "^8.25.0",
49
- "eslint-config-airbnb-base": "^15.0.0",
50
- "eslint-config-prettier": "^8.5.0",
51
- "eslint-plugin-import": "^2.26.0",
52
- "glob": "^8.0.3",
53
- "husky": "^8.0.0",
54
- "karma": "^6.4.1",
55
- "karma-chrome-launcher": "^3.1.1",
56
- "karma-firefox-launcher": "^2.1.2",
57
- "karma-mocha": "^2.0.1",
58
- "karma-mocha-reporter": "^2.2.5",
59
- "lint-staged": "^13.0.3",
60
- "mocha": "^10.0.0",
61
- "prettier": "^2.7.1",
62
- "rollup": "^2.79.1",
63
- "rollup-plugin-babel": "^4.4.0",
64
- "rollup-plugin-node-builtins": "^2.1.2",
65
- "rollup-plugin-node-globals": "^1.4.0",
66
- "rollup-plugin-node-resolve": "^5.2.0",
67
- "typescript": "^4.8.4"
68
- },
69
- "files": [
70
- "dist"
71
- ],
72
- "lint-staged": {
73
- "*.{cjs,js,jsx,mjs,ts,tsx,json,css,md}": "prettier --write"
74
- }
2
+ "name": "promise-worker-bi",
3
+ "version": "5.0.0",
4
+ "description": "Promise-based messaging for Web Workers and Shared Workers",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "type": "module",
14
+ "scripts": {
15
+ "prepublish": "node --run build",
16
+ "build": "rm -rf dist && rollup -c && tsc --emitDeclarationOnly",
17
+ "build-test": "node --run build && node scripts/build-test.js",
18
+ "lint": "eslint .",
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",
22
+ "prepare": "husky"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/dumbmatter/promise-worker-bi.git"
27
+ },
28
+ "keywords": [
29
+ "promise",
30
+ "shared worker",
31
+ "sharedworker",
32
+ "web worker",
33
+ "webworker",
34
+ "worker"
35
+ ],
36
+ "author": "Jeremy Scheff <jdscheff@gmail.com>",
37
+ "license": "Apache-2.0",
38
+ "bugs": {
39
+ "url": "https://github.com/dumbmatter/promise-worker-bi/issues"
40
+ },
41
+ "homepage": "https://github.com/dumbmatter/promise-worker-bi",
42
+ "devDependencies": {
43
+ "@babel/core": "^7.19.3",
44
+ "@babel/plugin-transform-destructuring": "^7.18.13",
45
+ "@babel/preset-typescript": "^7.18.6",
46
+ "@eslint/js": "^9.25.1",
47
+ "@rollup/plugin-babel": "^6.0.4",
48
+ "@rollup/plugin-node-resolve": "^16.0.1",
49
+ "@typescript-eslint/eslint-plugin": "^8.31.1",
50
+ "@typescript-eslint/parser": "^8.31.1",
51
+ "eslint": "^9.25.1",
52
+ "eslint-plugin-import-x": "^4.11.0",
53
+ "globals": "^16.0.0",
54
+ "husky": "^9.1.7",
55
+ "karma": "^6.4.1",
56
+ "karma-chrome-launcher": "^3.1.1",
57
+ "karma-firefox-launcher": "^2.1.2",
58
+ "karma-mocha": "^2.0.1",
59
+ "karma-mocha-reporter": "^2.2.5",
60
+ "lint-staged": "^15.5.1",
61
+ "mocha": "^11.2.2",
62
+ "prettier": "^3.5.3",
63
+ "rollup": "^4.40.1",
64
+ "rollup-plugin-node-builtins": "^2.1.2",
65
+ "rollup-plugin-node-globals": "^1.4.0",
66
+ "tinyglobby": "^0.2.13",
67
+ "typescript": "^5.8.3",
68
+ "typescript-eslint": "^8.31.1"
69
+ },
70
+ "files": [
71
+ "dist"
72
+ ],
73
+ "lint-staged": {
74
+ "*.{js,cjs,mjs,jsx,json,scss,ts,cts,mts,tsx}": "prettier --write"
75
+ }
75
76
  }
package/dist/commonjs.js DELETED
@@ -1,436 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- let messageIDs = 0;
6
- const MSGTYPE_QUERY = 0;
7
- const MSGTYPE_RESPONSE = 1;
8
- const MSGTYPE_HOST_ID = 2;
9
- const MSGTYPE_HOST_CLOSE = 3;
10
- const MSGTYPE_WORKER_ERROR = 4;
11
- const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID, MSGTYPE_HOST_CLOSE, MSGTYPE_WORKER_ERROR]; // Inlined from https://github.com/then/is-promise
12
-
13
- const isPromise = obj => !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
14
-
15
- const toFakeError = error => {
16
- const fakeError = {
17
- name: error.name,
18
- message: error.message
19
- };
20
-
21
- if (typeof error.stack === "string") {
22
- fakeError.stack = error.stack;
23
- } // These are non-standard properties, I think only in some versions of Firefox
24
- // @ts-expect-error
25
-
26
-
27
- if (typeof error.fileName === "string") {
28
- // @ts-expect-error
29
- fakeError.fileName = error.fileName;
30
- } // @ts-expect-error
31
-
32
-
33
- if (typeof error.columnNumber === "number") {
34
- // @ts-expect-error
35
- fakeError.columnNumber = error.columnNumber;
36
- } // @ts-expect-error
37
-
38
-
39
- if (typeof error.lineNumber === "number") {
40
- // @ts-expect-error
41
- fakeError.lineNumber = error.lineNumber;
42
- }
43
-
44
- return fakeError;
45
- }; // Object rather than FakeError for convenience
46
-
47
-
48
- const fromFakeError = fakeError => {
49
- const error = new Error();
50
- return Object.assign(error, fakeError);
51
- };
52
-
53
- const logError = err => {
54
- // Logging in the console makes debugging in the worker easier
55
-
56
- /* eslint-disable no-console */
57
- console.error("Error in Worker:");
58
- console.error(err); // Safari needs it on new line
59
-
60
- /* eslint-enable no-console */
61
- };
62
-
63
- class PWBBase {
64
- constructor() {
65
- // console.log('constructor', worker);
66
- this._callbacks = new Map(); // eslint-disable-next-line @typescript-eslint/no-empty-function
67
-
68
- this._queryCallback = () => {}; // @ts-expect-error
69
-
70
-
71
- this._onMessage = this._onMessage.bind(this);
72
- }
73
-
74
- register(cb) {
75
- // console.log('register', cb);
76
- this._queryCallback = cb;
77
- } // From worker, 2nd param could be hostID if sending to specific host. From UI, 2nd param could be an array of transferable objects
78
-
79
-
80
- _postResponse(messageID, error, result, hostID) {
81
- // console.log('_postResponse', messageID, error, result);
82
- if (error) {
83
- logError(error);
84
-
85
- this._postMessage([MSGTYPE_RESPONSE, messageID, toFakeError(error)], hostID);
86
- } else {
87
- // Hackily identify when message contains transferable objects
88
- if (typeof result === "object" && result !== null && result.hasOwnProperty("message") && result.hasOwnProperty("_PWB_TRANSFER")) {
89
- this._postMessage([MSGTYPE_RESPONSE, messageID, null, result.message], hostID, result._PWB_TRANSFER);
90
- } else {
91
- this._postMessage([MSGTYPE_RESPONSE, messageID, null, result], hostID);
92
- }
93
- }
94
- }
95
-
96
- _handleQuery(messageID, query, hostID) {
97
- // console.log('_handleQuery', messageID, query);
98
- try {
99
- const result = this._queryCallback(query, hostID);
100
-
101
- if (!isPromise(result)) {
102
- this._postResponse(messageID, null, result, hostID);
103
- } else {
104
- result.then(finalResult => {
105
- this._postResponse(messageID, null, finalResult, hostID);
106
- }, finalError => {
107
- this._postResponse(messageID, finalError, hostID);
108
- });
109
- }
110
- } catch (err) {
111
- this._postResponse(messageID, err);
112
- }
113
- } // Either return messageID and type if further processing is needed, or undefined otherwise
114
-
115
-
116
- _onMessageCommon(e) {
117
- // eslint-disable-line no-undef
118
- // console.log('_onMessage', e.data);
119
- const message = e.data;
120
-
121
- if (!Array.isArray(message) || message.length < 3 || message.length > 4) {
122
- return; // Ignore - this message is not for us
123
- }
124
-
125
- if (typeof message[0] !== "number" || MSGTYPES.indexOf(message[0]) < 0) {
126
- throw new Error("Invalid messageID");
127
- }
128
-
129
- const type = message[0];
130
-
131
- if (typeof message[1] !== "number") {
132
- throw new Error("Invalid messageID");
133
- }
134
-
135
- const messageID = message[1];
136
-
137
- if (type === MSGTYPE_QUERY) {
138
- const query = message[2];
139
-
140
- if (typeof message[3] !== "number" && message[3] !== undefined) {
141
- throw new Error("Invalid hostID");
142
- }
143
-
144
- const hostID = message[3];
145
-
146
- this._handleQuery(messageID, query, hostID);
147
-
148
- return;
149
- }
150
-
151
- if (type === MSGTYPE_RESPONSE) {
152
- if (message[2] !== null && typeof message[2] !== "object") {
153
- throw new Error("Invalid error");
154
- }
155
-
156
- const error = message[2] === null ? null : fromFakeError(message[2]);
157
- const result = message[3];
158
-
159
- const callback = this._callbacks.get(messageID);
160
-
161
- if (callback === undefined) {
162
- // Ignore - user might have created multiple PromiseWorkers.
163
- // This message is not for us.
164
- return;
165
- }
166
-
167
- this._callbacks.delete(messageID);
168
-
169
- callback(error, result);
170
- return;
171
- }
172
-
173
- return {
174
- message,
175
- type
176
- };
177
- }
178
-
179
- }
180
-
181
- class PWBHost extends PWBBase {
182
- // Only defined on host
183
- constructor(worker) {
184
- super(); // The following if statement used to check `worker instanceof Worker` but I have recieved
185
- // reports that in some weird cases, Safari will inappropriately return false for that, even
186
- // in obvious cases like:
187
- //
188
- // blob = new Blob(["self.onmessage = function() {};"], { type: "text/javascript" });
189
- // worker = new Worker(window.URL.createObjectURL(blob));
190
- // console.log(worker instanceof Worker);
191
- //
192
- // So instead, let's do this test for worker.port which only exists on shared workers.
193
- // @ts-expect-error
194
-
195
- if (worker.port === undefined) {
196
- this._workerType = "Worker"; // @ts-expect-error
197
-
198
- worker.addEventListener("message", this._onMessage);
199
- } else {
200
- this._workerType = "SharedWorker"; // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
201
-
202
- worker.port.addEventListener("message", this._onMessage); // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
203
-
204
- worker.port.start(); // Handle tab close. This isn't perfect, but there is no perfect method
205
- // http://stackoverflow.com/q/13662089/786644 and this should work like
206
- // 99% of the time. It is a memory leak if it fails, but for most use
207
- // cases, it shouldn't be noticeable.
208
-
209
- window.addEventListener("beforeunload", () => {
210
- // Prevent firing if we don't know hostID yet
211
- if (this._hostID !== undefined) {
212
- this._postMessage([MSGTYPE_HOST_CLOSE, -1, this._hostID]);
213
- }
214
- });
215
- }
216
-
217
- this._worker = worker;
218
- this._hostIDQueue = [];
219
- }
220
-
221
- registerError(cb) {
222
- // console.log('registerError', cb);
223
- this._errorCallback = cb; // Some browsers (Firefox) call onerror on every host, while others
224
- // (Chrome) do nothing. Let's disable that everywhere, for consistency.
225
-
226
- this._worker.addEventListener("error", e => {
227
- e.preventDefault();
228
- e.stopPropagation();
229
- });
230
- }
231
-
232
- _postMessage(obj, _hostID, transfer) {
233
- // console.log('_postMessage', obj, _hostID, transfer);
234
- if (this._workerType === "Worker") {
235
- // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
236
- this._worker.postMessage(obj, transfer);
237
- } else if (this._workerType === "SharedWorker") {
238
- // @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
239
- this._worker.port.postMessage(obj, transfer);
240
- } else {
241
- throw new Error("WTF");
242
- }
243
- }
244
-
245
- postMessage(userMessage, _hostID, transfer) {
246
- // console.log('postMessage', userMessage, _hostID, transfer);
247
- const actuallyPostMessage = (resolve, reject) => {
248
- const messageID = messageIDs;
249
- messageIDs += 1;
250
- const messageToSend = [MSGTYPE_QUERY, messageID, userMessage, this._hostID];
251
-
252
- this._callbacks.set(messageID, (error, result) => {
253
- if (error) {
254
- reject(error);
255
- } else {
256
- resolve(result);
257
- }
258
- });
259
-
260
- this._postMessage(messageToSend, undefined, transfer);
261
- };
262
-
263
- return new Promise((resolve, reject) => {
264
- // Don't send a message until hostID is known, otherwise it's a race
265
- // condition and sometimes hostID will be undefined.
266
- if (this._hostIDQueue !== undefined) {
267
- this._hostIDQueue.push(() => {
268
- actuallyPostMessage(resolve, reject);
269
- });
270
- } else {
271
- actuallyPostMessage(resolve, reject);
272
- }
273
- });
274
- }
275
-
276
- _onMessage(e) {
277
- const common = this._onMessageCommon(e);
278
-
279
- if (!common) {
280
- return;
281
- }
282
-
283
- const message = common.message,
284
- type = common.type;
285
-
286
- if (type === MSGTYPE_HOST_ID) {
287
- if (message[2] !== undefined && typeof message[2] !== "number") {
288
- throw new Error("Invalid hostID");
289
- }
290
-
291
- const hostID = message[2];
292
- this._hostID = hostID;
293
-
294
- if (this._hostIDQueue !== undefined) {
295
- this._hostIDQueue.forEach(func => {
296
- // Not entirely sure why setTimeout is needed, might be just for unit tests
297
- setTimeout(() => {
298
- func();
299
- }, 0);
300
- });
301
-
302
- this._hostIDQueue = undefined; // Never needed again after initial setup
303
- }
304
- } else if (type === MSGTYPE_WORKER_ERROR) {
305
- if (message[2] !== undefined && message[2] !== null && typeof message[2] === "object") {
306
- const error = fromFakeError(message[2]);
307
-
308
- if (this._errorCallback !== undefined) {
309
- this._errorCallback(error);
310
- }
311
- }
312
- }
313
- }
314
-
315
- }
316
-
317
- class PWBWorker extends PWBBase {
318
- constructor() {
319
- super(); // Only actually used for SharedWorker
320
-
321
- this._hosts = new Map();
322
- this._maxHostID = -1;
323
-
324
- if ( // @ts-expect-error
325
- typeof SharedWorkerGlobalScope !== "undefined" && // @ts-expect-error
326
- self instanceof SharedWorkerGlobalScope) {
327
- this._workerType = "SharedWorker";
328
- self.addEventListener("connect", e => {
329
- // @ts-expect-error
330
- const port = e.ports[0];
331
- port.addEventListener("message", e2 => this._onMessage(e2)); // eslint-disable-line no-undef
332
-
333
- port.start();
334
- this._maxHostID += 1;
335
- const hostID = this._maxHostID;
336
-
337
- this._hosts.set(hostID, {
338
- port
339
- }); // Send back hostID to this host, otherwise it has no way to know it
340
-
341
-
342
- this._postMessage([MSGTYPE_HOST_ID, -1, hostID], hostID);
343
- });
344
- self.addEventListener("error", e => {
345
- logError(e.error); // Just send to first host, so as to not duplicate error tracking
346
-
347
- const hostID = this._hosts.keys().next().value;
348
-
349
- if (hostID !== undefined) {
350
- this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)], hostID);
351
- }
352
- });
353
- } else {
354
- this._workerType = "Worker";
355
- self.addEventListener("message", this._onMessage); // Since this is not a Shared Worker, hostID is always 0 so it's not strictly required to
356
- // send this back, but it makes the API a bit more consistent if there is the same
357
- // initialization handshake in both cases.
358
-
359
- this._postMessage([MSGTYPE_HOST_ID, -1, 0], 0);
360
-
361
- self.addEventListener("error", e => {
362
- logError(e.error);
363
-
364
- this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)]);
365
- });
366
- }
367
- }
368
-
369
- _postMessage(obj, targetHostID, transfer) {
370
- // console.log('_postMessage', obj, targetHostID);
371
- if (this._workerType === "SharedWorker") {
372
- // If targetHostID has been deleted, this will do nothing, which is fine I think
373
- this._hosts.forEach(({
374
- port
375
- }, hostID) => {
376
- if (targetHostID === undefined || targetHostID === hostID) {
377
- // @ts-expect-error TypeScript thinks transfer can't be undefined
378
- port.postMessage(obj, transfer);
379
- }
380
- });
381
- } else if (this._workerType === "Worker") {
382
- // @ts-expect-error TypeScript thinks self is window, which has a different postMessage call signature. In a worker, this is correct.
383
- self.postMessage(obj, transfer);
384
- } else {
385
- throw new Error("WTF");
386
- }
387
- }
388
-
389
- postMessage(userMessage, targetHostID, transfer) {
390
- // console.log('postMessage', userMessage, targetHostID);
391
- const actuallyPostMessage = (resolve, reject) => {
392
- const messageID = messageIDs;
393
- messageIDs += 1;
394
- const messageToSend = [MSGTYPE_QUERY, messageID, userMessage];
395
-
396
- this._callbacks.set(messageID, (error, result) => {
397
- if (error) {
398
- reject(error);
399
- } else {
400
- resolve(result);
401
- }
402
- });
403
-
404
- this._postMessage(messageToSend, targetHostID, transfer);
405
- };
406
-
407
- return new Promise((resolve, reject) => {
408
- actuallyPostMessage(resolve, reject);
409
- });
410
- }
411
-
412
- _onMessage(e) {
413
- const common = this._onMessageCommon(e);
414
-
415
- if (!common) {
416
- return;
417
- }
418
-
419
- const message = common.message,
420
- type = common.type;
421
-
422
- if (type === MSGTYPE_HOST_CLOSE) {
423
- if (typeof message[2] !== "number") {
424
- throw new Error("Invalid hostID");
425
- }
426
-
427
- const hostID = message[2];
428
-
429
- this._hosts.delete(hostID);
430
- }
431
- }
432
-
433
- }
434
-
435
- exports.PWBHost = PWBHost;
436
- exports.PWBWorker = PWBWorker;