UNPKG

@loaders.gl/i3s

Version:
1,521 lines (1,482 loc) 279 kB
"use strict"; (() => { var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // ../loader-utils/src/loader-types.ts async function parseFromContext(data, loaders, options, context) { return context._parse(data, loaders, options, context); } // ../loader-utils/src/lib/env-utils/assert.ts function assert(condition, message) { if (!condition) { throw new Error(message || "loader assertion failed."); } } // ../loader-utils/src/lib/env-utils/globals.ts var globals = { self: typeof self !== "undefined" && self, window: typeof window !== "undefined" && window, global: typeof global !== "undefined" && global, document: typeof document !== "undefined" && document }; var self_ = globals.self || globals.window || globals.global || {}; var window_ = globals.window || globals.self || globals.global || {}; var global_ = globals.global || globals.self || globals.window || {}; var document_ = globals.document || {}; var isBrowser = ( // @ts-ignore process does not exist on browser Boolean(typeof process !== "object" || String(process) !== "[object process]" || process.browser) ); var matches = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version); var nodeVersion = matches && parseFloat(matches[1]) || 0; // ../../node_modules/@probe.gl/env/dist/lib/globals.js var window_2 = globalThis; var document_2 = globalThis.document || {}; var process_ = globalThis.process || {}; var console_ = globalThis.console; var navigator_ = globalThis.navigator || {}; // ../../node_modules/@probe.gl/env/dist/lib/is-electron.js function isElectron(mockUserAgent) { if (typeof window !== "undefined" && window.process?.type === "renderer") { return true; } if (typeof process !== "undefined" && Boolean(process.versions?.["electron"])) { return true; } const realUserAgent = typeof navigator !== "undefined" && navigator.userAgent; const userAgent = mockUserAgent || realUserAgent; return Boolean(userAgent && userAgent.indexOf("Electron") >= 0); } // ../../node_modules/@probe.gl/env/dist/lib/is-browser.js function isBrowser2() { const isNode = ( // @ts-expect-error typeof process === "object" && String(process) === "[object process]" && !process?.browser ); return !isNode || isElectron(); } // ../../node_modules/@probe.gl/env/dist/index.js var VERSION = true ? "4.1.1" : "untranspiled source"; // ../../node_modules/@probe.gl/log/dist/utils/assert.js function assert2(condition, message) { if (!condition) { throw new Error(message || "Assertion failed"); } } // ../../node_modules/@probe.gl/log/dist/loggers/log-utils.js function normalizeLogLevel(logLevel) { if (!logLevel) { return 0; } let resolvedLevel; switch (typeof logLevel) { case "number": resolvedLevel = logLevel; break; case "object": resolvedLevel = logLevel.logLevel || logLevel.priority || 0; break; default: return 0; } assert2(Number.isFinite(resolvedLevel) && resolvedLevel >= 0); return resolvedLevel; } function normalizeArguments(opts) { const { logLevel, message } = opts; opts.logLevel = normalizeLogLevel(logLevel); const args = opts.args ? Array.from(opts.args) : []; while (args.length && args.shift() !== message) { } switch (typeof logLevel) { case "string": case "function": if (message !== void 0) { args.unshift(message); } opts.message = logLevel; break; case "object": Object.assign(opts, logLevel); break; default: } if (typeof opts.message === "function") { opts.message = opts.message(); } const messageType = typeof opts.message; assert2(messageType === "string" || messageType === "object"); return Object.assign(opts, { args }, opts.opts); } // ../../node_modules/@probe.gl/log/dist/loggers/base-log.js var noop = () => { }; var BaseLog = class { constructor({ level = 0 } = {}) { this.userData = {}; this._onceCache = /* @__PURE__ */ new Set(); this._level = level; } set level(newLevel) { this.setLevel(newLevel); } get level() { return this.getLevel(); } setLevel(level) { this._level = level; return this; } getLevel() { return this._level; } // Unconditional logging warn(message, ...args) { return this._log("warn", 0, message, args, { once: true }); } error(message, ...args) { return this._log("error", 0, message, args); } // Conditional logging log(logLevel, message, ...args) { return this._log("log", logLevel, message, args); } info(logLevel, message, ...args) { return this._log("info", logLevel, message, args); } once(logLevel, message, ...args) { return this._log("once", logLevel, message, args, { once: true }); } _log(type, logLevel, message, args, options = {}) { const normalized = normalizeArguments({ logLevel, message, args: this._buildArgs(logLevel, message, args), opts: options }); return this._createLogFunction(type, normalized, options); } _buildArgs(logLevel, message, args) { return [logLevel, message, ...args]; } _createLogFunction(type, normalized, options) { if (!this._shouldLog(normalized.logLevel)) { return noop; } const tag = this._getOnceTag(options.tag ?? normalized.tag ?? normalized.message); if ((options.once || normalized.once) && tag !== void 0) { if (this._onceCache.has(tag)) { return noop; } this._onceCache.add(tag); } return this._emit(type, normalized); } _shouldLog(logLevel) { return this.getLevel() >= normalizeLogLevel(logLevel); } _getOnceTag(tag) { if (tag === void 0) { return void 0; } try { return typeof tag === "string" ? tag : String(tag); } catch { return void 0; } } }; // ../../node_modules/@probe.gl/log/dist/utils/local-storage.js function getStorage(type) { try { const storage = window[type]; const x = "__storage_test__"; storage.setItem(x, x); storage.removeItem(x); return storage; } catch (e) { return null; } } var LocalStorage = class { constructor(id, defaultConfig, type = "sessionStorage") { this.storage = getStorage(type); this.id = id; this.config = defaultConfig; this._loadConfiguration(); } getConfiguration() { return this.config; } setConfiguration(configuration) { Object.assign(this.config, configuration); if (this.storage) { const serialized = JSON.stringify(this.config); this.storage.setItem(this.id, serialized); } } // Get config from persistent store, if available _loadConfiguration() { let configuration = {}; if (this.storage) { const serializedConfiguration = this.storage.getItem(this.id); configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {}; } Object.assign(this.config, configuration); return this; } }; // ../../node_modules/@probe.gl/log/dist/utils/formatters.js function formatTime(ms) { let formatted; if (ms < 10) { formatted = `${ms.toFixed(2)}ms`; } else if (ms < 100) { formatted = `${ms.toFixed(1)}ms`; } else if (ms < 1e3) { formatted = `${ms.toFixed(0)}ms`; } else { formatted = `${(ms / 1e3).toFixed(2)}s`; } return formatted; } function leftPad(string, length2 = 8) { const padLength = Math.max(length2 - string.length, 0); return `${" ".repeat(padLength)}${string}`; } // ../../node_modules/@probe.gl/log/dist/utils/color.js var COLOR; (function(COLOR2) { COLOR2[COLOR2["BLACK"] = 30] = "BLACK"; COLOR2[COLOR2["RED"] = 31] = "RED"; COLOR2[COLOR2["GREEN"] = 32] = "GREEN"; COLOR2[COLOR2["YELLOW"] = 33] = "YELLOW"; COLOR2[COLOR2["BLUE"] = 34] = "BLUE"; COLOR2[COLOR2["MAGENTA"] = 35] = "MAGENTA"; COLOR2[COLOR2["CYAN"] = 36] = "CYAN"; COLOR2[COLOR2["WHITE"] = 37] = "WHITE"; COLOR2[COLOR2["BRIGHT_BLACK"] = 90] = "BRIGHT_BLACK"; COLOR2[COLOR2["BRIGHT_RED"] = 91] = "BRIGHT_RED"; COLOR2[COLOR2["BRIGHT_GREEN"] = 92] = "BRIGHT_GREEN"; COLOR2[COLOR2["BRIGHT_YELLOW"] = 93] = "BRIGHT_YELLOW"; COLOR2[COLOR2["BRIGHT_BLUE"] = 94] = "BRIGHT_BLUE"; COLOR2[COLOR2["BRIGHT_MAGENTA"] = 95] = "BRIGHT_MAGENTA"; COLOR2[COLOR2["BRIGHT_CYAN"] = 96] = "BRIGHT_CYAN"; COLOR2[COLOR2["BRIGHT_WHITE"] = 97] = "BRIGHT_WHITE"; })(COLOR || (COLOR = {})); var BACKGROUND_INCREMENT = 10; function getColor(color) { if (typeof color !== "string") { return color; } color = color.toUpperCase(); return COLOR[color] || COLOR.WHITE; } function addColor(string, color, background) { if (!isBrowser2 && typeof string === "string") { if (color) { const colorCode = getColor(color); string = `\x1B[${colorCode}m${string}\x1B[39m`; } if (background) { const colorCode = getColor(background); string = `\x1B[${colorCode + BACKGROUND_INCREMENT}m${string}\x1B[49m`; } } return string; } // ../../node_modules/@probe.gl/log/dist/utils/autobind.js function autobind(obj, predefined = ["constructor"]) { const proto = Object.getPrototypeOf(obj); const propNames = Object.getOwnPropertyNames(proto); const object = obj; for (const key of propNames) { const value = object[key]; if (typeof value === "function") { if (!predefined.find((name) => key === name)) { object[key] = value.bind(obj); } } } } // ../../node_modules/@probe.gl/log/dist/utils/hi-res-timestamp.js function getHiResTimestamp() { let timestamp; if (isBrowser2() && window_2.performance) { timestamp = window_2?.performance?.now?.(); } else if ("hrtime" in process_) { const timeParts = process_?.hrtime?.(); timestamp = timeParts[0] * 1e3 + timeParts[1] / 1e6; } else { timestamp = Date.now(); } return timestamp; } // ../../node_modules/@probe.gl/log/dist/loggers/probe-log.js var originalConsole = { debug: isBrowser2() ? console.debug || console.log : console.log, log: console.log, info: console.info, warn: console.warn, error: console.error }; var DEFAULT_LOG_CONFIGURATION = { enabled: true, level: 0 }; var ProbeLog = class extends BaseLog { constructor({ id } = { id: "" }) { super({ level: 0 }); this.VERSION = VERSION; this._startTs = getHiResTimestamp(); this._deltaTs = getHiResTimestamp(); this.userData = {}; this.LOG_THROTTLE_TIMEOUT = 0; this.id = id; this.userData = {}; this._storage = new LocalStorage(`__probe-${this.id}__`, { [this.id]: DEFAULT_LOG_CONFIGURATION }); this.timeStamp(`${this.id} started`); autobind(this); Object.seal(this); } isEnabled() { return this._getConfiguration().enabled; } getLevel() { return this._getConfiguration().level; } /** @return milliseconds, with fractions */ getTotal() { return Number((getHiResTimestamp() - this._startTs).toPrecision(10)); } /** @return milliseconds, with fractions */ getDelta() { return Number((getHiResTimestamp() - this._deltaTs).toPrecision(10)); } /** @deprecated use logLevel */ set priority(newPriority) { this.level = newPriority; } /** @deprecated use logLevel */ get priority() { return this.level; } /** @deprecated use logLevel */ getPriority() { return this.level; } // Configure enable(enabled = true) { this._updateConfiguration({ enabled }); return this; } setLevel(level) { this._updateConfiguration({ level }); return this; } /** return the current status of the setting */ get(setting) { return this._getConfiguration()[setting]; } // update the status of the setting set(setting, value) { this._updateConfiguration({ [setting]: value }); } /** Logs the current settings as a table */ settings() { if (console.table) { console.table(this._storage.config); } else { console.log(this._storage.config); } } // Unconditional logging assert(condition, message) { if (!condition) { throw new Error(message || "Assertion failed"); } } warn(message, ...args) { return this._log("warn", 0, message, args, { method: originalConsole.warn, once: true }); } error(message, ...args) { return this._log("error", 0, message, args, { method: originalConsole.error }); } /** Print a deprecation warning */ deprecated(oldUsage, newUsage) { return this.warn(`\`${oldUsage}\` is deprecated and will be removed in a later version. Use \`${newUsage}\` instead`); } /** Print a removal warning */ removed(oldUsage, newUsage) { return this.error(`\`${oldUsage}\` has been removed. Use \`${newUsage}\` instead`); } probe(logLevel, message, ...args) { return this._log("log", logLevel, message, args, { method: originalConsole.log, time: true, once: true }); } log(logLevel, message, ...args) { return this._log("log", logLevel, message, args, { method: originalConsole.debug }); } info(logLevel, message, ...args) { return this._log("info", logLevel, message, args, { method: console.info }); } once(logLevel, message, ...args) { return this._log("once", logLevel, message, args, { method: originalConsole.debug || originalConsole.info, once: true }); } /** Logs an object as a table */ table(logLevel, table, columns) { if (table) { return this._log("table", logLevel, table, columns && [columns] || [], { method: console.table || noop, tag: getTableHeader(table) }); } return noop; } time(logLevel, message) { return this._log("time", logLevel, message, [], { method: console.time ? console.time : console.info }); } timeEnd(logLevel, message) { return this._log("time", logLevel, message, [], { method: console.timeEnd ? console.timeEnd : console.info }); } timeStamp(logLevel, message) { return this._log("time", logLevel, message, [], { method: console.timeStamp || noop }); } group(logLevel, message, opts = { collapsed: false }) { const method = (opts.collapsed ? console.groupCollapsed : console.group) || console.info; return this._log("group", logLevel, message, [], { method }); } groupCollapsed(logLevel, message, opts = {}) { return this.group(logLevel, message, Object.assign({}, opts, { collapsed: true })); } groupEnd(logLevel) { return this._log("groupEnd", logLevel, "", [], { method: console.groupEnd || noop }); } // EXPERIMENTAL withGroup(logLevel, message, func) { this.group(logLevel, message)(); try { func(); } finally { this.groupEnd(logLevel)(); } } trace() { if (console.trace) { console.trace(); } } _shouldLog(logLevel) { return this.isEnabled() && super._shouldLog(logLevel); } _emit(_type, normalized) { const method = normalized.method; assert2(method); normalized.total = this.getTotal(); normalized.delta = this.getDelta(); this._deltaTs = getHiResTimestamp(); const message = decorateMessage(this.id, normalized.message, normalized); return method.bind(console, message, ...normalized.args); } _getConfiguration() { if (!this._storage.config[this.id]) { this._updateConfiguration(DEFAULT_LOG_CONFIGURATION); } return this._storage.config[this.id]; } _updateConfiguration(configuration) { const currentConfiguration = this._storage.config[this.id] || { ...DEFAULT_LOG_CONFIGURATION }; this._storage.setConfiguration({ [this.id]: { ...currentConfiguration, ...configuration } }); } }; ProbeLog.VERSION = VERSION; function decorateMessage(id, message, opts) { if (typeof message === "string") { const time = opts.time ? leftPad(formatTime(opts.total)) : ""; message = opts.time ? `${id}: ${time} ${message}` : `${id}: ${message}`; message = addColor(message, opts.color, opts.background); } return message; } function getTableHeader(table) { for (const key in table) { for (const title in table[key]) { return title || "untitled"; } } return "empty"; } // ../../node_modules/@probe.gl/log/dist/init.js globalThis.probe = {}; // ../../node_modules/@probe.gl/log/dist/index.js var dist_default = new ProbeLog({ id: "@probe.gl/log" }); // ../loader-utils/src/lib/log-utils/log.ts var VERSION2 = true ? "4.4.2" : "latest"; var version = VERSION2[0] >= "0" && VERSION2[0] <= "9" ? `v${VERSION2}` : ""; function createLog() { const log2 = new ProbeLog({ id: "loaders.gl" }); globalThis.loaders ||= {}; globalThis.loaders.log = log2; globalThis.loaders.version = version; globalThis.probe ||= {}; globalThis.probe.loaders = log2; return log2; } var log = createLog(); // ../loader-utils/src/lib/javascript-utils/is-type.ts var isBoolean = (value) => typeof value === "boolean"; var isFunction = (value) => typeof value === "function"; var isObject = (value) => value !== null && typeof value === "object"; var isPureObject = (value) => isObject(value) && value.constructor === {}.constructor; var isSharedArrayBuffer = (value) => typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer; var isArrayBufferLike = (value) => isObject(value) && typeof value.byteLength === "number" && typeof value.slice === "function"; var isIterable = (value) => Boolean(value) && isFunction(value[Symbol.iterator]); var isAsyncIterable = (value) => Boolean(value) && isFunction(value[Symbol.asyncIterator]); var isResponse = (value) => typeof Response !== "undefined" && value instanceof Response || isObject(value) && isFunction(value.arrayBuffer) && isFunction(value.text) && isFunction(value.json); var isBlob = (value) => typeof Blob !== "undefined" && value instanceof Blob; var isReadableDOMStream = (value) => typeof ReadableStream !== "undefined" && value instanceof ReadableStream || isObject(value) && isFunction(value.tee) && isFunction(value.cancel) && isFunction(value.getReader); var isReadableNodeStream = (value) => isObject(value) && isFunction(value.read) && isFunction(value.pipe) && isBoolean(value.readable); var isReadableStream = (value) => isReadableDOMStream(value) || isReadableNodeStream(value); // ../loader-utils/src/lib/option-utils/merge-options.ts function mergeOptions(baseOptions, newOptions) { return mergeOptionsRecursively(baseOptions || {}, newOptions); } function mergeOptionsRecursively(baseOptions, newOptions, level = 0) { if (level > 3) { return newOptions; } const options = { ...baseOptions }; for (const [key, newValue] of Object.entries(newOptions)) { if (newValue && typeof newValue === "object" && !Array.isArray(newValue)) { options[key] = mergeOptionsRecursively( options[key] || {}, newOptions[key], level + 1 ); } else { options[key] = newOptions[key]; } } return options; } // ../loader-utils/src/lib/module-utils/js-module-utils.ts function registerJSModules(modules) { globalThis.loaders ||= {}; globalThis.loaders.modules ||= {}; Object.assign(globalThis.loaders.modules, modules); } function getJSModuleOrNull(name) { const module = globalThis.loaders?.modules?.[name]; return module || null; } // ../worker-utils/src/lib/npm-tag.ts var NPM_TAG = "latest"; // ../worker-utils/src/lib/env-utils/version.ts function getVersion() { if (!globalThis._loadersgl_?.version) { globalThis._loadersgl_ = globalThis._loadersgl_ || {}; if (false) { console.warn( "loaders.gl: The __VERSION__ variable is not injected using babel plugin. Latest unstable workers would be fetched from the CDN." ); globalThis._loadersgl_.version = NPM_TAG; warningIssued = true; } else { globalThis._loadersgl_.version = "4.4.2"; } } return globalThis._loadersgl_.version; } var VERSION3 = getVersion(); // ../worker-utils/src/lib/env-utils/assert.ts function assert3(condition, message) { if (!condition) { throw new Error(message || "loaders.gl assertion failed."); } } // ../worker-utils/src/lib/env-utils/globals.ts var globals2 = { self: typeof self !== "undefined" && self, window: typeof window !== "undefined" && window, global: typeof global !== "undefined" && global, document: typeof document !== "undefined" && document }; var self_2 = globals2.self || globals2.window || globals2.global || {}; var window_3 = globals2.window || globals2.self || globals2.global || {}; var global_3 = globals2.global || globals2.self || globals2.window || {}; var document_3 = globals2.document || {}; var isBrowser3 = ( // @ts-ignore process.browser typeof process !== "object" || String(process) !== "[object process]" || process.browser ); var isWorker = typeof importScripts === "function"; var isMobile = typeof window !== "undefined" && typeof window.orientation !== "undefined"; var matches2 = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version); var nodeVersion2 = matches2 && parseFloat(matches2[1]) || 0; // ../worker-utils/src/lib/worker-farm/worker-job.ts var WorkerJob = class { name; workerThread; isRunning = true; /** Promise that resolves when Job is done */ result; _resolve = () => { }; _reject = () => { }; constructor(jobName, workerThread) { this.name = jobName; this.workerThread = workerThread; this.result = new Promise((resolve2, reject) => { this._resolve = resolve2; this._reject = reject; }); } /** * Send a message to the job's worker thread * @param data any data structure, ideally consisting mostly of transferrable objects */ postMessage(type, payload) { this.workerThread.postMessage({ source: "loaders.gl", // Lets worker ignore unrelated messages type, payload }); } /** * Call to resolve the `result` Promise with the supplied value */ done(value) { assert3(this.isRunning); this.isRunning = false; this._resolve(value); } /** * Call to reject the `result` Promise with the supplied error */ error(error) { assert3(this.isRunning); this.isRunning = false; this._reject(error); } }; // ../worker-utils/src/lib/node/worker_threads-browser.ts var NodeWorker = class { terminate() { } }; var parentPort = null; // ../worker-utils/src/lib/worker-utils/get-loadable-worker-url.ts var workerURLCache = /* @__PURE__ */ new Map(); function getLoadableWorkerURL(props) { assert3(props.source && !props.url || !props.source && props.url); let workerURL = workerURLCache.get(props.source || props.url); if (!workerURL) { if (props.url) { workerURL = getLoadableWorkerURLFromURL(props.url); workerURLCache.set(props.url, workerURL); } if (props.source) { workerURL = getLoadableWorkerURLFromSource(props.source); workerURLCache.set(props.source, workerURL); } } assert3(workerURL); return workerURL; } function getLoadableWorkerURLFromURL(url) { if (!url.startsWith("http")) { return url; } const workerSource = buildScriptSource(url); return getLoadableWorkerURLFromSource(workerSource); } function getLoadableWorkerURLFromSource(workerSource) { const blob = new Blob([workerSource], { type: "application/javascript" }); return URL.createObjectURL(blob); } function buildScriptSource(workerUrl) { return `try { importScripts('${workerUrl}'); } catch (error) { console.error(error); throw error; }`; } // ../worker-utils/src/lib/worker-utils/get-transfer-list.ts function getTransferList(object, recursive = true, transfers) { const transfersSet = transfers || /* @__PURE__ */ new Set(); if (!object) { } else if (isTransferable(object)) { transfersSet.add(object); } else if (isTransferable(object.buffer)) { transfersSet.add(object.buffer); } else if (ArrayBuffer.isView(object)) { } else if (recursive && typeof object === "object") { for (const key in object) { getTransferList(object[key], recursive, transfersSet); } } return transfers === void 0 ? Array.from(transfersSet) : []; } function isTransferable(object) { if (!object) { return false; } if (object instanceof ArrayBuffer) { return true; } if (typeof MessagePort !== "undefined" && object instanceof MessagePort) { return true; } if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) { return true; } if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) { return true; } return false; } // ../worker-utils/src/lib/worker-farm/worker-thread.ts var NOOP = () => { }; var WorkerThread = class { name; source; url; terminated = false; worker; onMessage; onError; _loadableURL = ""; /** Checks if workers are supported on this platform */ static isSupported() { return typeof Worker !== "undefined" && isBrowser3 || typeof NodeWorker !== "undefined" && !isBrowser3; } constructor(props) { const { name, source, url } = props; assert3(source || url); this.name = name; this.source = source; this.url = url; this.onMessage = NOOP; this.onError = (error) => console.log(error); this.worker = isBrowser3 ? this._createBrowserWorker() : this._createNodeWorker(); } /** * Terminate this worker thread * @note Can free up significant memory */ destroy() { this.onMessage = NOOP; this.onError = NOOP; this.worker.terminate(); this.terminated = true; } get isRunning() { return Boolean(this.onMessage); } /** * Send a message to this worker thread * @param data any data structure, ideally consisting mostly of transferrable objects * @param transferList If not supplied, calculated automatically by traversing data */ postMessage(data, transferList) { transferList = transferList || getTransferList(data); this.worker.postMessage(data, transferList); } // PRIVATE /** * Generate a standard Error from an ErrorEvent * @param event */ _getErrorFromErrorEvent(event) { let message = "Failed to load "; message += `worker ${this.name} from ${this.url}. `; if (event.message) { message += `${event.message} in `; } if (event.lineno) { message += `:${event.lineno}:${event.colno}`; } return new Error(message); } /** * Creates a worker thread on the browser */ _createBrowserWorker() { this._loadableURL = getLoadableWorkerURL({ source: this.source, url: this.url }); const worker = new Worker(this._loadableURL, { name: this.name }); worker.onmessage = (event) => { if (!event.data) { this.onError(new Error("No data received")); } else { this.onMessage(event.data); } }; worker.onerror = (error) => { this.onError(this._getErrorFromErrorEvent(error)); this.terminated = true; }; worker.onmessageerror = (event) => console.error(event); return worker; } /** * Creates a worker thread in node.js * @todo https://nodejs.org/api/async_hooks.html#async-resource-worker-pool */ _createNodeWorker() { let worker; if (this.url) { const absolute = this.url.includes(":/") || this.url.startsWith("/"); const url = absolute ? this.url : `./${this.url}`; const type = this.url.endsWith(".ts") || this.url.endsWith(".mjs") ? "module" : "commonjs"; worker = new NodeWorker(url, { eval: false, type }); } else if (this.source) { worker = new NodeWorker(this.source, { eval: true }); } else { throw new Error("no worker"); } worker.on("message", (data) => { this.onMessage(data); }); worker.on("error", (error) => { this.onError(error); }); worker.on("exit", (code) => { }); return worker; } }; // ../worker-utils/src/lib/worker-farm/worker-pool.ts var WorkerPool = class { name = "unnamed"; source; // | Function; url; maxConcurrency = 1; maxMobileConcurrency = 1; onDebug = () => { }; reuseWorkers = true; props = {}; jobQueue = []; idleQueue = []; count = 0; isDestroyed = false; /** Checks if workers are supported on this platform */ static isSupported() { return WorkerThread.isSupported(); } /** * @param processor - worker function * @param maxConcurrency - max count of workers */ constructor(props) { this.source = props.source; this.url = props.url; this.setProps(props); } /** * Terminates all workers in the pool * @note Can free up significant memory */ destroy() { this.idleQueue.forEach((worker) => worker.destroy()); this.isDestroyed = true; } setProps(props) { this.props = { ...this.props, ...props }; if (props.name !== void 0) { this.name = props.name; } if (props.maxConcurrency !== void 0) { this.maxConcurrency = props.maxConcurrency; } if (props.maxMobileConcurrency !== void 0) { this.maxMobileConcurrency = props.maxMobileConcurrency; } if (props.reuseWorkers !== void 0) { this.reuseWorkers = props.reuseWorkers; } if (props.onDebug !== void 0) { this.onDebug = props.onDebug; } } async startJob(name, onMessage2 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) { const startPromise = new Promise((onStart) => { this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart }); return this; }); this._startQueuedJob(); return await startPromise; } // PRIVATE /** * Starts first queued job if worker is available or can be created * Called when job is started and whenever a worker returns to the idleQueue */ async _startQueuedJob() { if (!this.jobQueue.length) { return; } const workerThread = this._getAvailableWorker(); if (!workerThread) { return; } const queuedJob = this.jobQueue.shift(); if (queuedJob) { this.onDebug({ message: "Starting job", name: queuedJob.name, workerThread, backlog: this.jobQueue.length }); const job = new WorkerJob(queuedJob.name, workerThread); workerThread.onMessage = (data) => queuedJob.onMessage(job, data.type, data.payload); workerThread.onError = (error) => queuedJob.onError(job, error); queuedJob.onStart(job); try { await job.result; } catch (error) { console.error(`Worker exception: ${error}`); } finally { this.returnWorkerToQueue(workerThread); } } } /** * Returns a worker to the idle queue * Destroys the worker if * - pool is destroyed * - if this pool doesn't reuse workers * - if maxConcurrency has been lowered * @param worker */ returnWorkerToQueue(worker) { const shouldDestroyWorker = ( // Workers on Node.js prevent the process from exiting. // Until we figure out how to close them before exit, we always destroy them !isBrowser3 || // If the pool is destroyed, there is no reason to keep the worker around this.isDestroyed || // If the app has disabled worker reuse, any completed workers should be destroyed !this.reuseWorkers || // If concurrency has been lowered, this worker might be surplus to requirements this.count > this._getMaxConcurrency() ); if (shouldDestroyWorker) { worker.destroy(); this.count--; } else { this.idleQueue.push(worker); } if (!this.isDestroyed) { this._startQueuedJob(); } } /** * Returns idle worker or creates new worker if maxConcurrency has not been reached */ _getAvailableWorker() { if (this.idleQueue.length > 0) { return this.idleQueue.shift() || null; } if (this.count < this._getMaxConcurrency()) { this.count++; const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`; return new WorkerThread({ name, source: this.source, url: this.url }); } return null; } _getMaxConcurrency() { return isMobile ? this.maxMobileConcurrency : this.maxConcurrency; } }; // ../worker-utils/src/lib/worker-farm/worker-farm.ts var DEFAULT_PROPS = { maxConcurrency: 3, maxMobileConcurrency: 1, reuseWorkers: true, onDebug: () => { } }; var _WorkerFarm = class { props; workerPools = /* @__PURE__ */ new Map(); /** Checks if workers are supported on this platform */ static isSupported() { return WorkerThread.isSupported(); } /** Get the singleton instance of the global worker farm */ static getWorkerFarm(props = {}) { _WorkerFarm._workerFarm = _WorkerFarm._workerFarm || new _WorkerFarm({}); _WorkerFarm._workerFarm.setProps(props); return _WorkerFarm._workerFarm; } /** get global instance with WorkerFarm.getWorkerFarm() */ constructor(props) { this.props = { ...DEFAULT_PROPS }; this.setProps(props); this.workerPools = /* @__PURE__ */ new Map(); } /** * Terminate all workers in the farm * @note Can free up significant memory */ destroy() { for (const workerPool of this.workerPools.values()) { workerPool.destroy(); } this.workerPools = /* @__PURE__ */ new Map(); } /** * Set props used when initializing worker pools * @param props */ setProps(props) { this.props = { ...this.props, ...props }; for (const workerPool of this.workerPools.values()) { workerPool.setProps(this._getWorkerPoolProps()); } } /** * Returns a worker pool for the specified worker * @param options - only used first time for a specific worker name * @param options.name - the name of the worker - used to identify worker pool * @param options.url - * @param options.source - * @example * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...); */ getWorkerPool(options) { const { name, source, url } = options; let workerPool = this.workerPools.get(name); if (!workerPool) { workerPool = new WorkerPool({ name, source, url }); workerPool.setProps(this._getWorkerPoolProps()); this.workerPools.set(name, workerPool); } return workerPool; } _getWorkerPoolProps() { return { maxConcurrency: this.props.maxConcurrency, maxMobileConcurrency: this.props.maxMobileConcurrency, reuseWorkers: this.props.reuseWorkers, onDebug: this.props.onDebug }; } }; var WorkerFarm = _WorkerFarm; // singleton __publicField(WorkerFarm, "_workerFarm"); // ../worker-utils/src/lib/worker-farm/worker-body.ts async function getParentPort() { return parentPort; } var onMessageWrapperMap = /* @__PURE__ */ new Map(); var WorkerBody = class { /** Check that we are actually in a worker thread */ static async inWorkerThread() { return typeof self !== "undefined" || Boolean(await getParentPort()); } /* * (type: WorkerMessageType, payload: WorkerMessagePayload) => any */ static set onmessage(onMessage2) { async function handleMessage(message) { const parentPort2 = await getParentPort(); const { type, payload } = parentPort2 ? message : message.data; onMessage2(type, payload); } getParentPort().then((parentPort2) => { if (parentPort2) { parentPort2.on("message", (message) => { handleMessage(message); }); parentPort2.on("exit", () => console.debug("Node worker closing")); } else { globalThis.onmessage = handleMessage; } }); } static async addEventListener(onMessage2) { let onMessageWrapper = onMessageWrapperMap.get(onMessage2); if (!onMessageWrapper) { onMessageWrapper = async (message) => { if (!isKnownMessage(message)) { return; } const parentPort3 = await getParentPort(); const { type, payload } = parentPort3 ? message : message.data; onMessage2(type, payload); }; } const parentPort2 = await getParentPort(); if (parentPort2) { console.error("not implemented"); } else { globalThis.addEventListener("message", onMessageWrapper); } } static async removeEventListener(onMessage2) { const onMessageWrapper = onMessageWrapperMap.get(onMessage2); onMessageWrapperMap.delete(onMessage2); const parentPort2 = await getParentPort(); if (parentPort2) { console.error("not implemented"); } else { globalThis.removeEventListener("message", onMessageWrapper); } } /** * Send a message from a worker to creating thread (main thread) * @param type * @param payload */ static async postMessage(type, payload) { const data = { source: "loaders.gl", type, payload }; const transferList = getTransferList(payload); const parentPort2 = await getParentPort(); if (parentPort2) { parentPort2.postMessage(data, transferList); } else { globalThis.postMessage(data, transferList); } } }; function isKnownMessage(message) { const { type, data } = message; return type === "message" && data && typeof data.source === "string" && data.source.startsWith("loaders.gl"); } // ../worker-utils/src/lib/worker-api/get-worker-url.ts function getWorkerURL(worker, options = {}) { const workerOptions = options[worker.id] || {}; const workerFile = isBrowser3 ? `${worker.id}-worker.js` : `${worker.id}-worker-node.js`; let url = workerOptions.workerUrl; if (!url && worker.id === "compression") { url = options.workerUrl; } const workerType = options._workerType || options?.core?._workerType; if (workerType === "test") { if (isBrowser3) { url = `modules/${worker.module}/dist/${workerFile}`; } else { url = `modules/${worker.module}/src/workers/${worker.id}-worker-node.ts`; } } if (!url) { let version2 = worker.version; if (version2 === "latest") { version2 = NPM_TAG; } const versionTag = version2 ? `@${version2}` : ""; url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`; } assert3(url); return url; } // ../worker-utils/src/lib/worker-api/validate-worker-version.ts function validateWorkerVersion(worker, coreVersion = VERSION3) { assert3(worker, "no worker provided"); const workerVersion = worker.version; if (!coreVersion || !workerVersion) { return false; } return true; } // ../worker-utils/src/lib/library-utils/library-utils.ts var loadLibraryPromises = {}; function extractLoadLibraryOptions(options = {}) { const useLocalLibraries = options.useLocalLibraries ?? options.core?.useLocalLibraries; const CDN = options.CDN ?? options.core?.CDN; const modules = options.modules; return { ...useLocalLibraries !== void 0 ? { useLocalLibraries } : {}, ...CDN !== void 0 ? { CDN } : {}, ...modules !== void 0 ? { modules } : {} }; } async function loadLibrary(libraryUrl, moduleName = null, options = {}, libraryName = null) { if (moduleName) { libraryUrl = getLibraryUrl(libraryUrl, moduleName, options, libraryName); } loadLibraryPromises[libraryUrl] = // eslint-disable-next-line @typescript-eslint/no-misused-promises loadLibraryPromises[libraryUrl] || loadLibraryFromFile(libraryUrl); return await loadLibraryPromises[libraryUrl]; } function getLibraryUrl(library, moduleName, options = {}, libraryName = null) { if (options?.core) { throw new Error("loadLibrary: options.core must be pre-normalized"); } if (!options.useLocalLibraries && library.startsWith("http")) { return library; } libraryName = libraryName || library; const modules = options.modules || {}; if (modules[libraryName]) { return modules[libraryName]; } if (!isBrowser3) { return `modules/${moduleName}/dist/libs/${libraryName}`; } if (options.CDN) { assert3(options.CDN.startsWith("http")); return `${options.CDN}/${moduleName}@${VERSION3}/dist/libs/${libraryName}`; } if (isWorker) { return `../src/libs/${libraryName}`; } return `modules/${moduleName}/src/libs/${libraryName}`; } async function loadLibraryFromFile(libraryUrl) { if (libraryUrl.endsWith("wasm")) { return await loadAsArrayBuffer(libraryUrl); } if (!isBrowser3) { const { requireFromFile } = globalThis.loaders || {}; try { const result = await requireFromFile?.(libraryUrl); if (result || !libraryUrl.includes("/dist/libs/")) { return result; } return await requireFromFile?.(libraryUrl.replace("/dist/libs/", "/src/libs/")); } catch (error) { if (libraryUrl.includes("/dist/libs/")) { try { return await requireFromFile?.(libraryUrl.replace("/dist/libs/", "/src/libs/")); } catch { } } console.error(error); return null; } } if (isWorker) { return importScripts(libraryUrl); } const scriptSource = await loadAsText(libraryUrl); return loadLibraryFromString(scriptSource, libraryUrl); } function loadLibraryFromString(scriptSource, id) { if (!isBrowser3) { const { requireFromString } = globalThis.loaders || {}; return requireFromString?.(scriptSource, id); } if (isWorker) { eval.call(globalThis, scriptSource); return null; } const script = document.createElement("script"); script.id = id; try { script.appendChild(document.createTextNode(scriptSource)); } catch (e) { script.text = scriptSource; } document.body.appendChild(script); return null; } async function loadAsArrayBuffer(url) { const { readFileAsArrayBuffer } = globalThis.loaders || {}; if (isBrowser3 || !readFileAsArrayBuffer || url.startsWith("http")) { const response = await fetch(url); return await response.arrayBuffer(); } try { return await readFileAsArrayBuffer(url); } catch { if (url.includes("/dist/libs/")) { return await readFileAsArrayBuffer(url.replace("/dist/libs/", "/src/libs/")); } throw new Error(`Failed to load ArrayBuffer from ${url}`); } } async function loadAsText(url) { const { readFileAsText } = globalThis.loaders || {}; if (isBrowser3 || !readFileAsText || url.startsWith("http")) { const response = await fetch(url); return await response.text(); } try { return await readFileAsText(url); } catch { if (url.includes("/dist/libs/")) { return await readFileAsText(url.replace("/dist/libs/", "/src/libs/")); } throw new Error(`Failed to load text from ${url}`); } } // ../loader-utils/src/lib/worker-loader-utils/create-loader-worker.ts var requestId = 0; async function createLoaderWorker(loader) { if (!await WorkerBody.inWorkerThread()) { return; } WorkerBody.onmessage = async (type, payload) => { switch (type) { case "process": try { const { input, options = {}, context = {} } = payload; const result = await parseData({ loader, arrayBuffer: input, options, // @ts-expect-error fetch missing context: { ...context, _parse: parseOnMainThread } }); WorkerBody.postMessage("done", { result }); } catch (error) { const message = error instanceof Error ? error.message : ""; WorkerBody.postMessage("error", { error: message }); } break; default: } }; } function parseOnMainThread(arrayBuffer, loader, options, context) { return new Promise((resolve2, reject) => { const id = requestId++; const onMessage2 = (type, payload2) => { if (payload2.id !== id) { return; } switch (type) { case "done": WorkerBody.removeEventListener(onMessage2); resolve2(payload2.result); break; case "error": WorkerBody.removeEventListener(onMessage2); reject(payload2.error); break; default: } }; WorkerBody.addEventListener(onMessage2); const payload = { id, input: arrayBuffer, options }; WorkerBody.postMessage("process", payload); }); } async function parseData({ loader, arrayBuffer, options, context }) { let data; let parser; if (loader.parseSync || loader.parse) { data = arrayBuffer; parser = loader.parseSync || loader.parse; } else if (loader.parseTextSync) { const textDecoder = new TextDecoder(); data = textDecoder.decode(arrayBuffer); parser = loader.parseTextSync; } else { throw new Error(`Could not load data with ${loader.name} loader`); } options = { ...options, modules: loader && loader.options && loader.options.modules || {}, core: { ...options.core, worker: false } }; return await parser(data, { ...options }, context, loader); } // ../loader-utils/src/lib/worker-loader-utils/parse-with-worker.ts function canParseWithWorker(loader, options) { if (!WorkerFarm.isSupported()) { return false; } const nodeWorkers = options?._nodeWorkers ?? options?.core?._nodeWorkers; if (!isBrowser3 && !nodeWorkers) { return false; } const useWorkers = options?.worker ?? options?.core?.worker; return Boolean(loader.worker && useWorkers); } async function parseWithWorker(loader, data, options, context, parseOnMainThread2) { const name = loader.id; const url = getWorkerURL(loader, options); const workerFarm = WorkerFarm.getWorkerFarm(options?.core); const workerPool = workerFarm.getWorkerPool({ name, url }); options = JSON.parse(JSON.stringify(options)); context = JSON.parse(JSON.stringify(context || {})); const job = await workerPool.startJob( "process-on-worker", // @ts-expect-error onMessage.bind(null, parseOnMainThread2) // eslint-disable-line @typescript-eslint/no-misused-promises ); job.postMessage("process", { // @ts-ignore input: data, options, context }); const result = await job.result; return await result.result; } async function onMessage(parseOnMainThread2, job, type, payload) { switch (type) { case "done": job.done(payload); break; case "error": job.error(new Error(payload.error)); break; case "process": const { id, input, options } = payload; try { const result = await parseOnMainThread2(input, options); job.postMessage("done", { id, result }); } catch (error) { const message = error instanceof Error ? error.message : "unknown error"; job.postMessage("error", { id, error: message }); } break; default: console.warn(`parse-