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

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 +379 -41
  2. package/dist/dist.min.js +3 -3
  3. package/dist/index.cjs +385 -42
  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 = () => {
@@ -1070,6 +1097,8 @@ var __exports__ = (() => {
1070
1097
  constructor(props) {
1071
1098
  this.source = props.source;
1072
1099
  this.url = props.url;
1100
+ this.getUrl = props.getUrl;
1101
+ this.loadWorker = props.loadWorker;
1073
1102
  this.setProps(props);
1074
1103
  }
1075
1104
  /**
@@ -1179,7 +1208,13 @@ var __exports__ = (() => {
1179
1208
  if (this.count < this._getMaxConcurrency()) {
1180
1209
  this.count++;
1181
1210
  const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`;
1182
- return new WorkerThread({ name, source: this.source, url: this.url });
1211
+ return new WorkerThread({
1212
+ name,
1213
+ source: this.source,
1214
+ url: this.url,
1215
+ getUrl: this.getUrl,
1216
+ loadWorker: this.loadWorker
1217
+ });
1183
1218
  }
1184
1219
  return null;
1185
1220
  }
@@ -1196,6 +1231,8 @@ var __exports__ = (() => {
1196
1231
  onDebug: () => {
1197
1232
  }
1198
1233
  };
1234
+ var loadWorkerIds = /* @__PURE__ */ new WeakMap();
1235
+ var nextLoadWorkerId = 1;
1199
1236
  var WorkerFarm = class _WorkerFarm {
1200
1237
  props;
1201
1238
  workerPools = /* @__PURE__ */ new Map();
@@ -1239,24 +1276,28 @@ var __exports__ = (() => {
1239
1276
  }
1240
1277
  /**
1241
1278
  * 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 -
1279
+ * @param options Worker target used to identify and initialize the pool.
1280
+ * @param options.name Worker name used as the base pool identity.
1281
+ * @param options.url Worker script URL.
1282
+ * @param options.source Inline worker source.
1283
+ * @param options.loadWorker Built-in browser worker factory.
1246
1284
  * @example
1247
1285
  * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...);
1248
1286
  */
1249
1287
  getWorkerPool(options) {
1250
- const { name, source, url } = options;
1251
- let workerPool = this.workerPools.get(name);
1288
+ const { name, source, url, getUrl, loadWorker } = options;
1289
+ const workerPoolKey = getWorkerPoolKey(options);
1290
+ let workerPool = this.workerPools.get(workerPoolKey);
1252
1291
  if (!workerPool) {
1253
1292
  workerPool = new WorkerPool({
1254
1293
  name,
1255
1294
  source,
1256
- url
1295
+ url,
1296
+ getUrl,
1297
+ loadWorker
1257
1298
  });
1258
1299
  workerPool.setProps(this._getWorkerPoolProps());
1259
- this.workerPools.set(name, workerPool);
1300
+ this.workerPools.set(workerPoolKey, workerPool);
1260
1301
  }
1261
1302
  return workerPool;
1262
1303
  }
@@ -1269,6 +1310,91 @@ var __exports__ = (() => {
1269
1310
  };
1270
1311
  }
1271
1312
  };
1313
+ function getWorkerPoolKey(options) {
1314
+ const { name, source, url, urlKey, loadWorker } = options;
1315
+ const sourceKey = source ? `source:${source}` : "";
1316
+ const urlKeyPart = url || urlKey ? `url:${url || urlKey}` : "";
1317
+ const loadWorkerKey = loadWorker ? `loadWorker:${getLoadWorkerId(loadWorker)}` : "";
1318
+ return [name, sourceKey, urlKeyPart, loadWorkerKey].filter(Boolean).join("|");
1319
+ }
1320
+ function getLoadWorkerId(loadWorker) {
1321
+ let loadWorkerId = loadWorkerIds.get(loadWorker);
1322
+ if (!loadWorkerId) {
1323
+ loadWorkerId = nextLoadWorkerId++;
1324
+ loadWorkerIds.set(loadWorker, loadWorkerId);
1325
+ }
1326
+ return loadWorkerId;
1327
+ }
1328
+
1329
+ // ../worker-utils/src/lib/async-queue/async-queue.ts
1330
+ var AsyncQueue = class {
1331
+ _values;
1332
+ _settlers;
1333
+ _closed;
1334
+ constructor() {
1335
+ this._values = [];
1336
+ this._settlers = [];
1337
+ this._closed = false;
1338
+ }
1339
+ /** Return an async iterator for this queue */
1340
+ [Symbol.asyncIterator]() {
1341
+ return this;
1342
+ }
1343
+ /** Push a new value - the async iterator will yield a promise resolved to this value */
1344
+ push(value) {
1345
+ return this.enqueue(value);
1346
+ }
1347
+ /**
1348
+ * Push a new value - the async iterator will yield a promise resolved to this value
1349
+ * Add an error - the async iterator will yield a promise rejected with this value
1350
+ */
1351
+ enqueue(value) {
1352
+ if (this._closed) {
1353
+ throw new Error("Closed");
1354
+ }
1355
+ if (this._settlers.length > 0) {
1356
+ if (this._values.length > 0) {
1357
+ throw new Error("Illegal internal state");
1358
+ }
1359
+ const settler = this._settlers.shift();
1360
+ if (value instanceof Error) {
1361
+ settler.reject(value);
1362
+ } else {
1363
+ settler.resolve({ value });
1364
+ }
1365
+ } else {
1366
+ this._values.push(value);
1367
+ }
1368
+ }
1369
+ /** Indicate that we not waiting for more values - The async iterator will be done */
1370
+ close() {
1371
+ while (this._settlers.length > 0) {
1372
+ const settler = this._settlers.shift();
1373
+ settler.resolve({ done: true });
1374
+ }
1375
+ this._closed = true;
1376
+ }
1377
+ // ITERATOR IMPLEMENTATION
1378
+ /** @returns a Promise for an IteratorResult */
1379
+ next() {
1380
+ if (this._values.length > 0) {
1381
+ const value = this._values.shift();
1382
+ if (value instanceof Error) {
1383
+ return Promise.reject(value);
1384
+ }
1385
+ return Promise.resolve({ done: false, value });
1386
+ }
1387
+ if (this._closed) {
1388
+ if (this._settlers.length > 0) {
1389
+ throw new Error("Illegal internal state");
1390
+ }
1391
+ return Promise.resolve({ done: true, value: void 0 });
1392
+ }
1393
+ return new Promise((resolve2, reject) => {
1394
+ this._settlers.push({ resolve: resolve2, reject });
1395
+ });
1396
+ }
1397
+ };
1272
1398
 
1273
1399
  // ../worker-utils/src/lib/worker-api/get-worker-url.ts
1274
1400
  var warnedWorkerVersionFallbacks = /* @__PURE__ */ new Set();
@@ -1276,34 +1402,41 @@ var __exports__ = (() => {
1276
1402
  const warning = worker.version !== VERSION3 ? ` (worker-utils@${VERSION3})` : "";
1277
1403
  return `${worker.name}@${worker.version}${warning}`;
1278
1404
  }
1279
- function getWorkerURL(worker, options = {}) {
1405
+ function getCustomWorkerURL(worker, options = {}) {
1280
1406
  const workerOptions = options[worker.id] || {};
1281
- const workerFile = isBrowser3 ? `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1407
+ const workerFile = isBrowser3 ? worker.workerFile || `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1282
1408
  let url = workerOptions.workerUrl;
1283
- if (!url && typeof worker.worker === "string") {
1284
- url = worker.worker;
1285
- }
1286
1409
  if (!url && worker.id === "compression") {
1287
1410
  url = options.workerUrl;
1288
1411
  }
1289
1412
  const workerType = options._workerType || options?.core?._workerType;
1290
- if (workerType === "test") {
1413
+ if (!url && workerType === "test") {
1291
1414
  if (isBrowser3) {
1292
1415
  url = `modules/${worker.module}/dist/${workerFile}`;
1293
1416
  } else {
1294
1417
  url = `modules/${worker.module}/src/workers/${worker.id}-worker-node.ts`;
1295
1418
  }
1296
1419
  }
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}`;
1420
+ return url || null;
1421
+ }
1422
+ function getWorkerURL(worker, options = {}) {
1423
+ const customWorkerUrl = getCustomWorkerURL(worker, options);
1424
+ const descriptorWorkerUrl = typeof worker.worker === "string" ? worker.worker : null;
1425
+ const url = customWorkerUrl || descriptorWorkerUrl || getDefaultWorkerURL(worker, true);
1426
+ assert3(url);
1427
+ return url;
1428
+ }
1429
+ function getDefaultWorkerURL(worker, warn = false) {
1430
+ const workerFile = isBrowser3 ? worker.workerFile || `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1431
+ let version2 = worker.version;
1432
+ if (version2 === "latest") {
1433
+ version2 = NPM_TAG;
1434
+ }
1435
+ const versionTag = version2 ? `@${version2}` : "";
1436
+ const url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
1437
+ if (warn) {
1304
1438
  warnIfUsingNpmTagFallback(worker, url);
1305
1439
  }
1306
- assert3(url);
1307
1440
  return url;
1308
1441
  }
1309
1442
  function warnIfUsingNpmTagFallback(worker, url) {
@@ -1326,18 +1459,15 @@ var __exports__ = (() => {
1326
1459
  return false;
1327
1460
  }
1328
1461
  const workerOptions = options?.[worker.id];
1329
- return Boolean((worker.worker || workerOptions?.workerUrl) && options?.worker);
1462
+ return Boolean(
1463
+ (worker.worker || worker.loadWorker || workerOptions?.workerUrl) && options?.worker
1464
+ );
1330
1465
  }
1331
1466
  async function processOnWorker(worker, data, options = {}, context = {}, jobContext = {}) {
1332
1467
  throwIfAborted(options.signal);
1333
1468
  const name = getWorkerName(worker);
1334
1469
  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);
1470
+ const workerPool = workerFarm.getWorkerPool(getWorkerPoolTarget(worker, options, name));
1341
1471
  const jobName = options.jobName || worker.name;
1342
1472
  const job = await workerPool.startJob(
1343
1473
  jobName,
@@ -1366,6 +1496,114 @@ var __exports__ = (() => {
1366
1496
  options.signal?.removeEventListener("abort", abortJob);
1367
1497
  }
1368
1498
  }
1499
+ function processOnWorkerInBatches(worker, input, options = {}, context = {}, jobContext = {}) {
1500
+ return processOnWorkerInBatchesIterator(worker, input, options, context, jobContext);
1501
+ }
1502
+ async function* processOnWorkerInBatchesIterator(worker, input, options, context, jobContext) {
1503
+ throwIfAborted(options.signal);
1504
+ const name = getWorkerName(worker);
1505
+ const workerFarm = WorkerFarm.getWorkerFarm(options);
1506
+ const workerPool = workerFarm.getWorkerPool(getWorkerPoolTarget(worker, options, name));
1507
+ const outputBatches = new AsyncQueue();
1508
+ const inputIterator = getAsyncIterator(input);
1509
+ let outputFinished = false;
1510
+ let inputFinished = false;
1511
+ let inputRequest = Promise.resolve();
1512
+ const batchJobFailed = new Error("Worker batch job failed");
1513
+ const finishOutput = () => {
1514
+ if (!outputFinished) {
1515
+ outputFinished = true;
1516
+ outputBatches.close();
1517
+ }
1518
+ };
1519
+ const failOutput = (_error) => {
1520
+ if (!outputFinished) {
1521
+ outputFinished = true;
1522
+ outputBatches.enqueue(batchJobFailed);
1523
+ outputBatches.close();
1524
+ }
1525
+ };
1526
+ const job = await workerPool.startJob(
1527
+ options.jobName || worker.name,
1528
+ (activeJob, type, payload) => {
1529
+ switch (type) {
1530
+ case "input-request":
1531
+ inputRequest = inputRequest.then(async () => {
1532
+ const nextBatch = await inputIterator.next();
1533
+ if (!activeJob.isRunning) {
1534
+ return;
1535
+ }
1536
+ if (nextBatch.done) {
1537
+ inputFinished = true;
1538
+ activeJob.postMessage("input-done", {});
1539
+ } else {
1540
+ activeJob.postMessage("input-batch", { input: nextBatch.value });
1541
+ }
1542
+ }).catch((error) => activeJob.abort(error));
1543
+ break;
1544
+ case "output-batch":
1545
+ outputBatches.push(payload.result);
1546
+ break;
1547
+ case "done":
1548
+ activeJob.done(payload);
1549
+ finishOutput();
1550
+ break;
1551
+ case "error": {
1552
+ const error = new Error(payload.error || "Worker batch processing failed");
1553
+ activeJob.error(error);
1554
+ failOutput(error);
1555
+ break;
1556
+ }
1557
+ case "process":
1558
+ void onMessage(context, activeJob, type, payload);
1559
+ break;
1560
+ default: {
1561
+ const error = new Error(`Unexpected worker batch message: ${type}`);
1562
+ activeJob.error(error);
1563
+ failOutput(error);
1564
+ break;
1565
+ }
1566
+ }
1567
+ }
1568
+ );
1569
+ const abortJob = () => job.abort(getAbortReason(options.signal));
1570
+ options.signal?.addEventListener("abort", abortJob, { once: true });
1571
+ if (options.signal?.aborted) {
1572
+ abortJob();
1573
+ }
1574
+ void job.result.catch(failOutput);
1575
+ try {
1576
+ const { signal: _signal, ...workerOptions } = options;
1577
+ if (job.isRunning) {
1578
+ job.postMessage("process-in-batches", {
1579
+ options: getTransferListForWriter(workerOptions),
1580
+ context: getTransferListForWriter(jobContext)
1581
+ });
1582
+ }
1583
+ try {
1584
+ for await (const outputBatch of outputBatches) {
1585
+ yield outputBatch;
1586
+ if (job.isRunning) {
1587
+ job.postMessage("output-ack", {});
1588
+ }
1589
+ }
1590
+ } catch (error) {
1591
+ if (error === batchJobFailed) {
1592
+ await job.result;
1593
+ }
1594
+ throw error;
1595
+ }
1596
+ await job.result;
1597
+ } finally {
1598
+ options.signal?.removeEventListener("abort", abortJob);
1599
+ if (job.isRunning) {
1600
+ job.abort(createAbortError2("Worker batch iterator was closed"));
1601
+ }
1602
+ if (!inputFinished) {
1603
+ closeInputIterator(inputIterator);
1604
+ }
1605
+ }
1606
+ }
1369
1607
  function throwIfAborted(signal) {
1370
1608
  if (!signal?.aborted) {
1371
1609
  return;
@@ -1380,6 +1618,38 @@ var __exports__ = (() => {
1380
1618
  error.name = "AbortError";
1381
1619
  return error;
1382
1620
  }
1621
+ function getAsyncIterator(input) {
1622
+ if (Symbol.asyncIterator in input) {
1623
+ return input[Symbol.asyncIterator]();
1624
+ }
1625
+ return (async function* iterateSynchronously() {
1626
+ yield* input;
1627
+ })();
1628
+ }
1629
+ function closeInputIterator(inputIterator) {
1630
+ try {
1631
+ void Promise.resolve(inputIterator.return?.()).catch(() => void 0);
1632
+ } catch {
1633
+ }
1634
+ }
1635
+ function getWorkerPoolTarget(worker, options, name) {
1636
+ if (options.source) {
1637
+ return { name, source: options.source };
1638
+ }
1639
+ const customWorkerUrl = getCustomWorkerURL(worker, options);
1640
+ if (customWorkerUrl) {
1641
+ return { name, url: customWorkerUrl };
1642
+ }
1643
+ if (isBrowser3 && worker.loadWorker) {
1644
+ return {
1645
+ name,
1646
+ loadWorker: worker.loadWorker,
1647
+ getUrl: () => getWorkerURL(worker, options),
1648
+ urlKey: getDefaultWorkerURL(worker)
1649
+ };
1650
+ }
1651
+ return { name, url: getWorkerURL(worker, options) };
1652
+ }
1383
1653
  async function onMessage(context, job, type, payload) {
1384
1654
  switch (type) {
1385
1655
  case "done":
@@ -1432,12 +1702,29 @@ var __exports__ = (() => {
1432
1702
  }
1433
1703
  return Boolean(canProcessOnWorker(loader, workerOptions));
1434
1704
  }
1705
+ function shouldParseWithWorker(loader, data, options, context, estimateLoader = loader) {
1706
+ if (!canParseWithWorker(loader, options)) {
1707
+ return false;
1708
+ }
1709
+ if (options?.core?.worker !== "auto" || !estimateLoader.getWorkerEstimate) {
1710
+ return true;
1711
+ }
1712
+ try {
1713
+ const estimate = estimateLoader.getWorkerEstimate(data, options, context);
1714
+ if (estimate === void 0 || !Number.isFinite(estimate) || estimate < 0 || estimate > 1) {
1715
+ return true;
1716
+ }
1717
+ return estimate >= (options.core?.workerThreshold ?? 0.1);
1718
+ } catch {
1719
+ return true;
1720
+ }
1721
+ }
1435
1722
  async function parseWithWorker(loader, data, options, context, parseOnMainThread, signal) {
1436
1723
  const workerSignal = signal || getWorkerAbortSignal(options);
1437
1724
  const result = await processOnWorker(
1438
1725
  loader,
1439
1726
  data,
1440
- { ...getWorkerOptions(options), signal: workerSignal },
1727
+ { ...getWorkerOptions(options, loader), signal: workerSignal },
1441
1728
  {
1442
1729
  process: async (input, processOptions, _workerContext, parseContext) => {
1443
1730
  if (!parseOnMainThread) {
@@ -1456,6 +1743,32 @@ var __exports__ = (() => {
1456
1743
  );
1457
1744
  return isLoaderWithWorkerResultDeserializer(loader) ? loader.deserializeWorkerResult(result, options, context) : result;
1458
1745
  }
1746
+ async function* parseWithWorkerInBatches(loader, inputIterator, options, context, parseOnMainThread, signal) {
1747
+ const workerSignal = signal || getWorkerAbortSignal(options);
1748
+ const outputIterator = processOnWorkerInBatches(
1749
+ loader,
1750
+ inputIterator,
1751
+ { ...getWorkerOptions(options), signal: workerSignal },
1752
+ {
1753
+ process: async (input, processOptions, _workerContext, parseContext) => {
1754
+ if (!parseOnMainThread) {
1755
+ throw new Error("Worker not set up to parse on main thread");
1756
+ }
1757
+ const mainThreadContext = context ? { ...context, ...parseContext || {} } : void 0;
1758
+ return await callParseOnMainThread(
1759
+ parseOnMainThread,
1760
+ input,
1761
+ processOptions,
1762
+ mainThreadContext
1763
+ );
1764
+ }
1765
+ },
1766
+ getSerializableLoaderContext(context)
1767
+ );
1768
+ for await (const batch of outputIterator) {
1769
+ yield loader.deserializeWorkerBatch ? loader.deserializeWorkerBatch(batch, options, context) : batch;
1770
+ }
1771
+ }
1459
1772
  function getWorkerAbortSignal(options) {
1460
1773
  const parquetSignal = options?.parquet?.signal;
1461
1774
  if (typeof AbortSignal !== "undefined" && parquetSignal instanceof AbortSignal) {
@@ -1469,12 +1782,19 @@ var __exports__ = (() => {
1469
1782
  }
1470
1783
  return parseOnMainThread(input, void 0, options, context);
1471
1784
  }
1472
- function getWorkerOptions(options = {}) {
1785
+ function getWorkerOptions(options = {}, loader) {
1473
1786
  const serializedOptions = JSON.parse(JSON.stringify(options));
1474
- return {
1787
+ const workerOptions = {
1475
1788
  ...serializedOptions.core,
1476
1789
  ...serializedOptions
1477
1790
  };
1791
+ if (workerOptions.worker === "auto") {
1792
+ workerOptions.worker = true;
1793
+ }
1794
+ if (loader) {
1795
+ workerOptions._workerLoaderId = loader.id;
1796
+ }
1797
+ return workerOptions;
1478
1798
  }
1479
1799
  function getSerializableLoaderContext(context) {
1480
1800
  if (!context) {
@@ -2728,6 +3048,7 @@ var __exports__ = (() => {
2728
3048
  CDN: "https://unpkg.com/@loaders.gl",
2729
3049
  worker: true,
2730
3050
  // By default, use worker if provided by loader.
3051
+ workerThreshold: 0.1,
2731
3052
  maxConcurrency: 3,
2732
3053
  // How many worker instances should be created for each loader.
2733
3054
  maxMobileConcurrency: 1,
@@ -2803,6 +3124,7 @@ var __exports__ = (() => {
2803
3124
  "useLocalLibraries",
2804
3125
  "CDN",
2805
3126
  "worker",
3127
+ "workerThreshold",
2806
3128
  "maxConcurrency",
2807
3129
  "maxMobileConcurrency",
2808
3130
  "reuseWorkers",
@@ -2843,7 +3165,10 @@ var __exports__ = (() => {
2843
3165
  loaders = loaders || [];
2844
3166
  loaders = Array.isArray(loaders) ? loaders : [loaders];
2845
3167
  validateOptions(options, loaders);
2846
- return normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
3168
+ validateWorkerThreshold(options);
3169
+ const normalizedOptions = normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
3170
+ validateWorkerThreshold(normalizedOptions);
3171
+ return normalizedOptions;
2847
3172
  }
2848
3173
  function normalizeLoaderOptions(options) {
2849
3174
  const normalized = cloneLoaderOptions(options);
@@ -2867,6 +3192,12 @@ var __exports__ = (() => {
2867
3192
  validateOptionsObject(idOptions, loader.id, loaderOptions, deprecatedOptions, loaders);
2868
3193
  }
2869
3194
  }
3195
+ function validateWorkerThreshold(options) {
3196
+ const threshold = options.core?.workerThreshold;
3197
+ if (threshold !== void 0 && (!Number.isFinite(threshold) || threshold < 0 || threshold > 1)) {
3198
+ throw new Error("core.workerThreshold must be a finite number between 0 and 1");
3199
+ }
3200
+ }
2870
3201
  function validateOptionsObject(options, id, defaultOptions, deprecatedOptions, loaders) {
2871
3202
  const loaderName = id || "Top level";
2872
3203
  const prefix = id ? `${id}.` : "";
@@ -3580,7 +3911,8 @@ var __exports__ = (() => {
3580
3911
  if (typeof fetchOption === "function") {
3581
3912
  fetchFunction = fetchOption;
3582
3913
  } else if (isObject(fetchOption)) {
3583
- fetchFunction = (url, requestOptions) => fetchFile(url, mergeFetchOptions(fetchOption, requestOptions));
3914
+ const baseFetch = context?.fetch || fetchFile;
3915
+ fetchFunction = (url, requestOptions) => baseFetch(url, mergeFetchOptions(fetchOption, requestOptions));
3584
3916
  } else if (context?.fetch) {
3585
3917
  fetchFunction = context.fetch;
3586
3918
  } else {
@@ -3898,6 +4230,9 @@ var __exports__ = (() => {
3898
4230
  options?.core?.transforms || []
3899
4231
  );
3900
4232
  if (loader.parseInBatches) {
4233
+ if (loader.id === "csv" && isBrowser && canParseWithWorker(loader, options)) {
4234
+ return parseWithWorkerInBatches(loader, transformedIterator, options, context, parse);
4235
+ }
3901
4236
  return loader.parseInBatches(transformedIterator, options, context);
3902
4237
  }
3903
4238
  return parseChunkInBatches(transformedIterator, loader, options, context);
@@ -4084,7 +4419,10 @@ var __exports__ = (() => {
4084
4419
  // src/lib/loader-utils/loader-context.ts
4085
4420
  function getLoaderContext(context, options, parentContext) {
4086
4421
  if (parentContext) {
4087
- return parentContext;
4422
+ return {
4423
+ ...parentContext,
4424
+ fetch: getFetchFunction(options, parentContext)
4425
+ };
4088
4426
  }
4089
4427
  const newContext = {
4090
4428
  ...context,
@@ -4157,7 +4495,7 @@ var __exports__ = (() => {
4157
4495
  context.response = { headers, ok, redirected, status, statusText, type, url };
4158
4496
  }
4159
4497
  const loaderWithParser = await getLoaderImplementation(loader, options, context.url);
4160
- if (canParseWithWorker(loaderWithParser, options)) {
4498
+ if (shouldParseWithWorker(loaderWithParser, data, options, context, loader)) {
4161
4499
  data = await getArrayBufferFromData(data, options);
4162
4500
  return await parseWithWorker(loaderWithParser, data, options, context, parse);
4163
4501
  }