@loaders.gl/worker-utils 4.0.0-beta.2 → 4.0.0-beta.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.
Files changed (141) hide show
  1. package/dist/index.cjs +989 -0
  2. package/dist/index.js +26 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/{esm/lib → lib}/async-queue/async-queue.js +3 -4
  5. package/dist/lib/async-queue/async-queue.js.map +1 -0
  6. package/dist/lib/env-utils/assert.js.map +1 -0
  7. package/dist/lib/env-utils/globals.js.map +1 -0
  8. package/dist/{esm/lib → lib}/env-utils/version.js +2 -2
  9. package/dist/lib/env-utils/version.js.map +1 -0
  10. package/dist/{esm/lib → lib}/library-utils/library-utils.js +10 -9
  11. package/dist/lib/library-utils/library-utils.js.map +1 -0
  12. package/dist/lib/node/require-utils.node.d.ts.map +1 -1
  13. package/dist/{esm/lib → lib}/node/require-utils.node.js +6 -5
  14. package/dist/lib/node/require-utils.node.js.map +1 -0
  15. package/dist/lib/node/worker_threads-browser.d.ts.map +1 -1
  16. package/dist/lib/node/worker_threads-browser.js.map +1 -0
  17. package/dist/lib/node/worker_threads.js.map +1 -0
  18. package/dist/{esm/lib → lib}/process-utils/child-process-proxy.js +12 -13
  19. package/dist/lib/process-utils/child-process-proxy.js.map +1 -0
  20. package/dist/lib/process-utils/process-utils.js.map +1 -0
  21. package/dist/{esm/lib → lib}/worker-api/create-worker.js +2 -2
  22. package/dist/lib/worker-api/create-worker.js.map +1 -0
  23. package/dist/lib/worker-api/get-worker-url.js +30 -0
  24. package/dist/lib/worker-api/get-worker-url.js.map +1 -0
  25. package/dist/{esm/lib → lib}/worker-api/process-on-worker.js +4 -4
  26. package/dist/lib/worker-api/process-on-worker.js.map +1 -0
  27. package/dist/{esm/lib → lib}/worker-api/validate-worker-version.js +2 -2
  28. package/dist/lib/worker-api/validate-worker-version.js.map +1 -0
  29. package/dist/{esm/lib → lib}/worker-farm/worker-body.js +1 -1
  30. package/dist/lib/worker-farm/worker-body.js.map +1 -0
  31. package/dist/{esm/lib → lib}/worker-farm/worker-farm.js +5 -6
  32. package/dist/lib/worker-farm/worker-farm.js.map +1 -0
  33. package/dist/{esm/lib → lib}/worker-farm/worker-job.js +7 -8
  34. package/dist/lib/worker-farm/worker-job.js.map +1 -0
  35. package/dist/lib/worker-farm/worker-pool.d.ts.map +1 -1
  36. package/dist/{esm/lib → lib}/worker-farm/worker-pool.js +18 -17
  37. package/dist/lib/worker-farm/worker-pool.js.map +1 -0
  38. package/dist/{esm/lib → lib}/worker-farm/worker-thread.js +17 -18
  39. package/dist/lib/worker-farm/worker-thread.js.map +1 -0
  40. package/dist/{esm/lib → lib}/worker-utils/get-loadable-worker-url.js +8 -2
  41. package/dist/lib/worker-utils/get-loadable-worker-url.js.map +1 -0
  42. package/dist/lib/worker-utils/get-transfer-list.js.map +1 -0
  43. package/dist/lib/worker-utils/remove-nontransferable-options.js.map +1 -0
  44. package/dist/null-worker-node.js +22 -2
  45. package/dist/null-worker-node.js.map +2 -2
  46. package/dist/null-worker.js +24 -2
  47. package/dist/null-worker.js.map +2 -2
  48. package/dist/types.js.map +1 -0
  49. package/dist/workers/null-worker.js +5 -0
  50. package/dist/workers/null-worker.js.map +1 -0
  51. package/package.json +12 -6
  52. package/src/lib/library-utils/library-utils.ts +8 -1
  53. package/src/lib/node/require-utils.node.ts +4 -2
  54. package/src/lib/node/worker_threads-browser.ts +0 -1
  55. package/src/lib/worker-farm/worker-pool.ts +3 -0
  56. package/dist/es5/index.js +0 -148
  57. package/dist/es5/index.js.map +0 -1
  58. package/dist/es5/lib/async-queue/async-queue.js +0 -100
  59. package/dist/es5/lib/async-queue/async-queue.js.map +0 -1
  60. package/dist/es5/lib/env-utils/assert.js +0 -12
  61. package/dist/es5/lib/env-utils/assert.js.map +0 -1
  62. package/dist/es5/lib/env-utils/globals.js +0 -32
  63. package/dist/es5/lib/env-utils/globals.js.map +0 -1
  64. package/dist/es5/lib/env-utils/version.js +0 -24
  65. package/dist/es5/lib/env-utils/version.js.map +0 -1
  66. package/dist/es5/lib/library-utils/library-utils.js +0 -217
  67. package/dist/es5/lib/library-utils/library-utils.js.map +0 -1
  68. package/dist/es5/lib/node/require-utils.node.js +0 -138
  69. package/dist/es5/lib/node/require-utils.node.js.map +0 -1
  70. package/dist/es5/lib/node/worker_threads-browser.js +0 -23
  71. package/dist/es5/lib/node/worker_threads-browser.js.map +0 -1
  72. package/dist/es5/lib/node/worker_threads.js +0 -27
  73. package/dist/es5/lib/node/worker_threads.js.map +0 -1
  74. package/dist/es5/lib/process-utils/child-process-proxy.js +0 -195
  75. package/dist/es5/lib/process-utils/child-process-proxy.js.map +0 -1
  76. package/dist/es5/lib/process-utils/process-utils.js +0 -33
  77. package/dist/es5/lib/process-utils/process-utils.js.map +0 -1
  78. package/dist/es5/lib/worker-api/create-worker.js +0 -166
  79. package/dist/es5/lib/worker-api/create-worker.js.map +0 -1
  80. package/dist/es5/lib/worker-api/get-worker-url.js +0 -37
  81. package/dist/es5/lib/worker-api/get-worker-url.js.map +0 -1
  82. package/dist/es5/lib/worker-api/process-on-worker.js +0 -137
  83. package/dist/es5/lib/worker-api/process-on-worker.js.map +0 -1
  84. package/dist/es5/lib/worker-api/validate-worker-version.js +0 -25
  85. package/dist/es5/lib/worker-api/validate-worker-version.js.map +0 -1
  86. package/dist/es5/lib/worker-farm/worker-body.js +0 -109
  87. package/dist/es5/lib/worker-farm/worker-body.js.map +0 -1
  88. package/dist/es5/lib/worker-farm/worker-farm.js +0 -113
  89. package/dist/es5/lib/worker-farm/worker-farm.js.map +0 -1
  90. package/dist/es5/lib/worker-farm/worker-job.js +0 -56
  91. package/dist/es5/lib/worker-farm/worker-job.js.map +0 -1
  92. package/dist/es5/lib/worker-farm/worker-pool.js +0 -211
  93. package/dist/es5/lib/worker-farm/worker-pool.js.map +0 -1
  94. package/dist/es5/lib/worker-farm/worker-thread.js +0 -136
  95. package/dist/es5/lib/worker-farm/worker-thread.js.map +0 -1
  96. package/dist/es5/lib/worker-utils/get-loadable-worker-url.js +0 -41
  97. package/dist/es5/lib/worker-utils/get-loadable-worker-url.js.map +0 -1
  98. package/dist/es5/lib/worker-utils/get-transfer-list.js +0 -59
  99. package/dist/es5/lib/worker-utils/get-transfer-list.js.map +0 -1
  100. package/dist/es5/lib/worker-utils/remove-nontransferable-options.js +0 -25
  101. package/dist/es5/lib/worker-utils/remove-nontransferable-options.js.map +0 -1
  102. package/dist/es5/types.js +0 -2
  103. package/dist/es5/types.js.map +0 -1
  104. package/dist/es5/workers/null-worker.js +0 -23
  105. package/dist/es5/workers/null-worker.js.map +0 -1
  106. package/dist/esm/index.js +0 -26
  107. package/dist/esm/index.js.map +0 -1
  108. package/dist/esm/lib/async-queue/async-queue.js.map +0 -1
  109. package/dist/esm/lib/env-utils/assert.js.map +0 -1
  110. package/dist/esm/lib/env-utils/globals.js.map +0 -1
  111. package/dist/esm/lib/env-utils/version.js.map +0 -1
  112. package/dist/esm/lib/library-utils/library-utils.js.map +0 -1
  113. package/dist/esm/lib/node/require-utils.node.js.map +0 -1
  114. package/dist/esm/lib/node/worker_threads-browser.js.map +0 -1
  115. package/dist/esm/lib/node/worker_threads.js.map +0 -1
  116. package/dist/esm/lib/process-utils/child-process-proxy.js.map +0 -1
  117. package/dist/esm/lib/process-utils/process-utils.js.map +0 -1
  118. package/dist/esm/lib/worker-api/create-worker.js.map +0 -1
  119. package/dist/esm/lib/worker-api/get-worker-url.js +0 -30
  120. package/dist/esm/lib/worker-api/get-worker-url.js.map +0 -1
  121. package/dist/esm/lib/worker-api/process-on-worker.js.map +0 -1
  122. package/dist/esm/lib/worker-api/validate-worker-version.js.map +0 -1
  123. package/dist/esm/lib/worker-farm/worker-body.js.map +0 -1
  124. package/dist/esm/lib/worker-farm/worker-farm.js.map +0 -1
  125. package/dist/esm/lib/worker-farm/worker-job.js.map +0 -1
  126. package/dist/esm/lib/worker-farm/worker-pool.js.map +0 -1
  127. package/dist/esm/lib/worker-farm/worker-thread.js.map +0 -1
  128. package/dist/esm/lib/worker-utils/get-loadable-worker-url.js.map +0 -1
  129. package/dist/esm/lib/worker-utils/get-transfer-list.js.map +0 -1
  130. package/dist/esm/lib/worker-utils/remove-nontransferable-options.js.map +0 -1
  131. package/dist/esm/types.js.map +0 -1
  132. package/dist/esm/workers/null-worker.js +0 -5
  133. package/dist/esm/workers/null-worker.js.map +0 -1
  134. /package/dist/{esm/lib → lib}/env-utils/assert.js +0 -0
  135. /package/dist/{esm/lib → lib}/env-utils/globals.js +0 -0
  136. /package/dist/{esm/lib → lib}/node/worker_threads-browser.js +0 -0
  137. /package/dist/{esm/lib → lib}/node/worker_threads.js +0 -0
  138. /package/dist/{esm/lib → lib}/process-utils/process-utils.js +0 -0
  139. /package/dist/{esm/lib → lib}/worker-utils/get-transfer-list.js +0 -0
  140. /package/dist/{esm/lib → lib}/worker-utils/remove-nontransferable-options.js +0 -0
  141. /package/dist/{esm/types.js → types.js} +0 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,989 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // (disabled):src/lib/node/require-utils.node
34
+ var require_require_utils = __commonJS({
35
+ "(disabled):src/lib/node/require-utils.node"() {
36
+ "use strict";
37
+ }
38
+ });
39
+
40
+ // (disabled):src/lib/process-utils/child-process-proxy
41
+ var require_child_process_proxy = __commonJS({
42
+ "(disabled):src/lib/process-utils/child-process-proxy"() {
43
+ "use strict";
44
+ }
45
+ });
46
+
47
+ // src/index.ts
48
+ var src_exports = {};
49
+ __export(src_exports, {
50
+ AsyncQueue: () => AsyncQueue,
51
+ ChildProcessProxy: () => import_child_process_proxy.default,
52
+ NullWorker: () => NullWorker,
53
+ WorkerBody: () => WorkerBody,
54
+ WorkerFarm: () => WorkerFarm,
55
+ WorkerJob: () => WorkerJob,
56
+ WorkerPool: () => WorkerPool,
57
+ WorkerThread: () => WorkerThread,
58
+ assert: () => assert,
59
+ canProcessOnWorker: () => canProcessOnWorker,
60
+ createWorker: () => createWorker,
61
+ getLibraryUrl: () => getLibraryUrl,
62
+ getTransferList: () => getTransferList,
63
+ getTransferListForWriter: () => getTransferListForWriter,
64
+ getWorkerURL: () => getWorkerURL,
65
+ isBrowser: () => isBrowser,
66
+ isWorker: () => isWorker,
67
+ loadLibrary: () => loadLibrary,
68
+ processOnWorker: () => processOnWorker,
69
+ validateWorkerVersion: () => validateWorkerVersion
70
+ });
71
+ module.exports = __toCommonJS(src_exports);
72
+
73
+ // src/lib/env-utils/version.ts
74
+ var NPM_TAG = "beta";
75
+ function getVersion() {
76
+ var _a;
77
+ if (!((_a = globalThis._loadersgl_) == null ? void 0 : _a.version)) {
78
+ globalThis._loadersgl_ = globalThis._loadersgl_ || {};
79
+ if (typeof __VERSION__ === "undefined") {
80
+ console.error(
81
+ "loaders.gl: The __VERSION__ variable is not injected using babel plugin. Latest unstable workers would be fetched from the CDN."
82
+ );
83
+ globalThis._loadersgl_.version = NPM_TAG;
84
+ } else {
85
+ globalThis._loadersgl_.version = __VERSION__;
86
+ }
87
+ }
88
+ return globalThis._loadersgl_.version;
89
+ }
90
+ var VERSION = getVersion();
91
+
92
+ // src/lib/env-utils/assert.ts
93
+ function assert(condition, message) {
94
+ if (!condition) {
95
+ throw new Error(message || "loaders.gl assertion failed.");
96
+ }
97
+ }
98
+
99
+ // src/lib/env-utils/globals.ts
100
+ var globals = {
101
+ self: typeof self !== "undefined" && self,
102
+ window: typeof window !== "undefined" && window,
103
+ global: typeof global !== "undefined" && global,
104
+ document: typeof document !== "undefined" && document
105
+ };
106
+ var self_ = globals.self || globals.window || globals.global || {};
107
+ var window_ = globals.window || globals.self || globals.global || {};
108
+ var global_ = globals.global || globals.self || globals.window || {};
109
+ var document_ = globals.document || {};
110
+ var isBrowser = (
111
+ // @ts-ignore process.browser
112
+ typeof process !== "object" || String(process) !== "[object process]" || process.browser
113
+ );
114
+ var isWorker = typeof importScripts === "function";
115
+ var isMobile = typeof window !== "undefined" && typeof window.orientation !== "undefined";
116
+ var matches = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version);
117
+ var nodeVersion = matches && parseFloat(matches[1]) || 0;
118
+
119
+ // src/lib/worker-farm/worker-job.ts
120
+ var WorkerJob = class {
121
+ constructor(jobName, workerThread) {
122
+ this.isRunning = true;
123
+ this._resolve = () => {
124
+ };
125
+ this._reject = () => {
126
+ };
127
+ this.name = jobName;
128
+ this.workerThread = workerThread;
129
+ this.result = new Promise((resolve, reject) => {
130
+ this._resolve = resolve;
131
+ this._reject = reject;
132
+ });
133
+ }
134
+ /**
135
+ * Send a message to the job's worker thread
136
+ * @param data any data structure, ideally consisting mostly of transferrable objects
137
+ */
138
+ postMessage(type, payload) {
139
+ this.workerThread.postMessage({
140
+ source: "loaders.gl",
141
+ // Lets worker ignore unrelated messages
142
+ type,
143
+ payload
144
+ });
145
+ }
146
+ /**
147
+ * Call to resolve the `result` Promise with the supplied value
148
+ */
149
+ done(value) {
150
+ assert(this.isRunning);
151
+ this.isRunning = false;
152
+ this._resolve(value);
153
+ }
154
+ /**
155
+ * Call to reject the `result` Promise with the supplied error
156
+ */
157
+ error(error) {
158
+ assert(this.isRunning);
159
+ this.isRunning = false;
160
+ this._reject(error);
161
+ }
162
+ };
163
+
164
+ // src/lib/node/worker_threads-browser.ts
165
+ var Worker2 = class {
166
+ terminate() {
167
+ }
168
+ };
169
+
170
+ // src/lib/worker-utils/get-loadable-worker-url.ts
171
+ var workerURLCache = /* @__PURE__ */ new Map();
172
+ function getLoadableWorkerURL(props) {
173
+ assert(props.source && !props.url || !props.source && props.url);
174
+ let workerURL = workerURLCache.get(props.source || props.url);
175
+ if (!workerURL) {
176
+ if (props.url) {
177
+ workerURL = getLoadableWorkerURLFromURL(props.url);
178
+ workerURLCache.set(props.url, workerURL);
179
+ }
180
+ if (props.source) {
181
+ workerURL = getLoadableWorkerURLFromSource(props.source);
182
+ workerURLCache.set(props.source, workerURL);
183
+ }
184
+ }
185
+ assert(workerURL);
186
+ return workerURL;
187
+ }
188
+ function getLoadableWorkerURLFromURL(url) {
189
+ if (!url.startsWith("http")) {
190
+ return url;
191
+ }
192
+ const workerSource = buildScriptSource(url);
193
+ return getLoadableWorkerURLFromSource(workerSource);
194
+ }
195
+ function getLoadableWorkerURLFromSource(workerSource) {
196
+ const blob = new Blob([workerSource], { type: "application/javascript" });
197
+ return URL.createObjectURL(blob);
198
+ }
199
+ function buildScriptSource(workerUrl) {
200
+ return `try {
201
+ importScripts('${workerUrl}');
202
+ } catch (error) {
203
+ console.error(error);
204
+ throw error;
205
+ }`;
206
+ }
207
+
208
+ // src/lib/worker-utils/get-transfer-list.ts
209
+ function getTransferList(object, recursive = true, transfers) {
210
+ const transfersSet = transfers || /* @__PURE__ */ new Set();
211
+ if (!object) {
212
+ } else if (isTransferable(object)) {
213
+ transfersSet.add(object);
214
+ } else if (isTransferable(object.buffer)) {
215
+ transfersSet.add(object.buffer);
216
+ } else if (ArrayBuffer.isView(object)) {
217
+ } else if (recursive && typeof object === "object") {
218
+ for (const key in object) {
219
+ getTransferList(object[key], recursive, transfersSet);
220
+ }
221
+ }
222
+ return transfers === void 0 ? Array.from(transfersSet) : [];
223
+ }
224
+ function isTransferable(object) {
225
+ if (!object) {
226
+ return false;
227
+ }
228
+ if (object instanceof ArrayBuffer) {
229
+ return true;
230
+ }
231
+ if (typeof MessagePort !== "undefined" && object instanceof MessagePort) {
232
+ return true;
233
+ }
234
+ if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) {
235
+ return true;
236
+ }
237
+ if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) {
238
+ return true;
239
+ }
240
+ return false;
241
+ }
242
+ function getTransferListForWriter(object) {
243
+ if (object === null) {
244
+ return {};
245
+ }
246
+ const clone = Object.assign({}, object);
247
+ Object.keys(clone).forEach((key) => {
248
+ if (typeof object[key] === "object" && !ArrayBuffer.isView(object[key]) && !(object[key] instanceof Array)) {
249
+ clone[key] = getTransferListForWriter(object[key]);
250
+ } else if (typeof clone[key] === "function" || clone[key] instanceof RegExp) {
251
+ clone[key] = {};
252
+ } else {
253
+ clone[key] = object[key];
254
+ }
255
+ });
256
+ return clone;
257
+ }
258
+
259
+ // src/lib/worker-farm/worker-thread.ts
260
+ var NOOP = () => {
261
+ };
262
+ var WorkerThread = class {
263
+ constructor(props) {
264
+ this.terminated = false;
265
+ this._loadableURL = "";
266
+ const { name, source, url } = props;
267
+ assert(source || url);
268
+ this.name = name;
269
+ this.source = source;
270
+ this.url = url;
271
+ this.onMessage = NOOP;
272
+ this.onError = (error) => console.log(error);
273
+ this.worker = isBrowser ? this._createBrowserWorker() : this._createNodeWorker();
274
+ }
275
+ /** Checks if workers are supported on this platform */
276
+ static isSupported() {
277
+ return typeof Worker !== "undefined" && isBrowser || typeof Worker2 !== "undefined" && !isBrowser;
278
+ }
279
+ /**
280
+ * Terminate this worker thread
281
+ * @note Can free up significant memory
282
+ */
283
+ destroy() {
284
+ this.onMessage = NOOP;
285
+ this.onError = NOOP;
286
+ this.worker.terminate();
287
+ this.terminated = true;
288
+ }
289
+ get isRunning() {
290
+ return Boolean(this.onMessage);
291
+ }
292
+ /**
293
+ * Send a message to this worker thread
294
+ * @param data any data structure, ideally consisting mostly of transferrable objects
295
+ * @param transferList If not supplied, calculated automatically by traversing data
296
+ */
297
+ postMessage(data, transferList) {
298
+ transferList = transferList || getTransferList(data);
299
+ this.worker.postMessage(data, transferList);
300
+ }
301
+ // PRIVATE
302
+ /**
303
+ * Generate a standard Error from an ErrorEvent
304
+ * @param event
305
+ */
306
+ _getErrorFromErrorEvent(event) {
307
+ let message = "Failed to load ";
308
+ message += `worker ${this.name} from ${this.url}. `;
309
+ if (event.message) {
310
+ message += `${event.message} in `;
311
+ }
312
+ if (event.lineno) {
313
+ message += `:${event.lineno}:${event.colno}`;
314
+ }
315
+ return new Error(message);
316
+ }
317
+ /**
318
+ * Creates a worker thread on the browser
319
+ */
320
+ _createBrowserWorker() {
321
+ this._loadableURL = getLoadableWorkerURL({ source: this.source, url: this.url });
322
+ const worker = new Worker(this._loadableURL, { name: this.name });
323
+ worker.onmessage = (event) => {
324
+ if (!event.data) {
325
+ this.onError(new Error("No data received"));
326
+ } else {
327
+ this.onMessage(event.data);
328
+ }
329
+ };
330
+ worker.onerror = (error) => {
331
+ this.onError(this._getErrorFromErrorEvent(error));
332
+ this.terminated = true;
333
+ };
334
+ worker.onmessageerror = (event) => console.error(event);
335
+ return worker;
336
+ }
337
+ /**
338
+ * Creates a worker thread in node.js
339
+ * @todo https://nodejs.org/api/async_hooks.html#async-resource-worker-pool
340
+ */
341
+ _createNodeWorker() {
342
+ let worker;
343
+ if (this.url) {
344
+ const absolute = this.url.includes(":/") || this.url.startsWith("/");
345
+ const url = absolute ? this.url : `./${this.url}`;
346
+ worker = new Worker2(url, { eval: false });
347
+ } else if (this.source) {
348
+ worker = new Worker2(this.source, { eval: true });
349
+ } else {
350
+ throw new Error("no worker");
351
+ }
352
+ worker.on("message", (data) => {
353
+ this.onMessage(data);
354
+ });
355
+ worker.on("error", (error) => {
356
+ this.onError(error);
357
+ });
358
+ worker.on("exit", (code) => {
359
+ });
360
+ return worker;
361
+ }
362
+ };
363
+
364
+ // src/lib/worker-farm/worker-pool.ts
365
+ var WorkerPool = class {
366
+ /**
367
+ * @param processor - worker function
368
+ * @param maxConcurrency - max count of workers
369
+ */
370
+ constructor(props) {
371
+ this.name = "unnamed";
372
+ this.maxConcurrency = 1;
373
+ this.maxMobileConcurrency = 1;
374
+ this.onDebug = () => {
375
+ };
376
+ this.reuseWorkers = true;
377
+ this.props = {};
378
+ this.jobQueue = [];
379
+ this.idleQueue = [];
380
+ this.count = 0;
381
+ this.isDestroyed = false;
382
+ this.source = props.source;
383
+ this.url = props.url;
384
+ this.setProps(props);
385
+ }
386
+ /** Checks if workers are supported on this platform */
387
+ static isSupported() {
388
+ return WorkerThread.isSupported();
389
+ }
390
+ /**
391
+ * Terminates all workers in the pool
392
+ * @note Can free up significant memory
393
+ */
394
+ destroy() {
395
+ this.idleQueue.forEach((worker) => worker.destroy());
396
+ this.isDestroyed = true;
397
+ }
398
+ setProps(props) {
399
+ this.props = { ...this.props, ...props };
400
+ if (props.name !== void 0) {
401
+ this.name = props.name;
402
+ }
403
+ if (props.maxConcurrency !== void 0) {
404
+ this.maxConcurrency = props.maxConcurrency;
405
+ }
406
+ if (props.maxMobileConcurrency !== void 0) {
407
+ this.maxMobileConcurrency = props.maxMobileConcurrency;
408
+ }
409
+ if (props.reuseWorkers !== void 0) {
410
+ this.reuseWorkers = props.reuseWorkers;
411
+ }
412
+ if (props.onDebug !== void 0) {
413
+ this.onDebug = props.onDebug;
414
+ }
415
+ }
416
+ async startJob(name, onMessage2 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) {
417
+ const startPromise = new Promise((onStart) => {
418
+ this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart });
419
+ return this;
420
+ });
421
+ this._startQueuedJob();
422
+ return await startPromise;
423
+ }
424
+ // PRIVATE
425
+ /**
426
+ * Starts first queued job if worker is available or can be created
427
+ * Called when job is started and whenever a worker returns to the idleQueue
428
+ */
429
+ async _startQueuedJob() {
430
+ if (!this.jobQueue.length) {
431
+ return;
432
+ }
433
+ const workerThread = this._getAvailableWorker();
434
+ if (!workerThread) {
435
+ return;
436
+ }
437
+ const queuedJob = this.jobQueue.shift();
438
+ if (queuedJob) {
439
+ this.onDebug({
440
+ message: "Starting job",
441
+ name: queuedJob.name,
442
+ workerThread,
443
+ backlog: this.jobQueue.length
444
+ });
445
+ const job = new WorkerJob(queuedJob.name, workerThread);
446
+ workerThread.onMessage = (data) => queuedJob.onMessage(job, data.type, data.payload);
447
+ workerThread.onError = (error) => queuedJob.onError(job, error);
448
+ queuedJob.onStart(job);
449
+ try {
450
+ await job.result;
451
+ } catch (error) {
452
+ console.error(`Worker exception: ${error}`);
453
+ } finally {
454
+ this.returnWorkerToQueue(workerThread);
455
+ }
456
+ }
457
+ }
458
+ /**
459
+ * Returns a worker to the idle queue
460
+ * Destroys the worker if
461
+ * - pool is destroyed
462
+ * - if this pool doesn't reuse workers
463
+ * - if maxConcurrency has been lowered
464
+ * @param worker
465
+ */
466
+ returnWorkerToQueue(worker) {
467
+ const shouldDestroyWorker = (
468
+ // Workers on Node.js prevent the process from exiting.
469
+ // Until we figure out how to close them before exit, we always destroy them
470
+ !isBrowser || // If the pool is destroyed, there is no reason to keep the worker around
471
+ this.isDestroyed || // If the app has disabled worker reuse, any completed workers should be destroyed
472
+ !this.reuseWorkers || // If concurrency has been lowered, this worker might be surplus to requirements
473
+ this.count > this._getMaxConcurrency()
474
+ );
475
+ if (shouldDestroyWorker) {
476
+ worker.destroy();
477
+ this.count--;
478
+ } else {
479
+ this.idleQueue.push(worker);
480
+ }
481
+ if (!this.isDestroyed) {
482
+ this._startQueuedJob();
483
+ }
484
+ }
485
+ /**
486
+ * Returns idle worker or creates new worker if maxConcurrency has not been reached
487
+ */
488
+ _getAvailableWorker() {
489
+ if (this.idleQueue.length > 0) {
490
+ return this.idleQueue.shift() || null;
491
+ }
492
+ if (this.count < this._getMaxConcurrency()) {
493
+ this.count++;
494
+ const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`;
495
+ return new WorkerThread({ name, source: this.source, url: this.url });
496
+ }
497
+ return null;
498
+ }
499
+ _getMaxConcurrency() {
500
+ return isMobile ? this.maxMobileConcurrency : this.maxConcurrency;
501
+ }
502
+ };
503
+
504
+ // src/lib/worker-farm/worker-farm.ts
505
+ var DEFAULT_PROPS = {
506
+ maxConcurrency: 3,
507
+ maxMobileConcurrency: 1,
508
+ reuseWorkers: true,
509
+ onDebug: () => {
510
+ }
511
+ };
512
+ var WorkerFarm = class {
513
+ /** get global instance with WorkerFarm.getWorkerFarm() */
514
+ constructor(props) {
515
+ this.workerPools = /* @__PURE__ */ new Map();
516
+ this.props = { ...DEFAULT_PROPS };
517
+ this.setProps(props);
518
+ this.workerPools = /* @__PURE__ */ new Map();
519
+ }
520
+ /** Checks if workers are supported on this platform */
521
+ static isSupported() {
522
+ return WorkerThread.isSupported();
523
+ }
524
+ /** Get the singleton instance of the global worker farm */
525
+ static getWorkerFarm(props = {}) {
526
+ WorkerFarm._workerFarm = WorkerFarm._workerFarm || new WorkerFarm({});
527
+ WorkerFarm._workerFarm.setProps(props);
528
+ return WorkerFarm._workerFarm;
529
+ }
530
+ /**
531
+ * Terminate all workers in the farm
532
+ * @note Can free up significant memory
533
+ */
534
+ destroy() {
535
+ for (const workerPool of this.workerPools.values()) {
536
+ workerPool.destroy();
537
+ }
538
+ this.workerPools = /* @__PURE__ */ new Map();
539
+ }
540
+ /**
541
+ * Set props used when initializing worker pools
542
+ * @param props
543
+ */
544
+ setProps(props) {
545
+ this.props = { ...this.props, ...props };
546
+ for (const workerPool of this.workerPools.values()) {
547
+ workerPool.setProps(this._getWorkerPoolProps());
548
+ }
549
+ }
550
+ /**
551
+ * Returns a worker pool for the specified worker
552
+ * @param options - only used first time for a specific worker name
553
+ * @param options.name - the name of the worker - used to identify worker pool
554
+ * @param options.url -
555
+ * @param options.source -
556
+ * @example
557
+ * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...);
558
+ */
559
+ getWorkerPool(options2) {
560
+ const { name, source, url } = options2;
561
+ let workerPool = this.workerPools.get(name);
562
+ if (!workerPool) {
563
+ workerPool = new WorkerPool({
564
+ name,
565
+ source,
566
+ url
567
+ });
568
+ workerPool.setProps(this._getWorkerPoolProps());
569
+ this.workerPools.set(name, workerPool);
570
+ }
571
+ return workerPool;
572
+ }
573
+ _getWorkerPoolProps() {
574
+ return {
575
+ maxConcurrency: this.props.maxConcurrency,
576
+ maxMobileConcurrency: this.props.maxMobileConcurrency,
577
+ reuseWorkers: this.props.reuseWorkers,
578
+ onDebug: this.props.onDebug
579
+ };
580
+ }
581
+ };
582
+
583
+ // src/lib/worker-farm/worker-body.ts
584
+ function getParentPort() {
585
+ let parentPort;
586
+ try {
587
+ eval("globalThis.parentPort = require('worker_threads').parentPort");
588
+ parentPort = globalThis.parentPort;
589
+ } catch {
590
+ }
591
+ return parentPort;
592
+ }
593
+ var onMessageWrapperMap = /* @__PURE__ */ new Map();
594
+ var WorkerBody = class {
595
+ /** Check that we are actually in a worker thread */
596
+ static inWorkerThread() {
597
+ return typeof self !== "undefined" || Boolean(getParentPort());
598
+ }
599
+ /*
600
+ * (type: WorkerMessageType, payload: WorkerMessagePayload) => any
601
+ */
602
+ static set onmessage(onMessage2) {
603
+ function handleMessage(message) {
604
+ const parentPort3 = getParentPort();
605
+ const { type, payload } = parentPort3 ? message : message.data;
606
+ onMessage2(type, payload);
607
+ }
608
+ const parentPort2 = getParentPort();
609
+ if (parentPort2) {
610
+ parentPort2.on("message", handleMessage);
611
+ parentPort2.on("exit", () => console.debug("Node worker closing"));
612
+ } else {
613
+ globalThis.onmessage = handleMessage;
614
+ }
615
+ }
616
+ static addEventListener(onMessage2) {
617
+ let onMessageWrapper = onMessageWrapperMap.get(onMessage2);
618
+ if (!onMessageWrapper) {
619
+ onMessageWrapper = (message) => {
620
+ if (!isKnownMessage(message)) {
621
+ return;
622
+ }
623
+ const parentPort3 = getParentPort();
624
+ const { type, payload } = parentPort3 ? message : message.data;
625
+ onMessage2(type, payload);
626
+ };
627
+ }
628
+ const parentPort2 = getParentPort();
629
+ if (parentPort2) {
630
+ console.error("not implemented");
631
+ } else {
632
+ globalThis.addEventListener("message", onMessageWrapper);
633
+ }
634
+ }
635
+ static removeEventListener(onMessage2) {
636
+ const onMessageWrapper = onMessageWrapperMap.get(onMessage2);
637
+ onMessageWrapperMap.delete(onMessage2);
638
+ const parentPort2 = getParentPort();
639
+ if (parentPort2) {
640
+ console.error("not implemented");
641
+ } else {
642
+ globalThis.removeEventListener("message", onMessageWrapper);
643
+ }
644
+ }
645
+ /**
646
+ * Send a message from a worker to creating thread (main thread)
647
+ * @param type
648
+ * @param payload
649
+ */
650
+ static postMessage(type, payload) {
651
+ const data = { source: "loaders.gl", type, payload };
652
+ const transferList = getTransferList(payload);
653
+ const parentPort2 = getParentPort();
654
+ if (parentPort2) {
655
+ parentPort2.postMessage(data, transferList);
656
+ } else {
657
+ globalThis.postMessage(data, transferList);
658
+ }
659
+ }
660
+ };
661
+ function isKnownMessage(message) {
662
+ const { type, data } = message;
663
+ return type === "message" && data && typeof data.source === "string" && data.source.startsWith("loaders.gl");
664
+ }
665
+
666
+ // src/lib/worker-api/get-worker-url.ts
667
+ function getWorkerName(worker) {
668
+ const warning = worker.version !== VERSION ? ` (worker-utils@${VERSION})` : "";
669
+ return `${worker.name}@${worker.version}${warning}`;
670
+ }
671
+ function getWorkerURL(worker, options2 = {}) {
672
+ const workerOptions = options2[worker.id] || {};
673
+ const workerFile = isBrowser ? `${worker.id}-worker.js` : `${worker.id}-worker-node.js`;
674
+ let url = workerOptions.workerUrl;
675
+ if (!url && worker.id === "compression") {
676
+ url = options2.workerUrl;
677
+ }
678
+ if (options2._workerType === "test") {
679
+ url = `modules/${worker.module}/dist/${workerFile}`;
680
+ }
681
+ if (!url) {
682
+ let version = worker.version;
683
+ if (version === "latest") {
684
+ version = NPM_TAG;
685
+ }
686
+ const versionTag = version ? `@${version}` : "";
687
+ url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
688
+ }
689
+ assert(url);
690
+ return url;
691
+ }
692
+
693
+ // src/lib/worker-api/process-on-worker.ts
694
+ function canProcessOnWorker(worker, options2) {
695
+ if (!WorkerFarm.isSupported()) {
696
+ return false;
697
+ }
698
+ return worker.worker && (options2 == null ? void 0 : options2.worker);
699
+ }
700
+ async function processOnWorker(worker, data, options2 = {}, context = {}) {
701
+ const name = getWorkerName(worker);
702
+ const workerFarm = WorkerFarm.getWorkerFarm(options2);
703
+ const { source } = options2;
704
+ const workerPoolProps = { name, source };
705
+ if (!source) {
706
+ workerPoolProps.url = getWorkerURL(worker, options2);
707
+ }
708
+ const workerPool = workerFarm.getWorkerPool(workerPoolProps);
709
+ const jobName = options2.jobName || worker.name;
710
+ const job = await workerPool.startJob(
711
+ jobName,
712
+ // eslint-disable-next-line
713
+ onMessage.bind(null, context)
714
+ );
715
+ const transferableOptions = getTransferListForWriter(options2);
716
+ job.postMessage("process", { input: data, options: transferableOptions });
717
+ const result = await job.result;
718
+ return result.result;
719
+ }
720
+ async function onMessage(context, job, type, payload) {
721
+ switch (type) {
722
+ case "done":
723
+ job.done(payload);
724
+ break;
725
+ case "error":
726
+ job.error(new Error(payload.error));
727
+ break;
728
+ case "process":
729
+ const { id, input, options: options2 } = payload;
730
+ try {
731
+ if (!context.process) {
732
+ job.postMessage("error", { id, error: "Worker not set up to process on main thread" });
733
+ return;
734
+ }
735
+ const result = await context.process(input, options2);
736
+ job.postMessage("done", { id, result });
737
+ } catch (error) {
738
+ const message = error instanceof Error ? error.message : "unknown error";
739
+ job.postMessage("error", { id, error: message });
740
+ }
741
+ break;
742
+ default:
743
+ console.warn(`process-on-worker: unknown message ${type}`);
744
+ }
745
+ }
746
+
747
+ // src/lib/async-queue/async-queue.ts
748
+ var AsyncQueue = class {
749
+ constructor() {
750
+ this._values = [];
751
+ this._settlers = [];
752
+ this._closed = false;
753
+ }
754
+ /** Return an async iterator for this queue */
755
+ [Symbol.asyncIterator]() {
756
+ return this;
757
+ }
758
+ /** Push a new value - the async iterator will yield a promise resolved to this value */
759
+ push(value) {
760
+ return this.enqueue(value);
761
+ }
762
+ /**
763
+ * Push a new value - the async iterator will yield a promise resolved to this value
764
+ * Add an error - the async iterator will yield a promise rejected with this value
765
+ */
766
+ enqueue(value) {
767
+ if (this._closed) {
768
+ throw new Error("Closed");
769
+ }
770
+ if (this._settlers.length > 0) {
771
+ if (this._values.length > 0) {
772
+ throw new Error("Illegal internal state");
773
+ }
774
+ const settler = this._settlers.shift();
775
+ if (value instanceof Error) {
776
+ settler.reject(value);
777
+ } else {
778
+ settler.resolve({ value });
779
+ }
780
+ } else {
781
+ this._values.push(value);
782
+ }
783
+ }
784
+ /** Indicate that we not waiting for more values - The async iterator will be done */
785
+ close() {
786
+ while (this._settlers.length > 0) {
787
+ const settler = this._settlers.shift();
788
+ settler.resolve({ done: true });
789
+ }
790
+ this._closed = true;
791
+ }
792
+ // ITERATOR IMPLEMENTATION
793
+ /** @returns a Promise for an IteratorResult */
794
+ next() {
795
+ if (this._values.length > 0) {
796
+ const value = this._values.shift();
797
+ if (value instanceof Error) {
798
+ return Promise.reject(value);
799
+ }
800
+ return Promise.resolve({ done: false, value });
801
+ }
802
+ if (this._closed) {
803
+ if (this._settlers.length > 0) {
804
+ throw new Error("Illegal internal state");
805
+ }
806
+ return Promise.resolve({ done: true, value: void 0 });
807
+ }
808
+ return new Promise((resolve, reject) => {
809
+ this._settlers.push({ resolve, reject });
810
+ });
811
+ }
812
+ };
813
+
814
+ // src/lib/worker-api/create-worker.ts
815
+ var requestId = 0;
816
+ var inputBatches;
817
+ var options;
818
+ function createWorker(process2, processInBatches) {
819
+ if (!WorkerBody.inWorkerThread()) {
820
+ return;
821
+ }
822
+ const context = {
823
+ process: processOnMainThread
824
+ };
825
+ WorkerBody.onmessage = async (type, payload) => {
826
+ try {
827
+ switch (type) {
828
+ case "process":
829
+ if (!process2) {
830
+ throw new Error("Worker does not support atomic processing");
831
+ }
832
+ const result = await process2(payload.input, payload.options || {}, context);
833
+ WorkerBody.postMessage("done", { result });
834
+ break;
835
+ case "process-in-batches":
836
+ if (!processInBatches) {
837
+ throw new Error("Worker does not support batched processing");
838
+ }
839
+ inputBatches = new AsyncQueue();
840
+ options = payload.options || {};
841
+ const resultIterator = processInBatches(inputBatches, options, context);
842
+ for await (const batch of resultIterator) {
843
+ WorkerBody.postMessage("output-batch", { result: batch });
844
+ }
845
+ WorkerBody.postMessage("done", {});
846
+ break;
847
+ case "input-batch":
848
+ inputBatches.push(payload.input);
849
+ break;
850
+ case "input-done":
851
+ inputBatches.close();
852
+ break;
853
+ default:
854
+ }
855
+ } catch (error) {
856
+ const message = error instanceof Error ? error.message : "";
857
+ WorkerBody.postMessage("error", { error: message });
858
+ }
859
+ };
860
+ }
861
+ function processOnMainThread(arrayBuffer, options2 = {}) {
862
+ return new Promise((resolve, reject) => {
863
+ const id = requestId++;
864
+ const onMessage2 = (type, payload2) => {
865
+ if (payload2.id !== id) {
866
+ return;
867
+ }
868
+ switch (type) {
869
+ case "done":
870
+ WorkerBody.removeEventListener(onMessage2);
871
+ resolve(payload2.result);
872
+ break;
873
+ case "error":
874
+ WorkerBody.removeEventListener(onMessage2);
875
+ reject(payload2.error);
876
+ break;
877
+ default:
878
+ }
879
+ };
880
+ WorkerBody.addEventListener(onMessage2);
881
+ const payload = { id, input: arrayBuffer, options: options2 };
882
+ WorkerBody.postMessage("process", payload);
883
+ });
884
+ }
885
+
886
+ // src/lib/worker-api/validate-worker-version.ts
887
+ function validateWorkerVersion(worker, coreVersion = VERSION) {
888
+ assert(worker, "no worker provided");
889
+ const workerVersion = worker.version;
890
+ if (!coreVersion || !workerVersion) {
891
+ return false;
892
+ }
893
+ return true;
894
+ }
895
+
896
+ // src/lib/library-utils/library-utils.ts
897
+ var node = __toESM(require_require_utils(), 1);
898
+ var loadLibraryPromises = {};
899
+ async function loadLibrary(libraryUrl, moduleName = null, options2 = {}, libraryName = null) {
900
+ if (moduleName) {
901
+ libraryUrl = getLibraryUrl(libraryUrl, moduleName, options2, libraryName);
902
+ }
903
+ loadLibraryPromises[libraryUrl] = // eslint-disable-next-line @typescript-eslint/no-misused-promises
904
+ loadLibraryPromises[libraryUrl] || loadLibraryFromFile(libraryUrl);
905
+ return await loadLibraryPromises[libraryUrl];
906
+ }
907
+ function getLibraryUrl(library, moduleName, options2 = {}, libraryName = null) {
908
+ if (!options2.useLocalLibraries && library.startsWith("http")) {
909
+ return library;
910
+ }
911
+ libraryName = libraryName || library;
912
+ const modules = options2.modules || {};
913
+ if (modules[libraryName]) {
914
+ return modules[libraryName];
915
+ }
916
+ if (!isBrowser) {
917
+ return `modules/${moduleName}/dist/libs/${libraryName}`;
918
+ }
919
+ if (options2.CDN) {
920
+ assert(options2.CDN.startsWith("http"));
921
+ return `${options2.CDN}/${moduleName}@${VERSION}/dist/libs/${libraryName}`;
922
+ }
923
+ if (isWorker) {
924
+ return `../src/libs/${libraryName}`;
925
+ }
926
+ return `modules/${moduleName}/src/libs/${libraryName}`;
927
+ }
928
+ async function loadLibraryFromFile(libraryUrl) {
929
+ if (libraryUrl.endsWith("wasm")) {
930
+ return await loadAsArrayBuffer(libraryUrl);
931
+ }
932
+ if (!isBrowser) {
933
+ try {
934
+ return node && void 0 && await (void 0)(libraryUrl);
935
+ } catch (error) {
936
+ console.error(error);
937
+ return null;
938
+ }
939
+ }
940
+ if (isWorker) {
941
+ return importScripts(libraryUrl);
942
+ }
943
+ const scriptSource = await loadAsText(libraryUrl);
944
+ return loadLibraryFromString(scriptSource, libraryUrl);
945
+ }
946
+ function loadLibraryFromString(scriptSource, id) {
947
+ if (!isBrowser) {
948
+ return void 0 && (void 0)(scriptSource, id);
949
+ }
950
+ if (isWorker) {
951
+ eval.call(global_, scriptSource);
952
+ return null;
953
+ }
954
+ const script = document.createElement("script");
955
+ script.id = id;
956
+ try {
957
+ script.appendChild(document.createTextNode(scriptSource));
958
+ } catch (e) {
959
+ script.text = scriptSource;
960
+ }
961
+ document.body.appendChild(script);
962
+ return null;
963
+ }
964
+ async function loadAsArrayBuffer(url) {
965
+ if (!void 0 || url.startsWith("http")) {
966
+ const response = await fetch(url);
967
+ return await response.arrayBuffer();
968
+ }
969
+ return await (void 0)(url);
970
+ }
971
+ async function loadAsText(url) {
972
+ if (!void 0 || url.startsWith("http")) {
973
+ const response = await fetch(url);
974
+ return await response.text();
975
+ }
976
+ return await (void 0)(url);
977
+ }
978
+
979
+ // src/index.ts
980
+ var import_child_process_proxy = __toESM(require_child_process_proxy(), 1);
981
+ var NullWorker = {
982
+ id: "null",
983
+ name: "null",
984
+ module: "worker-utils",
985
+ version: VERSION,
986
+ options: {
987
+ null: {}
988
+ }
989
+ };