UNPKG

@loaders.gl/core

Version:

The core API for working with loaders.gl loaders and writers

1,541 lines (1,501 loc) 116 kB
(function webpackUniversalModuleDefinition(root, factory) { if (typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if (typeof define === 'function' && define.amd) define([], factory); else if (typeof exports === 'object') exports['loaders'] = factory(); else root['loaders'] = factory();})(globalThis, function () { "use strict"; var __exports__ = (() => { var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; 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 __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // bundle.ts var bundle_exports = {}; __export(bundle_exports, { FetchError: () => FetchError, JSONLoader: () => JSONLoader, NullLoader: () => NullLoader, NullWorkerLoader: () => NullWorkerLoader, RequestScheduler: () => RequestScheduler, _BrowserFileSystem: () => BrowserFileSystem, _fetchProgress: () => fetchProgress, _selectSource: () => selectSource2, _unregisterLoaders: () => _unregisterLoaders, assert: () => assert, concatenateArrayBuffersAsync: () => concatenateArrayBuffersAsync, createDataSource: () => createDataSource, document: () => document_, encode: () => encode, encodeInBatches: () => encodeInBatches, encodeSync: () => encodeSync, encodeTable: () => encodeTable, encodeTableAsText: () => encodeTableAsText, encodeTableInBatches: () => encodeTableInBatches, encodeText: () => encodeText, encodeTextSync: () => encodeTextSync, encodeURLtoURL: () => encodeURLtoURL, fetchFile: () => fetchFile, forEach: () => forEach, getLoaderOptions: () => getGlobalLoaderOptions, getPathPrefix: () => getPathPrefix, global: () => global_, isAsyncIterable: () => isAsyncIterable, isBrowser: () => isBrowser, isIterable: () => isIterable, isIterator: () => isIterator, isPromise: () => isPromise, isPureObject: () => isPureObject, isReadableStream: () => isReadableStream, isResponse: () => isResponse, isWorker: () => isWorker, isWritableStream: () => isWritableStream, load: () => load, loadInBatches: () => loadInBatches, makeIterator: () => makeIterator, makeLineIterator: () => makeLineIterator, makeNumberedLineIterator: () => makeNumberedLineIterator, makeStream: () => makeStream, makeTextDecoderIterator: () => makeTextDecoderIterator, makeTextEncoderIterator: () => makeTextEncoderIterator, parse: () => parse, parseInBatches: () => parseInBatches, parseSync: () => parseSync, readArrayBuffer: () => readArrayBuffer, registerLoaders: () => registerLoaders, resolvePath: () => resolvePath, selectLoader: () => selectLoader, selectLoaderSync: () => selectLoaderSync, self: () => self_, setLoaderOptions: () => setGlobalOptions, setPathPrefix: () => setPathPrefix, window: () => window_ }); // ../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 isWorker = typeof importScripts === "function"; var matches = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version); var nodeVersion = matches && parseFloat(matches[1]) || 0; // ../../node_modules/@probe.gl/log/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/log/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/log/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/log/node_modules/@probe.gl/env/dist/index.js var VERSION = true ? "4.0.7" : "untranspiled source"; // ../../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, length = 8) { const padLength = Math.max(length - 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/assert.js function assert2(condition, message) { if (!condition) { throw new Error(message || "Assertion failed"); } } // ../../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/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 }; function noop() { } var cache = {}; var ONCE = { once: true }; var Log = class { constructor({ id } = { id: "" }) { 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}__`, DEFAULT_LOG_CONFIGURATION); this.timeStamp(`${this.id} started`); autobind(this); Object.seal(this); } set level(newLevel) { this.setLevel(newLevel); } get level() { return this.getLevel(); } isEnabled() { return this._storage.config.enabled; } getLevel() { return this._storage.config.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._storage.setConfiguration({ enabled }); return this; } setLevel(level) { this._storage.setConfiguration({ level }); return this; } /** return the current status of the setting */ get(setting) { return this._storage.config[setting]; } // update the status of the setting set(setting, value) { this._storage.setConfiguration({ [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) { return this._getLogFunction(0, message, originalConsole.warn, arguments, ONCE); } error(message) { return this._getLogFunction(0, message, originalConsole.error, arguments); } /** 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) { return this._getLogFunction(logLevel, message, originalConsole.log, arguments, { time: true, once: true }); } log(logLevel, message) { return this._getLogFunction(logLevel, message, originalConsole.debug, arguments); } info(logLevel, message) { return this._getLogFunction(logLevel, message, console.info, arguments); } once(logLevel, message) { return this._getLogFunction(logLevel, message, originalConsole.debug || originalConsole.info, arguments, ONCE); } /** Logs an object as a table */ table(logLevel, table, columns) { if (table) { return this._getLogFunction(logLevel, table, console.table || noop, columns && [columns], { tag: getTableHeader(table) }); } return noop; } time(logLevel, message) { return this._getLogFunction(logLevel, message, console.time ? console.time : console.info); } timeEnd(logLevel, message) { return this._getLogFunction(logLevel, message, console.timeEnd ? console.timeEnd : console.info); } timeStamp(logLevel, message) { return this._getLogFunction(logLevel, message, console.timeStamp || noop); } group(logLevel, message, opts = { collapsed: false }) { const options = normalizeArguments({ logLevel, message, opts }); const { collapsed } = opts; options.method = (collapsed ? console.groupCollapsed : console.group) || console.info; return this._getLogFunction(options); } groupCollapsed(logLevel, message, opts = {}) { return this.group(logLevel, message, Object.assign({}, opts, { collapsed: true })); } groupEnd(logLevel) { return this._getLogFunction(logLevel, "", console.groupEnd || noop); } // EXPERIMENTAL withGroup(logLevel, message, func) { this.group(logLevel, message)(); try { func(); } finally { this.groupEnd(logLevel)(); } } trace() { if (console.trace) { console.trace(); } } // PRIVATE METHODS /** Deduces log level from a variety of arguments */ _shouldLog(logLevel) { return this.isEnabled() && this.getLevel() >= normalizeLogLevel(logLevel); } _getLogFunction(logLevel, message, method, args, opts) { if (this._shouldLog(logLevel)) { opts = normalizeArguments({ logLevel, message, args, opts }); method = method || opts.method; assert2(method); opts.total = this.getTotal(); opts.delta = this.getDelta(); this._deltaTs = getHiResTimestamp(); const tag = opts.tag || opts.message; if (opts.once && tag) { if (!cache[tag]) { cache[tag] = getHiResTimestamp(); } else { return noop; } } message = decorateMessage(this.id, opts.message, opts); return method.bind(console, message, ...opts.args); } return noop; } }; Log.VERSION = VERSION; 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); } 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 Log({ id: "@probe.gl/log" }); // ../loader-utils/src/lib/log-utils/log.ts var VERSION2 = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest"; var version = VERSION2[0] >= "0" && VERSION2[0] <= "9" ? `v${VERSION2}` : ""; function createLog() { const log2 = new Log({ id: "loaders.gl" }); globalThis.loaders = globalThis.loaders || {}; globalThis.loaders.log = log2; globalThis.loaders.version = version; globalThis.probe = globalThis.probe || {}; globalThis.probe.loaders = log2; return log2; } var log = createLog(); // ../loader-utils/src/lib/option-utils/merge-loader-options.ts function mergeLoaderOptions(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); } // ../worker-utils/src/lib/env-utils/version.ts var NPM_TAG = "latest"; function getVersion() { if (!globalThis._loadersgl_?.version) { globalThis._loadersgl_ = globalThis._loadersgl_ || {}; if (typeof __VERSION__ === "undefined") { 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; } else { globalThis._loadersgl_.version = __VERSION__; } } 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 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() { } }; // ../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; } function getTransferListForWriter(object) { if (object === null) { return {}; } const clone = Object.assign({}, object); Object.keys(clone).forEach((key) => { if (typeof object[key] === "object" && !ArrayBuffer.isView(object[key]) && !(object[key] instanceof Array)) { clone[key] = getTransferListForWriter(object[key]); } else if (typeof clone[key] === "function" || clone[key] instanceof RegExp) { clone[key] = {}; } else { clone[key] = object[key]; } }); return clone; } // ../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}`; worker = new NodeWorker(url, { eval: false }); } 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, onMessage3 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) { const startPromise = new Promise((onStart) => { this.jobQueue.push({ name, onMessage: onMessage3, 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-api/get-worker-url.ts function getWorkerName(worker) { const warning = worker.version !== VERSION3 ? ` (worker-utils@${VERSION3})` : ""; return `${worker.name}@${worker.version}${warning}`; } 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; } if (options._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/process-on-worker.ts async function processOnWorker(worker, data, options = {}, context = {}) { const name = getWorkerName(worker); const workerFarm = WorkerFarm.getWorkerFarm(options); const { source } = options; const workerPoolProps = { name, source }; if (!source) { workerPoolProps.url = getWorkerURL(worker, options); } const workerPool = workerFarm.getWorkerPool(workerPoolProps); const jobName = options.jobName || worker.name; const job = await workerPool.startJob( jobName, // eslint-disable-next-line onMessage.bind(null, context) ); const transferableOptions = getTransferListForWriter(options); job.postMessage("process", { input: data, options: transferableOptions }); const result = await job.result; return result.result; } async function onMessage(context, 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 { if (!context.process) { job.postMessage("error", { id, error: "Worker not set up to process on main thread" }); return; } const result = await context.process(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(`process-on-worker: unknown message ${type}`); } } // ../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; } // ../loader-utils/src/lib/worker-loader-utils/parse-with-worker.ts function canParseWithWorker(loader, options) { if (!WorkerFarm.isSupported()) { return false; } if (!isBrowser3 && !options?._nodeWorkers) { return false; } return loader.worker && options?.worker; } async function parseWithWorker(loader, data, options, context, parseOnMainThread) { const name = loader.id; const url = getWorkerURL(loader, options); const workerFarm = WorkerFarm.getWorkerFarm(options); 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 onMessage2.bind(null, parseOnMainThread) // 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 onMessage2(parseOnMainThread, 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 parseOnMainThread(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-with-worker unknown message ${type}`); } } // ../loader-utils/src/lib/worker-loader-utils/encode-with-worker.ts function canEncodeWithWorker(writer, options) { if (!WorkerFarm.isSupported()) { return false; } if (!isBrowser && !options?._nodeWorkers) { return false; } return writer.worker && options?.worker; } // ../loader-utils/src/lib/binary-utils/array-buffer-utils.ts function compareArrayBuffers(arrayBuffer1, arrayBuffer2, byteLength) { byteLength = byteLength || arrayBuffer1.byteLength; if (arrayBuffer1.byteLength < byteLength || arrayBuffer2.byteLength < byteLength) { return false; } const array1 = new Uint8Array(arrayBuffer1); const array2 = new Uint8Array(arrayBuffer2); for (let i = 0; i < array1.length; ++i) { if (array1[i] !== array2[i]) { return false; } } return true; } function concatenateArrayBuffers(...sources) { return concatenateArrayBuffersFromArray(sources); } function concatenateArrayBuffersFromArray(sources) { const sourceArrays = sources.map( (source2) => source2 instanceof ArrayBuffer ? new Uint8Array(source2) : source2 ); const byteLength = sourceArrays.reduce((length, typedArray) => length + typedArray.byteLength, 0); const result = new Uint8Array(byteLength); let offset = 0; for (const sourceArray of sourceArrays) { result.set(sourceArray, offset); offset += sourceArray.byteLength; } return result.buffer; } // ../loader-utils/src/lib/iterators/text-iterators.ts async function* makeTextDecoderIterator(arrayBufferIterator, options = {}) { const textDecoder = new TextDecoder(void 0, options); for await (const arrayBuffer of arrayBufferIterator) { yield typeof arrayBuffer === "string" ? arrayBuffer : textDecoder.decode(arrayBuffer, { stream: true }); } } async function* makeTextEncoderIterator(textIterator) { const textEncoder = new TextEncoder(); for await (const text of textIterator) { yield typeof text === "string" ? textEncoder.encode(text) : text; } } async function* makeLineIterator(textIterator) { let previous = ""; for await (const textChunk of textIterator) { previous += textChunk; let eolIndex; while ((eolIndex = previous.indexOf("\n")) >= 0) { const line = previous.slice(0, eolIndex + 1); previous = previous.slice(eolIndex + 1); yield line; } } if (previous.length > 0) { yield previous; } } async function* makeNumberedLineIterator(lineIterator) { let counter = 1; for await (const line of lineIterator) { yield { counter, line }; counter++; } } // ../loader-utils/src/lib/iterators/async-iteration.ts async function forEach(iterator, visitor) { while (true) { const { done, value } = await iterator.next(); if (done) { iterator.return(); return; } const cancel = visitor(value); if (cancel) { return; } } } async function concatenateArrayBuffersAsync(asyncIterator) { const arrayBuffers = []; for await (const chunk of asyncIterator) { arrayBuffers.push(chunk); } return concatenateArrayBuffers(...arrayBuffers); } // ../../node_modules/@probe.gl/stats/dist/utils/hi-res-timestamp.js function getHiResTimestamp2() { let timestamp; if (typeof window !== "undefined" && window.performance) { timestamp = window.performance.now(); } else if (typeof process !== "undefined" && process.hrtime) { const timeParts = process.hrtime(); timestamp = timeParts[0] * 1e3 + timeParts[1] / 1e6; } else { timestamp = Date.now(); } return timestamp; } // ../../node_modules/@probe.gl/stats/dist/lib/stat.js var Stat = class { constructor(name, type) { this.sampleSize = 1; this.time = 0; this.count = 0; this.samples = 0; this.lastTiming = 0; this.lastSampleTime = 0; this.lastSampleCount = 0; this._count = 0; this._time = 0; this._samples = 0; this._startTime = 0; this._timerPending = false; this.name = name; this.type = type; this.reset(); } reset() { this.time = 0; this.count = 0; this.samples = 0; this.lastTiming = 0; this.lastSampleTime = 0; this.lastSampleCount = 0; this._count = 0; this._time = 0; this._samples = 0; this._startTime = 0; this._timerPending = false; return this; } setSampleSize(samples) { this.sampleSize = samples; return this; } /** Call to increment count (+1) */ incrementCount() { this.addCount(1); return this; } /** Call to decrement count (-1) */ decrementCount() { this.subtractCount(1); return this; } /** Increase count */ addCount(value) { this._count += value; this._samples++; this._checkSampling(); return this; } /** Decrease count */ subtractCount(value) { this._count -= value; this._samples++; this._checkSampling(); return this; } /** Add an arbitrary timing and bump the count */ addTime(time) { this._time += time; this.lastTiming = time; this._samples++; this._checkSampling(); return this; } /** Start a timer */ timeStart() { this._startTime = getHiResTimestamp2(); this._timerPending = true; return this; } /** End a timer. Adds to time and bumps the timing count. */ timeEnd() { if (!this._timerPending) { return this; } this.addTime(getHiResTimestamp2() - this._startTime); this._timerPending = false; this._checkSampling(); return this; } getSampleAverageCount() { return this.sampleSize > 0 ? this.lastSampleCount / this.sampleSize : 0; } /** Calculate average time / count for the previous window */ getSampleAverageTime() { return this.sampleSize > 0 ? this.lastSampleTime / this.sampleSize : 0; } /** Calculate counts per second for the previous window */ getSampleHz() { return this.lastSampleTime > 0 ? this.sampleSize / (this.lastSampleTime / 1e3) : 0; } getAverageCount() { return this.samples > 0 ? this.count / this.samples : 0; } /** Calculate average time / count */ getAverageTime() { return this.samples > 0 ? this.time / this.samples : 0; } /** Calculate counts per second */ getHz() { return this.time > 0 ? this.samples / (this.time / 1e3) : 0; } _checkSampling() { if (this._samples === this.sampleSize) { this.lastSampleTime = this._time; this.lastSampleCount = this._count; this.count += this._count; this.time += this._time; this.samples += this._samples; this._time = 0; this._count = 0; this._samples = 0; } } }; // ../../node_modules/@probe.gl/stats/dist/lib/stats.js var Stats = class { constructor(options) { this.stats = {}; this.id = options.id; this.stats = {}; this._initializeStats(options.stats); Object.seal(this); } /** Acquire a stat. Create if it doesn't exist. */ get(name, type = "count") { return this._getOrCreate({ name, type }); } get size() { return Object.keys(this.stats).length; } /** Reset all stats */ reset() { for (const stat of Object.values(this.stats)) { stat.reset(); } return this; } forEach(fn) { for (const stat of Object.values(this.stats)) { fn(stat); } } getTable() { const table = {}; this.forEach((stat) => { table[stat.name] = { time: stat.time || 0, count: stat.count || 0, average: stat.getAverageTime() || 0, hz: stat.getHz() || 0 }; }); return table; } _initializeStats(stats = []) { stats