@loaders.gl/core 5.0.0-alpha.2 → 5.0.0-alpha.4

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.
package/LICENSE CHANGED
@@ -37,7 +37,7 @@ License reproduced above.
37
37
  Copyright (c) 2016 Axel Rauschmayer
38
38
 
39
39
  loaders.gl includes certain files from Cesium (https://github.com/CesiumGS/cesium)
40
- under the Apache 2.0 License, including files in modules/3d-tiles and modules/math.
40
+ under the Apache 2.0 License, including files in modules/3d-tiles.
41
41
 
42
42
  Copyright 2011-2018 CesiumJS Contributors
43
43
 
package/dist/dist.dev.js CHANGED
@@ -795,17 +795,24 @@ var __exports__ = (() => {
795
795
  this.isRunning = false;
796
796
  this._reject(error);
797
797
  }
798
- /** Terminates the worker executing this job and rejects its result with an abort error. */
799
- abort() {
798
+ /**
799
+ * Terminates the worker executing this job and rejects its result.
800
+ * @param reason Abort reason supplied by the caller, or a cross-runtime `AbortError`.
801
+ */
802
+ abort(reason) {
800
803
  if (!this.isRunning) {
801
804
  return;
802
805
  }
803
- const error = new Error(`Worker job "${this.name}" was aborted`);
804
- error.name = "AbortError";
806
+ const error = reason ?? createAbortError(`Worker job "${this.name}" was aborted`);
805
807
  this.workerThread.destroy();
806
808
  this.error(error);
807
809
  }
808
810
  };
811
+ function createAbortError(message) {
812
+ const error = new Error(message);
813
+ error.name = "AbortError";
814
+ return error;
815
+ }
809
816
 
810
817
  // ../worker-utils/src/lib/node/worker_threads-browser.ts
811
818
  var NodeWorker = class {
@@ -1271,7 +1278,7 @@ var __exports__ = (() => {
1271
1278
  }
1272
1279
  function getWorkerURL(worker, options = {}) {
1273
1280
  const workerOptions = options[worker.id] || {};
1274
- const workerFile = isBrowser3 ? `${worker.id}-worker.js` : `${worker.id}-worker-node.js`;
1281
+ const workerFile = isBrowser3 ? `${worker.id}-worker.js` : worker.workerNode || `${worker.id}-worker-node.js`;
1275
1282
  let url = workerOptions.workerUrl;
1276
1283
  if (!url && typeof worker.worker === "string") {
1277
1284
  url = worker.worker;
@@ -1337,7 +1344,7 @@ var __exports__ = (() => {
1337
1344
  // eslint-disable-next-line
1338
1345
  onMessage.bind(null, context)
1339
1346
  );
1340
- const abortJob = () => job.abort();
1347
+ const abortJob = () => job.abort(getAbortReason(options.signal));
1341
1348
  options.signal?.addEventListener("abort", abortJob, { once: true });
1342
1349
  if (options.signal?.aborted) {
1343
1350
  abortJob();
@@ -1363,9 +1370,15 @@ var __exports__ = (() => {
1363
1370
  if (!signal?.aborted) {
1364
1371
  return;
1365
1372
  }
1366
- const error = new Error("Worker job was aborted");
1373
+ throw getAbortReason(signal);
1374
+ }
1375
+ function getAbortReason(signal) {
1376
+ return signal?.reason ?? createAbortError2("Worker job was aborted");
1377
+ }
1378
+ function createAbortError2(message) {
1379
+ const error = new Error(message);
1367
1380
  error.name = "AbortError";
1368
- throw error;
1381
+ return error;
1369
1382
  }
1370
1383
  async function onMessage(context, job, type, payload) {
1371
1384
  switch (type) {
@@ -1419,12 +1432,12 @@ var __exports__ = (() => {
1419
1432
  }
1420
1433
  return Boolean(canProcessOnWorker(loader, workerOptions));
1421
1434
  }
1422
- async function parseWithWorker(loader, data, options, context, parseOnMainThread) {
1423
- const signal = getWorkerAbortSignal(options);
1435
+ async function parseWithWorker(loader, data, options, context, parseOnMainThread, signal) {
1436
+ const workerSignal = signal || getWorkerAbortSignal(options);
1424
1437
  const result = await processOnWorker(
1425
1438
  loader,
1426
1439
  data,
1427
- { ...getWorkerOptions(options), signal },
1440
+ { ...getWorkerOptions(options), signal: workerSignal },
1428
1441
  {
1429
1442
  process: async (input, processOptions, _workerContext, parseContext) => {
1430
1443
  if (!parseOnMainThread) {
@@ -1971,6 +1984,114 @@ var __exports__ = (() => {
1971
1984
  }
1972
1985
  };
1973
1986
 
1987
+ // ../loader-utils/src/lib/request-utils/request-credentials.ts
1988
+ var AUTHENTICATED_FETCH = /* @__PURE__ */ Symbol("loaders.gl.authenticated-fetch");
1989
+ var refreshPromises = /* @__PURE__ */ new WeakMap();
1990
+ function createAuthenticatedFetch(options) {
1991
+ const baseFetch = options.fetch || ((url, requestOptions) => fetch(url, requestOptions));
1992
+ if (!options.credentials.length) return baseFetch;
1993
+ const existingMetadata = baseFetch[AUTHENTICATED_FETCH];
1994
+ if (existingMetadata === options.credentials) return baseFetch;
1995
+ const authenticatedFetch = async (url, requestOptions = {}) => {
1996
+ const resolvedURL = parseHTTPURL(url);
1997
+ if (!resolvedURL) return baseFetch(url, requestOptions);
1998
+ const authorization = await authorizeRequest(resolvedURL, requestOptions, options.credentials);
1999
+ const response = await baseFetch(authorization.url, authorization.options);
2000
+ const refreshableCredentials = authorization.credentials.filter(
2001
+ ({ credential }) => typeof credential.token === "function" && credential.refreshStatusCodes.includes(response.status)
2002
+ );
2003
+ if (!refreshableCredentials.length || !isReplayableRequest(requestOptions)) return response;
2004
+ if (requestOptions.signal?.aborted) throw createAbortError3();
2005
+ const refreshedTokens = /* @__PURE__ */ new Map();
2006
+ await Promise.all(
2007
+ refreshableCredentials.map(async ({ credential }) => {
2008
+ const token = await refreshCredential(credential, url, response);
2009
+ if (token) refreshedTokens.set(credential, token);
2010
+ })
2011
+ );
2012
+ if (!refreshedTokens.size) return response;
2013
+ await response.body?.cancel().catch(() => {
2014
+ });
2015
+ if (requestOptions.signal?.aborted) throw createAbortError3();
2016
+ const replayAuthorization = await authorizeRequest(
2017
+ resolvedURL,
2018
+ requestOptions,
2019
+ options.credentials,
2020
+ refreshedTokens,
2021
+ authorization.credentials
2022
+ );
2023
+ return baseFetch(replayAuthorization.url, replayAuthorization.options);
2024
+ };
2025
+ Object.defineProperty(authenticatedFetch, AUTHENTICATED_FETCH, {
2026
+ value: options.credentials
2027
+ });
2028
+ return authenticatedFetch;
2029
+ }
2030
+ async function authorizeRequest(sourceURL, requestOptions, credentials, tokenOverrides = /* @__PURE__ */ new Map(), previousCredentials = []) {
2031
+ const url = new URL(sourceURL);
2032
+ const headers = new Headers(requestOptions.headers);
2033
+ const resolvedCredentials = [];
2034
+ const previousTokens = new Map(
2035
+ previousCredentials.map(({ credential, token }) => [credential, token])
2036
+ );
2037
+ for (const credential of credentials) {
2038
+ if (!credential.origins.includes(url.origin)) continue;
2039
+ const overrideToken = tokenOverrides.get(credential);
2040
+ const previousToken = previousTokens.get(credential);
2041
+ const ownsQueryParameter = credential.type === "query-parameter" && previousToken !== void 0;
2042
+ const ownsHeader = credential.type === "header" && previousToken !== void 0;
2043
+ if (credential.type === "query-parameter" && url.searchParams.has(credential.name) && !ownsQueryParameter || credential.type === "header" && headers.has(credential.name) && !ownsHeader) {
2044
+ continue;
2045
+ }
2046
+ const token = overrideToken ?? previousToken ?? await resolveToken(credential.token, { url: sourceURL.toString(), reason: "request" });
2047
+ if (!token) continue;
2048
+ if (credential.type === "query-parameter") {
2049
+ url.searchParams.set(credential.name, token);
2050
+ } else {
2051
+ headers.set(credential.name, `${credential.prefix || ""}${token}`);
2052
+ }
2053
+ resolvedCredentials.push({ credential, token });
2054
+ }
2055
+ return {
2056
+ url: url.toString(),
2057
+ options: { ...requestOptions, headers },
2058
+ credentials: resolvedCredentials
2059
+ };
2060
+ }
2061
+ async function refreshCredential(credential, url, response) {
2062
+ const existingPromise = refreshPromises.get(credential);
2063
+ if (existingPromise) return existingPromise;
2064
+ const tokenProvider = credential.token;
2065
+ const promise = Promise.resolve(
2066
+ tokenProvider({
2067
+ url,
2068
+ reason: "refresh",
2069
+ response: { status: response.status, headers: response.headers }
2070
+ })
2071
+ ).finally(() => refreshPromises.delete(credential));
2072
+ refreshPromises.set(credential, promise);
2073
+ return promise;
2074
+ }
2075
+ async function resolveToken(token, context) {
2076
+ return typeof token === "function" ? token(context) : token;
2077
+ }
2078
+ function parseHTTPURL(url) {
2079
+ try {
2080
+ const parsedURL = new URL(url);
2081
+ return ["http:", "https:"].includes(parsedURL.protocol) ? parsedURL : null;
2082
+ } catch {
2083
+ return null;
2084
+ }
2085
+ }
2086
+ function isReplayableRequest(options) {
2087
+ const method = (options.method || "GET").toUpperCase();
2088
+ if (!["GET", "HEAD", "OPTIONS", "PUT", "DELETE"].includes(method)) return false;
2089
+ return !(options.body && typeof ReadableStream !== "undefined" && options.body instanceof ReadableStream);
2090
+ }
2091
+ function createAbortError3() {
2092
+ return new DOMException("The operation was aborted.", "AbortError");
2093
+ }
2094
+
1974
2095
  // ../loader-utils/src/lib/path-utils/file-aliases.ts
1975
2096
  var pathPrefix = "";
1976
2097
  var fileAliases = {};
@@ -3455,16 +3576,29 @@ var __exports__ = (() => {
3455
3576
  const globalOptions = getGlobalLoaderOptions();
3456
3577
  const loaderOptions = options || globalOptions;
3457
3578
  const fetchOption = loaderOptions.fetch ?? loaderOptions.core?.fetch;
3579
+ let fetchFunction;
3458
3580
  if (typeof fetchOption === "function") {
3459
- return fetchOption;
3460
- }
3461
- if (isObject(fetchOption)) {
3462
- return (url) => fetchFile(url, fetchOption);
3581
+ fetchFunction = fetchOption;
3582
+ } else if (isObject(fetchOption)) {
3583
+ fetchFunction = (url, requestOptions) => fetchFile(url, mergeFetchOptions(fetchOption, requestOptions));
3584
+ } else if (context?.fetch) {
3585
+ fetchFunction = context.fetch;
3586
+ } else {
3587
+ fetchFunction = fetchFile;
3463
3588
  }
3464
- if (context?.fetch) {
3465
- return context?.fetch;
3589
+ return createAuthenticatedFetch({
3590
+ fetch: fetchFunction,
3591
+ credentials: loaderOptions.core?.credentials || []
3592
+ });
3593
+ }
3594
+ function mergeFetchOptions(defaultOptions, requestOptions) {
3595
+ const options = { ...defaultOptions, ...requestOptions };
3596
+ if (defaultOptions.headers || requestOptions?.headers) {
3597
+ const headers = new Headers(defaultOptions.headers);
3598
+ new Headers(requestOptions?.headers).forEach((value, key) => headers.set(key, value));
3599
+ options.headers = headers;
3466
3600
  }
3467
- return fetchFile;
3601
+ return options;
3468
3602
  }
3469
3603
 
3470
3604
  // src/lib/api/load-loader.ts
@@ -3679,7 +3813,7 @@ var __exports__ = (() => {
3679
3813
  case "geojson-table":
3680
3814
  return Array.isArray(table.features);
3681
3815
  case "columnar-table":
3682
- return table.data && typeof table.data === "object";
3816
+ return Boolean(table.data && typeof table.data === "object");
3683
3817
  case "arrow-table":
3684
3818
  return Boolean(table?.data?.numRows !== void 0);
3685
3819
  default:
@@ -3893,6 +4027,15 @@ var __exports__ = (() => {
3893
4027
  }
3894
4028
  );
3895
4029
  }
4030
+ if (selectedLoader && typeof url === "string") {
4031
+ const loaderImplementation = await getLoaderImplementation(
4032
+ selectedLoader,
4033
+ resolvedOptions,
4034
+ url
4035
+ );
4036
+ const parseUrl = loaderImplementation.parseUrl;
4037
+ if (parseUrl) return await parseUrl(url, resolvedOptions, context);
4038
+ }
3896
4039
  }
3897
4040
  const fetch2 = getFetchFunction(resolvedOptions);
3898
4041
  let data = url;
@@ -4375,18 +4518,29 @@ var __exports__ = (() => {
4375
4518
  if (path.includes("://")) {
4376
4519
  return this._fetch(path, options);
4377
4520
  }
4378
- const file = this.files[path];
4521
+ const file = this._getFile(path, true);
4379
4522
  if (!file) {
4380
4523
  return new Response(path, { status: 400, statusText: "NOT FOUND" });
4381
4524
  }
4382
4525
  const headers = new Headers(options?.headers);
4383
4526
  const range = headers.get("Range");
4384
- const bytes = range && /bytes=($1)-($2)/.exec(range);
4527
+ const bytes = range && /bytes=(\d+)-(\d+)/.exec(range);
4385
4528
  if (bytes) {
4386
4529
  const start = parseInt(bytes[1]);
4387
- const end = parseInt(bytes[2]);
4388
- const data = await file.slice(start, end).arrayBuffer();
4389
- const response2 = new Response(data);
4530
+ const end = Math.min(parseInt(bytes[2]), file.size - 1);
4531
+ if (start > end) {
4532
+ const response3 = new Response(null, {
4533
+ status: 416,
4534
+ headers: { "Content-Range": `bytes */${file.size}` }
4535
+ });
4536
+ Object.defineProperty(response3, "url", { value: path });
4537
+ return response3;
4538
+ }
4539
+ const data = await file.slice(start, end + 1).arrayBuffer();
4540
+ const response2 = new Response(data, {
4541
+ status: 206,
4542
+ headers: { "Content-Range": `bytes ${start}-${end}/${file.size}` }
4543
+ });
4390
4544
  Object.defineProperty(response2, "url", { value: path });
4391
4545
  return response2;
4392
4546
  }
@@ -4410,7 +4564,7 @@ var __exports__ = (() => {
4410
4564
  * Return information (size) about files in this file system
4411
4565
  */
4412
4566
  async stat(path, options) {
4413
- const file = this.files[path];
4567
+ const file = this._getFile(path, false);
4414
4568
  if (!file) {
4415
4569
  throw new Error(path);
4416
4570
  }
@@ -4420,19 +4574,22 @@ var __exports__ = (() => {
4420
4574
  * Just removes the file from the list
4421
4575
  */
4422
4576
  async unlink(path) {
4423
- delete this.files[path];
4424
- delete this.lowerCaseFiles[path];
4425
- this.usedFiles[path] = true;
4577
+ const file = this._getFile(path, false);
4578
+ if (file) {
4579
+ delete this.files[file.name];
4580
+ delete this.lowerCaseFiles[file.name.toLowerCase()];
4581
+ this.usedFiles[file.name] = true;
4582
+ }
4426
4583
  }
4427
4584
  // implements IRandomAccessFileSystem
4428
4585
  // RANDOM ACCESS
4429
4586
  async openReadableFile(pathname, flags) {
4430
- return new BlobFile(this.files[pathname]);
4587
+ return new BlobFile(this._getFile(pathname, true));
4431
4588
  }
4432
4589
  // PRIVATE
4433
4590
  // Supports case independent paths, and file usage tracking
4434
4591
  _getFile(path, used) {
4435
- const file = this.files[path] || this.lowerCaseFiles[path];
4592
+ const file = this.files[path] || this.lowerCaseFiles[path.toLowerCase()];
4436
4593
  if (file && used) {
4437
4594
  this.usedFiles[path] = true;
4438
4595
  }