@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/index.cjs CHANGED
@@ -401,6 +401,10 @@ var WorkerThread = class {
401
401
  name;
402
402
  source;
403
403
  url;
404
+ /** Lazily resolves the classic worker URL used as a fallback. */
405
+ getUrl;
406
+ /** Creates a browser Worker directly. */
407
+ loadWorker;
404
408
  terminated = false;
405
409
  worker;
406
410
  onMessage;
@@ -411,11 +415,13 @@ var WorkerThread = class {
411
415
  return typeof Worker !== "undefined" && isBrowser2 || typeof NodeWorker !== "undefined" && !isBrowser2;
412
416
  }
413
417
  constructor(props) {
414
- const { name, source, url } = props;
415
- assert2(source || url);
418
+ const { name, source, url, getUrl, loadWorker } = props;
419
+ assert2(source || url || getUrl || loadWorker);
416
420
  this.name = name;
417
421
  this.source = source;
418
422
  this.url = url;
423
+ this.getUrl = getUrl;
424
+ this.loadWorker = loadWorker;
419
425
  this.onMessage = NOOP;
420
426
  this.onError = (error) => console.log(error);
421
427
  this.worker = isBrowser2 ? this._createBrowserWorker() : this._createNodeWorker();
@@ -461,7 +467,7 @@ var WorkerThread = class {
461
467
  */
462
468
  _getErrorFromErrorEvent(event) {
463
469
  let message = "Failed to load ";
464
- message += `worker ${this.name} from ${this.url}. `;
470
+ message += `worker ${this.name} from ${this.url || "built-in worker factory"}. `;
465
471
  if (event.message) {
466
472
  message += `${event.message} in `;
467
473
  }
@@ -474,8 +480,26 @@ var WorkerThread = class {
474
480
  * Creates a worker thread on the browser
475
481
  */
476
482
  _createBrowserWorker() {
477
- this._loadableURL = getLoadableWorkerURL({ source: this.source, url: this.url });
483
+ var _a;
484
+ if (this.loadWorker) {
485
+ try {
486
+ const worker2 = this.loadWorker();
487
+ if (worker2) {
488
+ return this._initializeBrowserWorker(worker2);
489
+ }
490
+ } catch (error) {
491
+ if (!this.source && !this.url && !this.getUrl) {
492
+ throw error;
493
+ }
494
+ }
495
+ }
496
+ const url = this.url || ((_a = this.getUrl) == null ? void 0 : _a.call(this));
497
+ this._loadableURL = getLoadableWorkerURL({ source: this.source, url });
478
498
  const worker = new Worker(this._loadableURL, { name: this.name });
499
+ return this._initializeBrowserWorker(worker);
500
+ }
501
+ /** Attaches protocol handlers to a browser worker. */
502
+ _initializeBrowserWorker(worker) {
479
503
  worker.onmessage = (event) => {
480
504
  if (!event.data) {
481
505
  this.onError(new Error("No data received"));
@@ -525,6 +549,10 @@ var WorkerPool = class {
525
549
  source;
526
550
  // | Function;
527
551
  url;
552
+ /** Lazily resolves a classic worker fallback URL. */
553
+ getUrl;
554
+ /** Creates a browser Worker directly. */
555
+ loadWorker;
528
556
  maxConcurrency = 1;
529
557
  maxMobileConcurrency = 1;
530
558
  onDebug = () => {
@@ -533,6 +561,7 @@ var WorkerPool = class {
533
561
  props = {};
534
562
  jobQueue = [];
535
563
  idleQueue = [];
564
+ activeJobs = /* @__PURE__ */ new Set();
536
565
  count = 0;
537
566
  isDestroyed = false;
538
567
  /** Checks if workers are supported on this platform */
@@ -546,13 +575,19 @@ var WorkerPool = class {
546
575
  constructor(props) {
547
576
  this.source = props.source;
548
577
  this.url = props.url;
578
+ this.getUrl = props.getUrl;
579
+ this.loadWorker = props.loadWorker;
549
580
  this.setProps(props);
550
581
  }
551
582
  /**
552
- * Terminates all workers in the pool
583
+ * Terminates all workers in the pool and aborts active jobs.
584
+ * @param reason Optional error delivered to active jobs.
553
585
  * @note Can free up significant memory
554
586
  */
555
- destroy() {
587
+ destroy(reason = new Error("Worker pool was destroyed")) {
588
+ this.activeJobs.forEach((job) => job.abort(reason));
589
+ const queuedJobs = this.jobQueue.splice(0);
590
+ queuedJobs.forEach((queuedJob) => queuedJob.onReject(reason));
556
591
  this.idleQueue.forEach((worker) => worker.destroy());
557
592
  this.isDestroyed = true;
558
593
  }
@@ -575,8 +610,11 @@ var WorkerPool = class {
575
610
  }
576
611
  }
577
612
  async startJob(name, onMessage2 = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) {
578
- const startPromise = new Promise((onStart) => {
579
- this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart });
613
+ if (this.isDestroyed) {
614
+ return Promise.reject(new Error("Worker pool was destroyed"));
615
+ }
616
+ const startPromise = new Promise((onStart, onReject) => {
617
+ this.jobQueue.push({ name, onMessage: onMessage2, onError, onStart, onReject });
580
618
  return this;
581
619
  });
582
620
  this._startQueuedJob();
@@ -604,6 +642,7 @@ var WorkerPool = class {
604
642
  backlog: this.jobQueue.length
605
643
  });
606
644
  const job = new WorkerJob(queuedJob.name, workerThread);
645
+ this.activeJobs.add(job);
607
646
  workerThread.ref();
608
647
  workerThread.onMessage = (data) => queuedJob.onMessage(job, data.type, data.payload);
609
648
  workerThread.onError = (error) => queuedJob.onError(job, error);
@@ -612,6 +651,7 @@ var WorkerPool = class {
612
651
  await job.result;
613
652
  } catch {
614
653
  } finally {
654
+ this.activeJobs.delete(job);
615
655
  this.returnWorkerToQueue(workerThread);
616
656
  }
617
657
  }
@@ -655,7 +695,13 @@ var WorkerPool = class {
655
695
  if (this.count < this._getMaxConcurrency()) {
656
696
  this.count++;
657
697
  const name = `${this.name.toLowerCase()} (#${this.count} of ${this.maxConcurrency})`;
658
- return new WorkerThread({ name, source: this.source, url: this.url });
698
+ return new WorkerThread({
699
+ name,
700
+ source: this.source,
701
+ url: this.url,
702
+ getUrl: this.getUrl,
703
+ loadWorker: this.loadWorker
704
+ });
659
705
  }
660
706
  return null;
661
707
  }
@@ -672,6 +718,8 @@ var DEFAULT_PROPS = {
672
718
  onDebug: () => {
673
719
  }
674
720
  };
721
+ var loadWorkerIds = /* @__PURE__ */ new WeakMap();
722
+ var nextLoadWorkerId = 1;
675
723
  var WorkerFarm = class _WorkerFarm {
676
724
  props;
677
725
  workerPools = /* @__PURE__ */ new Map();
@@ -694,12 +742,13 @@ var WorkerFarm = class _WorkerFarm {
694
742
  this.workerPools = /* @__PURE__ */ new Map();
695
743
  }
696
744
  /**
697
- * Terminate all workers in the farm
745
+ * Terminate all workers in the farm and abort active jobs.
746
+ * @param reason Optional error delivered to active jobs.
698
747
  * @note Can free up significant memory
699
748
  */
700
- destroy() {
749
+ destroy(reason) {
701
750
  for (const workerPool of this.workerPools.values()) {
702
- workerPool.destroy();
751
+ workerPool.destroy(reason);
703
752
  }
704
753
  this.workerPools = /* @__PURE__ */ new Map();
705
754
  }
@@ -715,24 +764,28 @@ var WorkerFarm = class _WorkerFarm {
715
764
  }
716
765
  /**
717
766
  * Returns a worker pool for the specified worker
718
- * @param options - only used first time for a specific worker name
719
- * @param options.name - the name of the worker - used to identify worker pool
720
- * @param options.url -
721
- * @param options.source -
767
+ * @param options Worker target used to identify and initialize the pool.
768
+ * @param options.name Worker name used as the base pool identity.
769
+ * @param options.url Worker script URL.
770
+ * @param options.source Inline worker source.
771
+ * @param options.loadWorker Built-in browser worker factory.
722
772
  * @example
723
773
  * const job = WorkerFarm.getWorkerFarm().getWorkerPool({name, url}).startJob(...);
724
774
  */
725
775
  getWorkerPool(options) {
726
- const { name, source, url } = options;
727
- let workerPool = this.workerPools.get(name);
776
+ const { name, source, url, getUrl, loadWorker } = options;
777
+ const workerPoolKey = getWorkerPoolKey(options);
778
+ let workerPool = this.workerPools.get(workerPoolKey);
728
779
  if (!workerPool) {
729
780
  workerPool = new WorkerPool({
730
781
  name,
731
782
  source,
732
- url
783
+ url,
784
+ getUrl,
785
+ loadWorker
733
786
  });
734
787
  workerPool.setProps(this._getWorkerPoolProps());
735
- this.workerPools.set(name, workerPool);
788
+ this.workerPools.set(workerPoolKey, workerPool);
736
789
  }
737
790
  return workerPool;
738
791
  }
@@ -745,6 +798,91 @@ var WorkerFarm = class _WorkerFarm {
745
798
  };
746
799
  }
747
800
  };
801
+ function getWorkerPoolKey(options) {
802
+ const { name, source, url, urlKey, loadWorker } = options;
803
+ const sourceKey = source ? `source:${source}` : "";
804
+ const urlKeyPart = url || urlKey ? `url:${url || urlKey}` : "";
805
+ const loadWorkerKey = loadWorker ? `loadWorker:${getLoadWorkerId(loadWorker)}` : "";
806
+ return [name, sourceKey, urlKeyPart, loadWorkerKey].filter(Boolean).join("|");
807
+ }
808
+ function getLoadWorkerId(loadWorker) {
809
+ let loadWorkerId = loadWorkerIds.get(loadWorker);
810
+ if (!loadWorkerId) {
811
+ loadWorkerId = nextLoadWorkerId++;
812
+ loadWorkerIds.set(loadWorker, loadWorkerId);
813
+ }
814
+ return loadWorkerId;
815
+ }
816
+
817
+ // ../worker-utils/src/lib/async-queue/async-queue.ts
818
+ var AsyncQueue = class {
819
+ _values;
820
+ _settlers;
821
+ _closed;
822
+ constructor() {
823
+ this._values = [];
824
+ this._settlers = [];
825
+ this._closed = false;
826
+ }
827
+ /** Return an async iterator for this queue */
828
+ [Symbol.asyncIterator]() {
829
+ return this;
830
+ }
831
+ /** Push a new value - the async iterator will yield a promise resolved to this value */
832
+ push(value) {
833
+ return this.enqueue(value);
834
+ }
835
+ /**
836
+ * Push a new value - the async iterator will yield a promise resolved to this value
837
+ * Add an error - the async iterator will yield a promise rejected with this value
838
+ */
839
+ enqueue(value) {
840
+ if (this._closed) {
841
+ throw new Error("Closed");
842
+ }
843
+ if (this._settlers.length > 0) {
844
+ if (this._values.length > 0) {
845
+ throw new Error("Illegal internal state");
846
+ }
847
+ const settler = this._settlers.shift();
848
+ if (value instanceof Error) {
849
+ settler.reject(value);
850
+ } else {
851
+ settler.resolve({ value });
852
+ }
853
+ } else {
854
+ this._values.push(value);
855
+ }
856
+ }
857
+ /** Indicate that we not waiting for more values - The async iterator will be done */
858
+ close() {
859
+ while (this._settlers.length > 0) {
860
+ const settler = this._settlers.shift();
861
+ settler.resolve({ done: true });
862
+ }
863
+ this._closed = true;
864
+ }
865
+ // ITERATOR IMPLEMENTATION
866
+ /** @returns a Promise for an IteratorResult */
867
+ next() {
868
+ if (this._values.length > 0) {
869
+ const value = this._values.shift();
870
+ if (value instanceof Error) {
871
+ return Promise.reject(value);
872
+ }
873
+ return Promise.resolve({ done: false, value });
874
+ }
875
+ if (this._closed) {
876
+ if (this._settlers.length > 0) {
877
+ throw new Error("Illegal internal state");
878
+ }
879
+ return Promise.resolve({ done: true, value: void 0 });
880
+ }
881
+ return new Promise((resolve2, reject) => {
882
+ this._settlers.push({ resolve: resolve2, reject });
883
+ });
884
+ }
885
+ };
748
886
 
749
887
  // ../worker-utils/src/lib/worker-api/get-worker-url.ts
750
888
  var warnedWorkerVersionFallbacks = /* @__PURE__ */ new Set();
@@ -752,35 +890,42 @@ function getWorkerName(worker) {
752
890
  const warning = worker.version !== VERSION2 ? ` (worker-utils@${VERSION2})` : "";
753
891
  return `${worker.name}@${worker.version}${warning}`;
754
892
  }
755
- function getWorkerURL(worker, options = {}) {
893
+ function getCustomWorkerURL(worker, options = {}) {
756
894
  var _a;
757
895
  const workerOptions = options[worker.id] || {};
758
- const workerFile = isBrowser2 ? `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
896
+ const workerFile = isBrowser2 ? worker.workerFile || `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
759
897
  let url = workerOptions.workerUrl;
760
- if (!url && typeof worker.worker === "string") {
761
- url = worker.worker;
762
- }
763
898
  if (!url && worker.id === "compression") {
764
899
  url = options.workerUrl;
765
900
  }
766
901
  const workerType = options._workerType || ((_a = options == null ? void 0 : options.core) == null ? void 0 : _a._workerType);
767
- if (workerType === "test") {
902
+ if (!url && workerType === "test") {
768
903
  if (isBrowser2) {
769
904
  url = `modules/${worker.module}/dist/${workerFile}`;
770
905
  } else {
771
906
  url = `modules/${worker.module}/src/workers/${worker.id}-worker-node.ts`;
772
907
  }
773
908
  }
774
- if (!url) {
775
- let version2 = worker.version;
776
- if (version2 === "latest") {
777
- version2 = NPM_TAG;
778
- }
779
- const versionTag = version2 ? `@${version2}` : "";
780
- url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
909
+ return url || null;
910
+ }
911
+ function getWorkerURL(worker, options = {}) {
912
+ const customWorkerUrl = getCustomWorkerURL(worker, options);
913
+ const descriptorWorkerUrl = typeof worker.worker === "string" ? worker.worker : null;
914
+ const url = customWorkerUrl || descriptorWorkerUrl || getDefaultWorkerURL(worker, true);
915
+ assert2(url);
916
+ return url;
917
+ }
918
+ function getDefaultWorkerURL(worker, warn = false) {
919
+ const workerFile = isBrowser2 ? worker.workerFile || `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
920
+ let version2 = worker.version;
921
+ if (version2 === "latest") {
922
+ version2 = NPM_TAG;
923
+ }
924
+ const versionTag = version2 ? `@${version2}` : "";
925
+ const url = `https://unpkg.com/@loaders.gl/${worker.module}${versionTag}/dist/${workerFile}`;
926
+ if (warn) {
781
927
  warnIfUsingNpmTagFallback(worker, url);
782
928
  }
783
- assert2(url);
784
929
  return url;
785
930
  }
786
931
  function warnIfUsingNpmTagFallback(worker, url) {
@@ -803,19 +948,16 @@ function canProcessOnWorker(worker, options) {
803
948
  return false;
804
949
  }
805
950
  const workerOptions = options == null ? void 0 : options[worker.id];
806
- return Boolean((worker.worker || (workerOptions == null ? void 0 : workerOptions.workerUrl)) && (options == null ? void 0 : options.worker));
951
+ return Boolean(
952
+ (worker.worker || worker.loadWorker || (workerOptions == null ? void 0 : workerOptions.workerUrl)) && (options == null ? void 0 : options.worker)
953
+ );
807
954
  }
808
955
  async function processOnWorker(worker, data, options = {}, context = {}, jobContext = {}) {
809
956
  var _a, _b, _c;
810
957
  throwIfAborted(options.signal);
811
958
  const name = getWorkerName(worker);
812
959
  const workerFarm = WorkerFarm.getWorkerFarm(options);
813
- const { source } = options;
814
- const workerPoolProps = { name, source };
815
- if (!source) {
816
- workerPoolProps.url = getWorkerURL(worker, options);
817
- }
818
- const workerPool = workerFarm.getWorkerPool(workerPoolProps);
960
+ const workerPool = workerFarm.getWorkerPool(getWorkerPoolTarget(worker, options, name));
819
961
  const jobName = options.jobName || worker.name;
820
962
  const job = await workerPool.startJob(
821
963
  jobName,
@@ -844,6 +986,115 @@ async function processOnWorker(worker, data, options = {}, context = {}, jobCont
844
986
  (_c = options.signal) == null ? void 0 : _c.removeEventListener("abort", abortJob);
845
987
  }
846
988
  }
989
+ function processOnWorkerInBatches(worker, input, options = {}, context = {}, jobContext = {}) {
990
+ return processOnWorkerInBatchesIterator(worker, input, options, context, jobContext);
991
+ }
992
+ async function* processOnWorkerInBatchesIterator(worker, input, options, context, jobContext) {
993
+ var _a, _b, _c;
994
+ throwIfAborted(options.signal);
995
+ const name = getWorkerName(worker);
996
+ const workerFarm = WorkerFarm.getWorkerFarm(options);
997
+ const workerPool = workerFarm.getWorkerPool(getWorkerPoolTarget(worker, options, name));
998
+ const outputBatches = new AsyncQueue();
999
+ const inputIterator = getAsyncIterator(input);
1000
+ let outputFinished = false;
1001
+ let inputFinished = false;
1002
+ let inputRequest = Promise.resolve();
1003
+ const batchJobFailed = new Error("Worker batch job failed");
1004
+ const finishOutput = () => {
1005
+ if (!outputFinished) {
1006
+ outputFinished = true;
1007
+ outputBatches.close();
1008
+ }
1009
+ };
1010
+ const failOutput = (_error) => {
1011
+ if (!outputFinished) {
1012
+ outputFinished = true;
1013
+ outputBatches.enqueue(batchJobFailed);
1014
+ outputBatches.close();
1015
+ }
1016
+ };
1017
+ const job = await workerPool.startJob(
1018
+ options.jobName || worker.name,
1019
+ (activeJob, type, payload) => {
1020
+ switch (type) {
1021
+ case "input-request":
1022
+ inputRequest = inputRequest.then(async () => {
1023
+ const nextBatch = await inputIterator.next();
1024
+ if (!activeJob.isRunning) {
1025
+ return;
1026
+ }
1027
+ if (nextBatch.done) {
1028
+ inputFinished = true;
1029
+ activeJob.postMessage("input-done", {});
1030
+ } else {
1031
+ activeJob.postMessage("input-batch", { input: nextBatch.value });
1032
+ }
1033
+ }).catch((error) => activeJob.abort(error));
1034
+ break;
1035
+ case "output-batch":
1036
+ outputBatches.push(payload.result);
1037
+ break;
1038
+ case "done":
1039
+ activeJob.done(payload);
1040
+ finishOutput();
1041
+ break;
1042
+ case "error": {
1043
+ const error = new Error(payload.error || "Worker batch processing failed");
1044
+ activeJob.error(error);
1045
+ failOutput(error);
1046
+ break;
1047
+ }
1048
+ case "process":
1049
+ void onMessage(context, activeJob, type, payload);
1050
+ break;
1051
+ default: {
1052
+ const error = new Error(`Unexpected worker batch message: ${type}`);
1053
+ activeJob.error(error);
1054
+ failOutput(error);
1055
+ break;
1056
+ }
1057
+ }
1058
+ }
1059
+ );
1060
+ const abortJob = () => job.abort(getAbortReason(options.signal));
1061
+ (_a = options.signal) == null ? void 0 : _a.addEventListener("abort", abortJob, { once: true });
1062
+ if ((_b = options.signal) == null ? void 0 : _b.aborted) {
1063
+ abortJob();
1064
+ }
1065
+ void job.result.catch(failOutput);
1066
+ try {
1067
+ const { signal: _signal, ...workerOptions } = options;
1068
+ if (job.isRunning) {
1069
+ job.postMessage("process-in-batches", {
1070
+ options: getTransferListForWriter(workerOptions),
1071
+ context: getTransferListForWriter(jobContext)
1072
+ });
1073
+ }
1074
+ try {
1075
+ for await (const outputBatch of outputBatches) {
1076
+ yield outputBatch;
1077
+ if (job.isRunning) {
1078
+ job.postMessage("output-ack", {});
1079
+ }
1080
+ }
1081
+ } catch (error) {
1082
+ if (error === batchJobFailed) {
1083
+ await job.result;
1084
+ }
1085
+ throw error;
1086
+ }
1087
+ await job.result;
1088
+ } finally {
1089
+ (_c = options.signal) == null ? void 0 : _c.removeEventListener("abort", abortJob);
1090
+ if (job.isRunning) {
1091
+ job.abort(createAbortError2("Worker batch iterator was closed"));
1092
+ }
1093
+ if (!inputFinished) {
1094
+ closeInputIterator(inputIterator);
1095
+ }
1096
+ }
1097
+ }
847
1098
  function throwIfAborted(signal) {
848
1099
  if (!(signal == null ? void 0 : signal.aborted)) {
849
1100
  return;
@@ -858,6 +1109,39 @@ function createAbortError2(message) {
858
1109
  error.name = "AbortError";
859
1110
  return error;
860
1111
  }
1112
+ function getAsyncIterator(input) {
1113
+ if (Symbol.asyncIterator in input) {
1114
+ return input[Symbol.asyncIterator]();
1115
+ }
1116
+ return (async function* iterateSynchronously() {
1117
+ yield* input;
1118
+ })();
1119
+ }
1120
+ function closeInputIterator(inputIterator) {
1121
+ var _a;
1122
+ try {
1123
+ void Promise.resolve((_a = inputIterator.return) == null ? void 0 : _a.call(inputIterator)).catch(() => void 0);
1124
+ } catch {
1125
+ }
1126
+ }
1127
+ function getWorkerPoolTarget(worker, options, name) {
1128
+ if (options.source) {
1129
+ return { name, source: options.source };
1130
+ }
1131
+ const customWorkerUrl = getCustomWorkerURL(worker, options);
1132
+ if (customWorkerUrl) {
1133
+ return { name, url: customWorkerUrl };
1134
+ }
1135
+ if (isBrowser2 && worker.loadWorker) {
1136
+ return {
1137
+ name,
1138
+ loadWorker: worker.loadWorker,
1139
+ getUrl: () => getWorkerURL(worker, options),
1140
+ urlKey: getDefaultWorkerURL(worker)
1141
+ };
1142
+ }
1143
+ return { name, url: getWorkerURL(worker, options) };
1144
+ }
861
1145
  async function onMessage(context, job, type, payload) {
862
1146
  switch (type) {
863
1147
  case "done":
@@ -897,13 +1181,13 @@ function validateWorkerVersion(worker, coreVersion = VERSION2) {
897
1181
 
898
1182
  // ../loader-utils/src/lib/worker-loader-utils/parse-with-worker.ts
899
1183
  function canParseWithWorker(loader, options) {
900
- var _a, _b;
1184
+ var _a;
901
1185
  const workerOptions = getWorkerOptions(options);
902
1186
  const nodeWorkers = workerOptions._nodeWorkers;
903
1187
  if (!isBrowser2 && !nodeWorkers) {
904
1188
  return false;
905
1189
  }
906
- if (loader.id === "excel" && ((_a = options == null ? void 0 : options.excel) == null ? void 0 : _a.shape) === "arrow-table" || loader.id === "ply" && ((_b = options == null ? void 0 : options.ply) == null ? void 0 : _b.shape) === "arrow-table") {
1190
+ if (loader.id === "las" && (((_a = options == null ? void 0 : options.las) == null ? void 0 : _a.shape) ?? "arrow-table") === "arrow-table") {
907
1191
  return false;
908
1192
  }
909
1193
  if (loader.id === "csv" && !shouldParseCSVWithWorker(options)) {
@@ -911,12 +1195,30 @@ function canParseWithWorker(loader, options) {
911
1195
  }
912
1196
  return Boolean(canProcessOnWorker(loader, workerOptions));
913
1197
  }
1198
+ function shouldParseWithWorker(loader, data, options, context, estimateLoader = loader) {
1199
+ var _a, _b;
1200
+ if (!canParseWithWorker(loader, options)) {
1201
+ return false;
1202
+ }
1203
+ if (((_a = options == null ? void 0 : options.core) == null ? void 0 : _a.worker) !== "auto" || !estimateLoader.getWorkerEstimate) {
1204
+ return true;
1205
+ }
1206
+ try {
1207
+ const estimate = estimateLoader.getWorkerEstimate(data, options, context);
1208
+ if (estimate === void 0 || !Number.isFinite(estimate) || estimate < 0 || estimate > 1) {
1209
+ return true;
1210
+ }
1211
+ return estimate >= (((_b = options.core) == null ? void 0 : _b.workerThreshold) ?? 0.1);
1212
+ } catch {
1213
+ return true;
1214
+ }
1215
+ }
914
1216
  async function parseWithWorker(loader, data, options, context, parseOnMainThread, signal) {
915
1217
  const workerSignal = signal || getWorkerAbortSignal(options);
916
1218
  const result = await processOnWorker(
917
1219
  loader,
918
1220
  data,
919
- { ...getWorkerOptions(options), signal: workerSignal },
1221
+ { ...getWorkerOptions(options, loader), signal: workerSignal },
920
1222
  {
921
1223
  process: async (input, processOptions, _workerContext, parseContext) => {
922
1224
  if (!parseOnMainThread) {
@@ -935,6 +1237,32 @@ async function parseWithWorker(loader, data, options, context, parseOnMainThread
935
1237
  );
936
1238
  return isLoaderWithWorkerResultDeserializer(loader) ? loader.deserializeWorkerResult(result, options, context) : result;
937
1239
  }
1240
+ async function* parseWithWorkerInBatches(loader, inputIterator, options, context, parseOnMainThread, signal) {
1241
+ const workerSignal = signal || getWorkerAbortSignal(options);
1242
+ const outputIterator = processOnWorkerInBatches(
1243
+ loader,
1244
+ inputIterator,
1245
+ { ...getWorkerOptions(options), signal: workerSignal },
1246
+ {
1247
+ process: async (input, processOptions, _workerContext, parseContext) => {
1248
+ if (!parseOnMainThread) {
1249
+ throw new Error("Worker not set up to parse on main thread");
1250
+ }
1251
+ const mainThreadContext = context ? { ...context, ...parseContext || {} } : void 0;
1252
+ return await callParseOnMainThread(
1253
+ parseOnMainThread,
1254
+ input,
1255
+ processOptions,
1256
+ mainThreadContext
1257
+ );
1258
+ }
1259
+ },
1260
+ getSerializableLoaderContext(context)
1261
+ );
1262
+ for await (const batch of outputIterator) {
1263
+ yield loader.deserializeWorkerBatch ? loader.deserializeWorkerBatch(batch, options, context) : batch;
1264
+ }
1265
+ }
938
1266
  function getWorkerAbortSignal(options) {
939
1267
  var _a;
940
1268
  const parquetSignal = (_a = options == null ? void 0 : options.parquet) == null ? void 0 : _a.signal;
@@ -949,12 +1277,19 @@ function callParseOnMainThread(parseOnMainThread, input, options, context) {
949
1277
  }
950
1278
  return parseOnMainThread(input, void 0, options, context);
951
1279
  }
952
- function getWorkerOptions(options = {}) {
1280
+ function getWorkerOptions(options = {}, loader) {
953
1281
  const serializedOptions = JSON.parse(JSON.stringify(options));
954
- return {
1282
+ const workerOptions = {
955
1283
  ...serializedOptions.core,
956
1284
  ...serializedOptions
957
1285
  };
1286
+ if (workerOptions.worker === "auto") {
1287
+ workerOptions.worker = true;
1288
+ }
1289
+ if (loader) {
1290
+ workerOptions._workerLoaderId = loader.id;
1291
+ }
1292
+ return workerOptions;
958
1293
  }
959
1294
  function getSerializableLoaderContext(context) {
960
1295
  if (!context) {
@@ -2029,6 +2364,7 @@ var DEFAULT_LOADER_OPTIONS = {
2029
2364
  CDN: "https://unpkg.com/@loaders.gl",
2030
2365
  worker: true,
2031
2366
  // By default, use worker if provided by loader.
2367
+ workerThreshold: 0.1,
2032
2368
  maxConcurrency: 3,
2033
2369
  // How many worker instances should be created for each loader.
2034
2370
  maxMobileConcurrency: 1,
@@ -2104,6 +2440,7 @@ var CORE_LOADER_OPTION_KEYS = [
2104
2440
  "useLocalLibraries",
2105
2441
  "CDN",
2106
2442
  "worker",
2443
+ "workerThreshold",
2107
2444
  "maxConcurrency",
2108
2445
  "maxMobileConcurrency",
2109
2446
  "reuseWorkers",
@@ -2144,7 +2481,10 @@ function normalizeOptions(options, loader, loaders, url) {
2144
2481
  loaders = loaders || [];
2145
2482
  loaders = Array.isArray(loaders) ? loaders : [loaders];
2146
2483
  validateOptions(options, loaders);
2147
- return normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
2484
+ validateWorkerThreshold(options);
2485
+ const normalizedOptions = normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
2486
+ validateWorkerThreshold(normalizedOptions);
2487
+ return normalizedOptions;
2148
2488
  }
2149
2489
  function normalizeLoaderOptions(options) {
2150
2490
  const normalized = cloneLoaderOptions(options);
@@ -2168,6 +2508,13 @@ function validateOptions(options, loaders) {
2168
2508
  validateOptionsObject(idOptions, loader.id, loaderOptions, deprecatedOptions, loaders);
2169
2509
  }
2170
2510
  }
2511
+ function validateWorkerThreshold(options) {
2512
+ var _a;
2513
+ const threshold = (_a = options.core) == null ? void 0 : _a.workerThreshold;
2514
+ if (threshold !== void 0 && (!Number.isFinite(threshold) || threshold < 0 || threshold > 1)) {
2515
+ throw new Error("core.workerThreshold must be a finite number between 0 and 1");
2516
+ }
2517
+ }
2171
2518
  function validateOptionsObject(options, id, defaultOptions, deprecatedOptions, loaders) {
2172
2519
  const loaderName = id || "Top level";
2173
2520
  const prefix = id ? `${id}.` : "";
@@ -2872,7 +3219,8 @@ function getFetchFunction(options, context) {
2872
3219
  if (typeof fetchOption === "function") {
2873
3220
  fetchFunction = fetchOption;
2874
3221
  } else if (isObject(fetchOption)) {
2875
- fetchFunction = (url, requestOptions) => fetchFile(url, mergeFetchOptions(fetchOption, requestOptions));
3222
+ const baseFetch = (context == null ? void 0 : context.fetch) || fetchFile;
3223
+ fetchFunction = (url, requestOptions) => baseFetch(url, mergeFetchOptions(fetchOption, requestOptions));
2876
3224
  } else if (context == null ? void 0 : context.fetch) {
2877
3225
  fetchFunction = context.fetch;
2878
3226
  } else {
@@ -3167,6 +3515,9 @@ async function parseToOutputIterator(loader, data, options, context) {
3167
3515
  const inputIterator = await getAsyncIterableFromData(data, options);
3168
3516
  const transformedIterator = await applyInputTransforms(inputIterator, ((_a = options == null ? void 0 : options.core) == null ? void 0 : _a.transforms) || []);
3169
3517
  if (loader.parseInBatches) {
3518
+ if (loader.id === "csv" && isBrowser && canParseWithWorker(loader, options)) {
3519
+ return parseWithWorkerInBatches(loader, transformedIterator, options, context, parse);
3520
+ }
3170
3521
  return loader.parseInBatches(transformedIterator, options, context);
3171
3522
  }
3172
3523
  return parseChunkInBatches(transformedIterator, loader, options, context);
@@ -3337,7 +3688,10 @@ var coreApi = Object.freeze({
3337
3688
  // dist/lib/loader-utils/loader-context.js
3338
3689
  function getLoaderContext(context, options, parentContext) {
3339
3690
  if (parentContext) {
3340
- return parentContext;
3691
+ return {
3692
+ ...parentContext,
3693
+ fetch: getFetchFunction(options, parentContext)
3694
+ };
3341
3695
  }
3342
3696
  const newContext = {
3343
3697
  ...context,
@@ -3408,7 +3762,7 @@ async function parseWithLoader(loader, data, options, context) {
3408
3762
  context.response = { headers, ok, redirected, status, statusText, type, url };
3409
3763
  }
3410
3764
  const loaderWithParser = await getLoaderImplementation(loader, options, context.url);
3411
- if (canParseWithWorker(loaderWithParser, options)) {
3765
+ if (shouldParseWithWorker(loaderWithParser, data, options, context, loader)) {
3412
3766
  data = await getArrayBufferFromData(data, options);
3413
3767
  return await parseWithWorker(loaderWithParser, data, options, context, parse);
3414
3768
  }
@@ -3651,7 +4005,7 @@ function makeStream(source, options) {
3651
4005
  }
3652
4006
 
3653
4007
  // dist/null-loader.js
3654
- var VERSION4 = true ? "5.0.0-alpha.5" : "latest";
4008
+ var VERSION4 = true ? "5.0.0-alpha.7" : "latest";
3655
4009
  var NullWorkerLoader = {
3656
4010
  dataType: null,
3657
4011
  batchType: null,