@loaders.gl/core 5.0.0-alpha.5 → 5.0.0-alpha.7

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 (33) hide show
  1. package/dist/dist.dev.js +398 -49
  2. package/dist/dist.min.js +3 -3
  3. package/dist/index.cjs +405 -51
  4. package/dist/index.cjs.map +3 -3
  5. package/dist/lib/api/parse-in-batches.d.ts.map +1 -1
  6. package/dist/lib/api/parse-in-batches.js +6 -2
  7. package/dist/lib/api/parse-in-batches.js.map +1 -1
  8. package/dist/lib/api/parse.js +2 -2
  9. package/dist/lib/api/parse.js.map +1 -1
  10. package/dist/lib/init.js +1 -1
  11. package/dist/lib/loader-utils/get-fetch-function.d.ts.map +1 -1
  12. package/dist/lib/loader-utils/get-fetch-function.js +2 -1
  13. package/dist/lib/loader-utils/get-fetch-function.js.map +1 -1
  14. package/dist/lib/loader-utils/loader-context.d.ts +1 -1
  15. package/dist/lib/loader-utils/loader-context.d.ts.map +1 -1
  16. package/dist/lib/loader-utils/loader-context.js +6 -3
  17. package/dist/lib/loader-utils/loader-context.js.map +1 -1
  18. package/dist/lib/loader-utils/option-defaults.d.ts.map +1 -1
  19. package/dist/lib/loader-utils/option-defaults.js +1 -0
  20. package/dist/lib/loader-utils/option-defaults.js.map +1 -1
  21. package/dist/lib/loader-utils/option-utils.d.ts.map +1 -1
  22. package/dist/lib/loader-utils/option-utils.js +12 -1
  23. package/dist/lib/loader-utils/option-utils.js.map +1 -1
  24. package/dist/null-loader.js +1 -1
  25. package/dist/null-worker-node.js +29 -3
  26. package/dist/null-worker.js +29 -3
  27. package/package.json +6 -6
  28. package/src/lib/api/parse-in-batches.ts +11 -2
  29. package/src/lib/api/parse.ts +2 -2
  30. package/src/lib/loader-utils/get-fetch-function.ts +2 -1
  31. package/src/lib/loader-utils/loader-context.ts +6 -3
  32. package/src/lib/loader-utils/option-defaults.ts +1 -0
  33. package/src/lib/loader-utils/option-utils.ts +13 -1
package/dist/dist.dev.js CHANGED
@@ -925,6 +925,10 @@ var __exports__ = (() => {
925
925
  name;
926
926
  source;
927
927
  url;
928
+ /** Lazily resolves the classic worker URL used as a fallback. */
929
+ getUrl;
930
+ /** Creates a browser Worker directly. */
931
+ loadWorker;
928
932
  terminated = false;
929
933
  worker;
930
934
  onMessage;
@@ -935,11 +939,13 @@ var __exports__ = (() => {
935
939
  return typeof Worker !== "undefined" && isBrowser3 || typeof NodeWorker !== "undefined" && !isBrowser3;
936
940
  }
937
941
  constructor(props) {
938
- const { name, source, url } = props;
939
- assert3(source || url);
942
+ const { name, source, url, getUrl, loadWorker } = props;
943
+ assert3(source || url || getUrl || loadWorker);
940
944
  this.name = name;
941
945
  this.source = source;
942
946
  this.url = url;
947
+ this.getUrl = getUrl;
948
+ this.loadWorker = loadWorker;
943
949
  this.onMessage = NOOP;
944
950
  this.onError = (error) => console.log(error);
945
951
  this.worker = isBrowser3 ? this._createBrowserWorker() : this._createNodeWorker();
@@ -985,7 +991,7 @@ var __exports__ = (() => {
985
991
  */
986
992
  _getErrorFromErrorEvent(event) {
987
993
  let message = "Failed to load ";
988
- message += `worker ${this.name} from ${this.url}. `;
994
+ message += `worker ${this.name} from ${this.url || "built-in worker factory"}. `;
989
995
  if (event.message) {
990
996
  message += `${event.message} in `;
991
997
  }
@@ -998,8 +1004,25 @@ var __exports__ = (() => {
998
1004
  * Creates a worker thread on the browser
999
1005
  */
1000
1006
  _createBrowserWorker() {
1001
- this._loadableURL = getLoadableWorkerURL({ source: this.source, url: this.url });
1007
+ if (this.loadWorker) {
1008
+ try {
1009
+ const worker2 = this.loadWorker();
1010
+ if (worker2) {
1011
+ return this._initializeBrowserWorker(worker2);
1012
+ }
1013
+ } catch (error) {
1014
+ if (!this.source && !this.url && !this.getUrl) {
1015
+ throw error;
1016
+ }
1017
+ }
1018
+ }
1019
+ const url = this.url || this.getUrl?.();
1020
+ this._loadableURL = getLoadableWorkerURL({ source: this.source, url });
1002
1021
  const worker = new Worker(this._loadableURL, { name: this.name });
1022
+ return this._initializeBrowserWorker(worker);
1023
+ }
1024
+ /** Attaches protocol handlers to a browser worker. */
1025
+ _initializeBrowserWorker(worker) {
1003
1026
  worker.onmessage = (event) => {
1004
1027
  if (!event.data) {
1005
1028
  this.onError(new Error("No data received"));
@@ -1049,6 +1072,10 @@ var __exports__ = (() => {
1049
1072
  source;
1050
1073
  // | Function;
1051
1074
  url;
1075
+ /** Lazily resolves a classic worker fallback URL. */
1076
+ getUrl;
1077
+ /** Creates a browser Worker directly. */
1078
+ loadWorker;
1052
1079
  maxConcurrency = 1;
1053
1080
  maxMobileConcurrency = 1;
1054
1081
  onDebug = () => {
@@ -1057,6 +1084,7 @@ var __exports__ = (() => {
1057
1084
  props = {};
1058
1085
  jobQueue = [];
1059
1086
  idleQueue = [];
1087
+ activeJobs = /* @__PURE__ */ new Set();
1060
1088
  count = 0;
1061
1089
  isDestroyed = false;
1062
1090
  /** Checks if workers are supported on this platform */
@@ -1070,13 +1098,19 @@ var __exports__ = (() => {
1070
1098
  constructor(props) {
1071
1099
  this.source = props.source;
1072
1100
  this.url = props.url;
1101
+ this.getUrl = props.getUrl;
1102
+ this.loadWorker = props.loadWorker;
1073
1103
  this.setProps(props);
1074
1104
  }
1075
1105
  /**
1076
- * Terminates all workers in the pool
1106
+ * Terminates all workers in the pool and aborts active jobs.
1107
+ * @param reason Optional error delivered to active jobs.
1077
1108
  * @note Can free up significant memory
1078
1109
  */
1079
- destroy() {
1110
+ destroy(reason = new Error("Worker pool was destroyed")) {
1111
+ this.activeJobs.forEach((job) => job.abort(reason));
1112
+ const queuedJobs = this.jobQueue.splice(0);
1113
+ queuedJobs.forEach((queuedJob) => queuedJob.onReject(reason));
1080
1114
  this.idleQueue.forEach((worker) => worker.destroy());
1081
1115
  this.isDestroyed = true;
1082
1116
  }
@@ -1099,8 +1133,11 @@ var __exports__ = (() => {
1099
1133
  }
1100
1134
  }
1101
1135
  async startJob(name, onMessage2 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) {
1102
- const startPromise = new Promise((onStart) => {
1103
- this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart });
1136
+ if (this.isDestroyed) {
1137
+ return Promise.reject(new Error("Worker pool was destroyed"));
1138
+ }
1139
+ const startPromise = new Promise((onStart, onReject) => {
1140
+ this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart, onReject });
1104
1141
  return this;
1105
1142
  });
1106
1143
  this._startQueuedJob();
@@ -1128,6 +1165,7 @@ var __exports__ = (() => {
1128
1165
  backlog: this.jobQueue.length
1129
1166
  });
1130
1167
  const job = new WorkerJob(queuedJob.name, workerThread);
1168
+ this.activeJobs.add(job);
1131
1169
  workerThread.ref();
1132
1170
  workerThread.onMessage = (data) => queuedJob.onMessage(job, data.type, data.payload);
1133
1171
  workerThread.onError = (error) => queuedJob.onError(job, error);
@@ -1136,6 +1174,7 @@ var __exports__ = (() => {
1136
1174
  await job.result;
1137
1175
  } catch {
1138
1176
  } finally {
1177
+ this.activeJobs.delete(job);
1139
1178
  this.returnWorkerToQueue(workerThread);
1140
1179
  }
1141
1180
  }
@@ -1179,7 +1218,13 @@ var __exports__ = (() => {
1179
1218
  if (this.count < this._getMaxConcurrency()) {
1180
1219
  this.count++;
1181
1220
  const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`;
1182
- return new WorkerThread({ name, source: this.source, url: this.url });
1221
+ return new WorkerThread({
1222
+ name,
1223
+ source: this.source,
1224
+ url: this.url,
1225
+ getUrl: this.getUrl,
1226
+ loadWorker: this.loadWorker
1227
+ });
1183
1228
  }
1184
1229
  return null;
1185
1230
  }
@@ -1196,6 +1241,8 @@ var __exports__ = (() => {
1196
1241
  onDebug: () => {
1197
1242
  }
1198
1243
  };
1244
+ var loadWorkerIds = /* @__PURE__ */ new WeakMap();
1245
+ var nextLoadWorkerId = 1;
1199
1246
  var WorkerFarm = class _WorkerFarm {
1200
1247
  props;
1201
1248
  workerPools = /* @__PURE__ */ new Map();
@@ -1218,12 +1265,13 @@ var __exports__ = (() => {
1218
1265
  this.workerPools = /* @__PURE__ */ new Map();
1219
1266
  }
1220
1267
  /**
1221
- * Terminate all workers in the farm
1268
+ * Terminate all workers in the farm and abort active jobs.
1269
+ * @param reason Optional error delivered to active jobs.
1222
1270
  * @note Can free up significant memory
1223
1271
  */
1224
- destroy() {
1272
+ destroy(reason) {
1225
1273
  for (const workerPool of this.workerPools.values()) {
1226
- workerPool.destroy();
1274
+ workerPool.destroy(reason);
1227
1275
  }
1228
1276
  this.workerPools = /* @__PURE__ */ new Map();
1229
1277
  }
@@ -1239,24 +1287,28 @@ var __exports__ = (() => {
1239
1287
  }
1240
1288
  /**
1241
1289
  * Returns a worker pool for the specified worker
1242
- * @param options - only used first time for a specific worker name
1243
- * @param options.name - the name of the worker - used to identify worker pool
1244
- * @param options.url -
1245
- * @param options.source -
1290
+ * @param options Worker target used to identify and initialize the pool.
1291
+ * @param options.name Worker name used as the base pool identity.
1292
+ * @param options.url Worker script URL.
1293
+ * @param options.source Inline worker source.
1294
+ * @param options.loadWorker Built-in browser worker factory.
1246
1295
  * @example
1247
1296
  * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...);
1248
1297
  */
1249
1298
  getWorkerPool(options) {
1250
- const { name, source, url } = options;
1251
- let workerPool = this.workerPools.get(name);
1299
+ const { name, source, url, getUrl, loadWorker } = options;
1300
+ const workerPoolKey = getWorkerPoolKey(options);
1301
+ let workerPool = this.workerPools.get(workerPoolKey);
1252
1302
  if (!workerPool) {
1253
1303
  workerPool = new WorkerPool({
1254
1304
  name,
1255
1305
  source,
1256
- url
1306
+ url,
1307
+ getUrl,
1308
+ loadWorker
1257
1309
  });
1258
1310
  workerPool.setProps(this._getWorkerPoolProps());
1259
- this.workerPools.set(name, workerPool);
1311
+ this.workerPools.set(workerPoolKey, workerPool);
1260
1312
  }
1261
1313
  return workerPool;
1262
1314
  }
@@ -1269,6 +1321,91 @@ var __exports__ = (() => {
1269
1321
  };
1270
1322
  }
1271
1323
  };
1324
+ function getWorkerPoolKey(options) {
1325
+ const { name, source, url, urlKey, loadWorker } = options;
1326
+ const sourceKey = source ? `source:${source}` : "";
1327
+ const urlKeyPart = url || urlKey ? `url:${url || urlKey}` : "";
1328
+ const loadWorkerKey = loadWorker ? `loadWorker:${getLoadWorkerId(loadWorker)}` : "";
1329
+ return [name, sourceKey, urlKeyPart, loadWorkerKey].filter(Boolean).join("|");
1330
+ }
1331
+ function getLoadWorkerId(loadWorker) {
1332
+ let loadWorkerId = loadWorkerIds.get(loadWorker);
1333
+ if (!loadWorkerId) {
1334
+ loadWorkerId = nextLoadWorkerId++;
1335
+ loadWorkerIds.set(loadWorker, loadWorkerId);
1336
+ }
1337
+ return loadWorkerId;
1338
+ }
1339
+
1340
+ // ../worker-utils/src/lib/async-queue/async-queue.ts
1341
+ var AsyncQueue = class {
1342
+ _values;
1343
+ _settlers;
1344
+ _closed;
1345
+ constructor() {
1346
+ this._values = [];
1347
+ this._settlers = [];
1348
+ this._closed = false;
1349
+ }
1350
+ /** Return an async iterator for this queue */
1351
+ [Symbol.asyncIterator]() {
1352
+ return this;
1353
+ }
1354
+ /** Push a new value - the async iterator will yield a promise resolved to this value */
1355
+ push(value) {
1356
+ return this.enqueue(value);
1357
+ }
1358
+ /**
1359
+ * Push a new value - the async iterator will yield a promise resolved to this value
1360
+ * Add an error - the async iterator will yield a promise rejected with this value
1361
+ */
1362
+ enqueue(value) {
1363
+ if (this._closed) {
1364
+ throw new Error("Closed");
1365
+ }
1366
+ if (this._settlers.length > 0) {
1367
+ if (this._values.length > 0) {
1368
+ throw new Error("Illegal internal state");
1369
+ }
1370
+ const settler = this._settlers.shift();
1371
+ if (value instanceof Error) {
1372
+ settler.reject(value);
1373
+ } else {
1374
+ settler.resolve({ value });
1375
+ }
1376
+ } else {
1377
+ this._values.push(value);
1378
+ }
1379
+ }
1380
+ /** Indicate that we not waiting for more values - The async iterator will be done */
1381
+ close() {
1382
+ while (this._settlers.length > 0) {
1383
+ const settler = this._settlers.shift();
1384
+ settler.resolve({ done: true });
1385
+ }
1386
+ this._closed = true;
1387
+ }
1388
+ // ITERATOR IMPLEMENTATION
1389
+ /** @returns a Promise for an IteratorResult */
1390
+ next() {
1391
+ if (this._values.length > 0) {
1392
+ const value = this._values.shift();
1393
+ if (value instanceof Error) {
1394
+ return Promise.reject(value);
1395
+ }
1396
+ return Promise.resolve({ done: false, value });
1397
+ }
1398
+ if (this._closed) {
1399
+ if (this._settlers.length > 0) {
1400
+ throw new Error("Illegal internal state");
1401
+ }
1402
+ return Promise.resolve({ done: true, value: void 0 });
1403
+ }
1404
+ return new Promise((resolve2, reject) => {
1405
+ this._settlers.push({ resolve: resolve2, reject });
1406
+ });
1407
+ }
1408
+ };
1272
1409
 
1273
1410
  // ../worker-utils/src/lib/worker-api/get-worker-url.ts
1274
1411
  var warnedWorkerVersionFallbacks = /* @__PURE__ */ new Set();
@@ -1276,34 +1413,41 @@ var __exports__ = (() => {
1276
1413
  const warning = worker.version !== VERSION3 ? ` (worker-utils@${VERSION3})` : "";
1277
1414
  return `${worker.name}@${worker.version}${warning}`;
1278
1415
  }
1279
- function getWorkerURL(worker, options = {}) {
1416
+ function getCustomWorkerURL(worker, options = {}) {
1280
1417
  const workerOptions = options[worker.id] || {};
1281
- const workerFile = isBrowser3 ? `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1418
+ const workerFile = isBrowser3 ? worker.workerFile || `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1282
1419
  let url = workerOptions.workerUrl;
1283
- if (!url && typeof worker.worker === "string") {
1284
- url = worker.worker;
1285
- }
1286
1420
  if (!url && worker.id === "compression") {
1287
1421
  url = options.workerUrl;
1288
1422
  }
1289
1423
  const workerType = options._workerType || options?.core?._workerType;
1290
- if (workerType === "test") {
1424
+ if (!url && workerType === "test") {
1291
1425
  if (isBrowser3) {
1292
1426
  url = `modules/${worker.module}/dist/${workerFile}`;
1293
1427
  } else {
1294
1428
  url = `modules/${worker.module}/src/workers/${worker.id}-worker-node.ts`;
1295
1429
  }
1296
1430
  }
1297
- if (!url) {
1298
- let version2 = worker.version;
1299
- if (version2 === "latest") {
1300
- version2 = NPM_TAG;
1301
- }
1302
- const versionTag = version2 ? `@${version2}` : "";
1303
- url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
1431
+ return url || null;
1432
+ }
1433
+ function getWorkerURL(worker, options = {}) {
1434
+ const customWorkerUrl = getCustomWorkerURL(worker, options);
1435
+ const descriptorWorkerUrl = typeof worker.worker === "string" ? worker.worker : null;
1436
+ const url = customWorkerUrl || descriptorWorkerUrl || getDefaultWorkerURL(worker, true);
1437
+ assert3(url);
1438
+ return url;
1439
+ }
1440
+ function getDefaultWorkerURL(worker, warn = false) {
1441
+ const workerFile = isBrowser3 ? worker.workerFile || `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1442
+ let version2 = worker.version;
1443
+ if (version2 === "latest") {
1444
+ version2 = NPM_TAG;
1445
+ }
1446
+ const versionTag = version2 ? `@${version2}` : "";
1447
+ const url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
1448
+ if (warn) {
1304
1449
  warnIfUsingNpmTagFallback(worker, url);
1305
1450
  }
1306
- assert3(url);
1307
1451
  return url;
1308
1452
  }
1309
1453
  function warnIfUsingNpmTagFallback(worker, url) {
@@ -1326,18 +1470,15 @@ var __exports__ = (() => {
1326
1470
  return false;
1327
1471
  }
1328
1472
  const workerOptions = options?.[worker.id];
1329
- return Boolean((worker.worker || workerOptions?.workerUrl) && options?.worker);
1473
+ return Boolean(
1474
+ (worker.worker || worker.loadWorker || workerOptions?.workerUrl) && options?.worker
1475
+ );
1330
1476
  }
1331
1477
  async function processOnWorker(worker, data, options = {}, context = {}, jobContext = {}) {
1332
1478
  throwIfAborted(options.signal);
1333
1479
  const name = getWorkerName(worker);
1334
1480
  const workerFarm = WorkerFarm.getWorkerFarm(options);
1335
- const { source } = options;
1336
- const workerPoolProps = { name, source };
1337
- if (!source) {
1338
- workerPoolProps.url = getWorkerURL(worker, options);
1339
- }
1340
- const workerPool = workerFarm.getWorkerPool(workerPoolProps);
1481
+ const workerPool = workerFarm.getWorkerPool(getWorkerPoolTarget(worker, options, name));
1341
1482
  const jobName = options.jobName || worker.name;
1342
1483
  const job = await workerPool.startJob(
1343
1484
  jobName,
@@ -1366,6 +1507,114 @@ var __exports__ = (() => {
1366
1507
  options.signal?.removeEventListener("abort", abortJob);
1367
1508
  }
1368
1509
  }
1510
+ function processOnWorkerInBatches(worker, input, options = {}, context = {}, jobContext = {}) {
1511
+ return processOnWorkerInBatchesIterator(worker, input, options, context, jobContext);
1512
+ }
1513
+ async function* processOnWorkerInBatchesIterator(worker, input, options, context, jobContext) {
1514
+ throwIfAborted(options.signal);
1515
+ const name = getWorkerName(worker);
1516
+ const workerFarm = WorkerFarm.getWorkerFarm(options);
1517
+ const workerPool = workerFarm.getWorkerPool(getWorkerPoolTarget(worker, options, name));
1518
+ const outputBatches = new AsyncQueue();
1519
+ const inputIterator = getAsyncIterator(input);
1520
+ let outputFinished = false;
1521
+ let inputFinished = false;
1522
+ let inputRequest = Promise.resolve();
1523
+ const batchJobFailed = new Error("Worker batch job failed");
1524
+ const finishOutput = () => {
1525
+ if (!outputFinished) {
1526
+ outputFinished = true;
1527
+ outputBatches.close();
1528
+ }
1529
+ };
1530
+ const failOutput = (_error) => {
1531
+ if (!outputFinished) {
1532
+ outputFinished = true;
1533
+ outputBatches.enqueue(batchJobFailed);
1534
+ outputBatches.close();
1535
+ }
1536
+ };
1537
+ const job = await workerPool.startJob(
1538
+ options.jobName || worker.name,
1539
+ (activeJob, type, payload) => {
1540
+ switch (type) {
1541
+ case "input-request":
1542
+ inputRequest = inputRequest.then(async () => {
1543
+ const nextBatch = await inputIterator.next();
1544
+ if (!activeJob.isRunning) {
1545
+ return;
1546
+ }
1547
+ if (nextBatch.done) {
1548
+ inputFinished = true;
1549
+ activeJob.postMessage("input-done", {});
1550
+ } else {
1551
+ activeJob.postMessage("input-batch", { input: nextBatch.value });
1552
+ }
1553
+ }).catch((error) => activeJob.abort(error));
1554
+ break;
1555
+ case "output-batch":
1556
+ outputBatches.push(payload.result);
1557
+ break;
1558
+ case "done":
1559
+ activeJob.done(payload);
1560
+ finishOutput();
1561
+ break;
1562
+ case "error": {
1563
+ const error = new Error(payload.error || "Worker batch processing failed");
1564
+ activeJob.error(error);
1565
+ failOutput(error);
1566
+ break;
1567
+ }
1568
+ case "process":
1569
+ void onMessage(context, activeJob, type, payload);
1570
+ break;
1571
+ default: {
1572
+ const error = new Error(`Unexpected worker batch message: ${type}`);
1573
+ activeJob.error(error);
1574
+ failOutput(error);
1575
+ break;
1576
+ }
1577
+ }
1578
+ }
1579
+ );
1580
+ const abortJob = () => job.abort(getAbortReason(options.signal));
1581
+ options.signal?.addEventListener("abort", abortJob, { once: true });
1582
+ if (options.signal?.aborted) {
1583
+ abortJob();
1584
+ }
1585
+ void job.result.catch(failOutput);
1586
+ try {
1587
+ const { signal: _signal, ...workerOptions } = options;
1588
+ if (job.isRunning) {
1589
+ job.postMessage("process-in-batches", {
1590
+ options: getTransferListForWriter(workerOptions),
1591
+ context: getTransferListForWriter(jobContext)
1592
+ });
1593
+ }
1594
+ try {
1595
+ for await (const outputBatch of outputBatches) {
1596
+ yield outputBatch;
1597
+ if (job.isRunning) {
1598
+ job.postMessage("output-ack", {});
1599
+ }
1600
+ }
1601
+ } catch (error) {
1602
+ if (error === batchJobFailed) {
1603
+ await job.result;
1604
+ }
1605
+ throw error;
1606
+ }
1607
+ await job.result;
1608
+ } finally {
1609
+ options.signal?.removeEventListener("abort", abortJob);
1610
+ if (job.isRunning) {
1611
+ job.abort(createAbortError2("Worker batch iterator was closed"));
1612
+ }
1613
+ if (!inputFinished) {
1614
+ closeInputIterator(inputIterator);
1615
+ }
1616
+ }
1617
+ }
1369
1618
  function throwIfAborted(signal) {
1370
1619
  if (!signal?.aborted) {
1371
1620
  return;
@@ -1380,6 +1629,38 @@ var __exports__ = (() => {
1380
1629
  error.name = "AbortError";
1381
1630
  return error;
1382
1631
  }
1632
+ function getAsyncIterator(input) {
1633
+ if (Symbol.asyncIterator in input) {
1634
+ return input[Symbol.asyncIterator]();
1635
+ }
1636
+ return (async function* iterateSynchronously() {
1637
+ yield* input;
1638
+ })();
1639
+ }
1640
+ function closeInputIterator(inputIterator) {
1641
+ try {
1642
+ void Promise.resolve(inputIterator.return?.()).catch(() => void 0);
1643
+ } catch {
1644
+ }
1645
+ }
1646
+ function getWorkerPoolTarget(worker, options, name) {
1647
+ if (options.source) {
1648
+ return { name, source: options.source };
1649
+ }
1650
+ const customWorkerUrl = getCustomWorkerURL(worker, options);
1651
+ if (customWorkerUrl) {
1652
+ return { name, url: customWorkerUrl };
1653
+ }
1654
+ if (isBrowser3 && worker.loadWorker) {
1655
+ return {
1656
+ name,
1657
+ loadWorker: worker.loadWorker,
1658
+ getUrl: () => getWorkerURL(worker, options),
1659
+ urlKey: getDefaultWorkerURL(worker)
1660
+ };
1661
+ }
1662
+ return { name, url: getWorkerURL(worker, options) };
1663
+ }
1383
1664
  async function onMessage(context, job, type, payload) {
1384
1665
  switch (type) {
1385
1666
  case "done":
@@ -1424,7 +1705,7 @@ var __exports__ = (() => {
1424
1705
  if (!isBrowser3 && !nodeWorkers) {
1425
1706
  return false;
1426
1707
  }
1427
- if (loader.id === "excel" && options?.excel?.shape === "arrow-table" || loader.id === "ply" && options?.ply?.shape === "arrow-table") {
1708
+ if (loader.id === "las" && (options?.las?.shape ?? "arrow-table") === "arrow-table") {
1428
1709
  return false;
1429
1710
  }
1430
1711
  if (loader.id === "csv" && !shouldParseCSVWithWorker(options)) {
@@ -1432,12 +1713,29 @@ var __exports__ = (() => {
1432
1713
  }
1433
1714
  return Boolean(canProcessOnWorker(loader, workerOptions));
1434
1715
  }
1716
+ function shouldParseWithWorker(loader, data, options, context, estimateLoader = loader) {
1717
+ if (!canParseWithWorker(loader, options)) {
1718
+ return false;
1719
+ }
1720
+ if (options?.core?.worker !== "auto" || !estimateLoader.getWorkerEstimate) {
1721
+ return true;
1722
+ }
1723
+ try {
1724
+ const estimate = estimateLoader.getWorkerEstimate(data, options, context);
1725
+ if (estimate === void 0 || !Number.isFinite(estimate) || estimate < 0 || estimate > 1) {
1726
+ return true;
1727
+ }
1728
+ return estimate >= (options.core?.workerThreshold ?? 0.1);
1729
+ } catch {
1730
+ return true;
1731
+ }
1732
+ }
1435
1733
  async function parseWithWorker(loader, data, options, context, parseOnMainThread, signal) {
1436
1734
  const workerSignal = signal || getWorkerAbortSignal(options);
1437
1735
  const result = await processOnWorker(
1438
1736
  loader,
1439
1737
  data,
1440
- { ...getWorkerOptions(options), signal: workerSignal },
1738
+ { ...getWorkerOptions(options, loader), signal: workerSignal },
1441
1739
  {
1442
1740
  process: async (input, processOptions, _workerContext, parseContext) => {
1443
1741
  if (!parseOnMainThread) {
@@ -1456,6 +1754,32 @@ var __exports__ = (() => {
1456
1754
  );
1457
1755
  return isLoaderWithWorkerResultDeserializer(loader) ? loader.deserializeWorkerResult(result, options, context) : result;
1458
1756
  }
1757
+ async function* parseWithWorkerInBatches(loader, inputIterator, options, context, parseOnMainThread, signal) {
1758
+ const workerSignal = signal || getWorkerAbortSignal(options);
1759
+ const outputIterator = processOnWorkerInBatches(
1760
+ loader,
1761
+ inputIterator,
1762
+ { ...getWorkerOptions(options), signal: workerSignal },
1763
+ {
1764
+ process: async (input, processOptions, _workerContext, parseContext) => {
1765
+ if (!parseOnMainThread) {
1766
+ throw new Error("Worker not set up to parse on main thread");
1767
+ }
1768
+ const mainThreadContext = context ? { ...context, ...parseContext || {} } : void 0;
1769
+ return await callParseOnMainThread(
1770
+ parseOnMainThread,
1771
+ input,
1772
+ processOptions,
1773
+ mainThreadContext
1774
+ );
1775
+ }
1776
+ },
1777
+ getSerializableLoaderContext(context)
1778
+ );
1779
+ for await (const batch of outputIterator) {
1780
+ yield loader.deserializeWorkerBatch ? loader.deserializeWorkerBatch(batch, options, context) : batch;
1781
+ }
1782
+ }
1459
1783
  function getWorkerAbortSignal(options) {
1460
1784
  const parquetSignal = options?.parquet?.signal;
1461
1785
  if (typeof AbortSignal !== "undefined" && parquetSignal instanceof AbortSignal) {
@@ -1469,12 +1793,19 @@ var __exports__ = (() => {
1469
1793
  }
1470
1794
  return parseOnMainThread(input, void 0, options, context);
1471
1795
  }
1472
- function getWorkerOptions(options = {}) {
1796
+ function getWorkerOptions(options = {}, loader) {
1473
1797
  const serializedOptions = JSON.parse(JSON.stringify(options));
1474
- return {
1798
+ const workerOptions = {
1475
1799
  ...serializedOptions.core,
1476
1800
  ...serializedOptions
1477
1801
  };
1802
+ if (workerOptions.worker === "auto") {
1803
+ workerOptions.worker = true;
1804
+ }
1805
+ if (loader) {
1806
+ workerOptions._workerLoaderId = loader.id;
1807
+ }
1808
+ return workerOptions;
1478
1809
  }
1479
1810
  function getSerializableLoaderContext(context) {
1480
1811
  if (!context) {
@@ -2728,6 +3059,7 @@ var __exports__ = (() => {
2728
3059
  CDN: "https://unpkg.com/@loaders.gl",
2729
3060
  worker: true,
2730
3061
  // By default, use worker if provided by loader.
3062
+ workerThreshold: 0.1,
2731
3063
  maxConcurrency: 3,
2732
3064
  // How many worker instances should be created for each loader.
2733
3065
  maxMobileConcurrency: 1,
@@ -2803,6 +3135,7 @@ var __exports__ = (() => {
2803
3135
  "useLocalLibraries",
2804
3136
  "CDN",
2805
3137
  "worker",
3138
+ "workerThreshold",
2806
3139
  "maxConcurrency",
2807
3140
  "maxMobileConcurrency",
2808
3141
  "reuseWorkers",
@@ -2843,7 +3176,10 @@ var __exports__ = (() => {
2843
3176
  loaders = loaders || [];
2844
3177
  loaders = Array.isArray(loaders) ? loaders : [loaders];
2845
3178
  validateOptions(options, loaders);
2846
- return normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
3179
+ validateWorkerThreshold(options);
3180
+ const normalizedOptions = normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
3181
+ validateWorkerThreshold(normalizedOptions);
3182
+ return normalizedOptions;
2847
3183
  }
2848
3184
  function normalizeLoaderOptions(options) {
2849
3185
  const normalized = cloneLoaderOptions(options);
@@ -2867,6 +3203,12 @@ var __exports__ = (() => {
2867
3203
  validateOptionsObject(idOptions, loader.id, loaderOptions, deprecatedOptions, loaders);
2868
3204
  }
2869
3205
  }
3206
+ function validateWorkerThreshold(options) {
3207
+ const threshold = options.core?.workerThreshold;
3208
+ if (threshold !== void 0 && (!Number.isFinite(threshold) || threshold < 0 || threshold > 1)) {
3209
+ throw new Error("core.workerThreshold must be a finite number between 0 and 1");
3210
+ }
3211
+ }
2870
3212
  function validateOptionsObject(options, id, defaultOptions, deprecatedOptions, loaders) {
2871
3213
  const loaderName = id || "Top level";
2872
3214
  const prefix = id ? `${id}.` : "";
@@ -3580,7 +3922,8 @@ var __exports__ = (() => {
3580
3922
  if (typeof fetchOption === "function") {
3581
3923
  fetchFunction = fetchOption;
3582
3924
  } else if (isObject(fetchOption)) {
3583
- fetchFunction = (url, requestOptions) => fetchFile(url, mergeFetchOptions(fetchOption, requestOptions));
3925
+ const baseFetch = context?.fetch || fetchFile;
3926
+ fetchFunction = (url, requestOptions) => baseFetch(url, mergeFetchOptions(fetchOption, requestOptions));
3584
3927
  } else if (context?.fetch) {
3585
3928
  fetchFunction = context.fetch;
3586
3929
  } else {
@@ -3898,6 +4241,9 @@ var __exports__ = (() => {
3898
4241
  options?.core?.transforms || []
3899
4242
  );
3900
4243
  if (loader.parseInBatches) {
4244
+ if (loader.id === "csv" && isBrowser && canParseWithWorker(loader, options)) {
4245
+ return parseWithWorkerInBatches(loader, transformedIterator, options, context, parse);
4246
+ }
3901
4247
  return loader.parseInBatches(transformedIterator, options, context);
3902
4248
  }
3903
4249
  return parseChunkInBatches(transformedIterator, loader, options, context);
@@ -4084,7 +4430,10 @@ var __exports__ = (() => {
4084
4430
  // src/lib/loader-utils/loader-context.ts
4085
4431
  function getLoaderContext(context, options, parentContext) {
4086
4432
  if (parentContext) {
4087
- return parentContext;
4433
+ return {
4434
+ ...parentContext,
4435
+ fetch: getFetchFunction(options, parentContext)
4436
+ };
4088
4437
  }
4089
4438
  const newContext = {
4090
4439
  ...context,
@@ -4157,7 +4506,7 @@ var __exports__ = (() => {
4157
4506
  context.response = { headers, ok, redirected, status, statusText, type, url };
4158
4507
  }
4159
4508
  const loaderWithParser = await getLoaderImplementation(loader, options, context.url);
4160
- if (canParseWithWorker(loaderWithParser, options)) {
4509
+ if (shouldParseWithWorker(loaderWithParser, data, options, context, loader)) {
4161
4510
  data = await getArrayBufferFromData(data, options);
4162
4511
  return await parseWithWorker(loaderWithParser, data, options, context, parse);
4163
4512
  }