@loaders.gl/splats 5.0.0-alpha.7 → 5.0.0-alpha.9

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/dist/index.cjs CHANGED
@@ -221,23 +221,98 @@ var init_async_iteration = __esm({
221
221
  }
222
222
  });
223
223
 
224
+ // ../loader-utils/src/lib/request-utils/authentication.ts
225
+ function resolveCredentials(credentials, authentications = []) {
226
+ if (credentials.every(isAuthentication)) return credentials;
227
+ return credentials.map((credential, index) => {
228
+ if (isAuthentication(credential)) return credential;
229
+ const AuthenticationClass = authentications.find(
230
+ (authentication2) => authentication2.type === (credential == null ? void 0 : credential.type)
231
+ );
232
+ if (!AuthenticationClass) {
233
+ throw new Error(`No authentication class registered for credential at index ${index}.`);
234
+ }
235
+ let authentication;
236
+ try {
237
+ authentication = new AuthenticationClass(credential);
238
+ } catch {
239
+ throw new Error(`Invalid authentication configuration at index ${index}.`);
240
+ }
241
+ if (!isAuthentication(authentication)) {
242
+ throw new Error(`Authentication class returned an invalid credential at index ${index}.`);
243
+ }
244
+ return authentication;
245
+ });
246
+ }
247
+ function resolveAuthenticationOptions(options) {
248
+ var _a, _b;
249
+ if (!((_b = (_a = options.core) == null ? void 0 : _a.credentials) == null ? void 0 : _b.length)) return options;
250
+ const credentials = resolveCredentials(options.core.credentials, options.core.authentications);
251
+ if (credentials === options.core.credentials) return options;
252
+ return { ...options, core: { ...options.core, credentials } };
253
+ }
254
+ function isAuthentication(credential) {
255
+ if (!credential || typeof credential !== "object") return false;
256
+ if (typeof credential.id !== "string" || !Array.isArray(credential.origins)) return false;
257
+ if (credential.type === "request") return typeof credential.authenticate === "function";
258
+ return (credential.type === "header" || credential.type === "query-parameter") && typeof credential.name === "string" && (typeof credential.token === "string" || typeof credential.token === "function") && Array.isArray(credential.refreshStatusCodes);
259
+ }
260
+ var init_authentication = __esm({
261
+ "../loader-utils/src/lib/request-utils/authentication.ts"() {
262
+ "use strict";
263
+ }
264
+ });
265
+
224
266
  // ../loader-utils/src/lib/request-utils/request-credentials.ts
225
267
  function createAuthenticatedFetch(options) {
226
- const baseFetch = options.fetch || ((url, requestOptions) => fetch(url, requestOptions));
227
- if (!options.credentials.length) return baseFetch;
228
- const existingMetadata = baseFetch[AUTHENTICATED_FETCH];
229
- if (existingMetadata === options.credentials) return baseFetch;
268
+ const suppliedFetch = options.fetch || ((url, requestOptions) => fetch(url, requestOptions));
269
+ const existingMetadata = suppliedFetch[AUTHENTICATED_FETCH];
270
+ const credentialResolutions = new Map(existingMetadata == null ? void 0 : existingMetadata.credentialResolutions);
271
+ const resolvedCredentials = resolveCredentials(
272
+ options.credentials.map((credential) => credentialResolutions.get(credential) || credential),
273
+ options.authentications
274
+ );
275
+ options.credentials.forEach((credential, index) => {
276
+ credentialResolutions.set(credential, resolvedCredentials[index]);
277
+ });
278
+ if (!options.fetchOptions && (!resolvedCredentials.length || (existingMetadata == null ? void 0 : existingMetadata.credentials.length) === resolvedCredentials.length && resolvedCredentials.every(
279
+ (credential, index) => credential === existingMetadata.credentials[index]
280
+ )))
281
+ return suppliedFetch;
282
+ const baseFetch = (existingMetadata == null ? void 0 : existingMetadata.fetch) || suppliedFetch;
283
+ const credentials = existingMetadata ? [.../* @__PURE__ */ new Set([...resolvedCredentials, ...existingMetadata.credentials])] : resolvedCredentials;
284
+ const fetchOptions = mergeFetchOptions(
285
+ (existingMetadata == null ? void 0 : existingMetadata.fetchOptions) || {},
286
+ options.fetchOptions
287
+ );
288
+ const tokenCredentials = credentials.filter(
289
+ (credential) => credential.type !== "request"
290
+ );
291
+ const requestCredentials = credentials.filter(
292
+ (credential) => credential.type === "request"
293
+ );
294
+ for (const credential of requestCredentials) normalizeRequestOrigins(credential.origins);
230
295
  const authenticatedFetch = async (url, requestOptions = {}) => {
231
- var _a, _b, _c;
296
+ var _a, _b, _c, _d;
297
+ requestOptions = mergeFetchOptions(fetchOptions, requestOptions);
298
+ if ((_a = requestOptions.signal) == null ? void 0 : _a.aborted) throw createAbortError();
299
+ if (!credentials.length) return baseFetch(url, requestOptions);
232
300
  const resolvedURL = parseHTTPURL(url);
233
- if (!resolvedURL) return baseFetch(url, requestOptions);
234
- const authorization = await authorizeRequest(resolvedURL, requestOptions, options.credentials);
235
- const response = await baseFetch(authorization.url, authorization.options);
301
+ const authorization = resolvedURL ? await authorizeRequest(resolvedURL, requestOptions, tokenCredentials) : { url, options: requestOptions, credentials: [] };
302
+ const signedRequest = await authenticateRequest(authorization, requestCredentials, "request");
303
+ const response = await baseFetch(signedRequest.url, signedRequest.options);
236
304
  const refreshableCredentials = authorization.credentials.filter(
237
305
  ({ credential }) => typeof credential.token === "function" && credential.refreshStatusCodes.includes(response.status)
238
306
  );
239
- if (!refreshableCredentials.length || !isReplayableRequest(requestOptions)) return response;
240
- if ((_a = requestOptions.signal) == null ? void 0 : _a.aborted) throw createAbortError();
307
+ const shouldRetrySignature = signedRequest.credentials.some(
308
+ (credential) => {
309
+ var _a2;
310
+ return (_a2 = credential.refreshStatusCodes) == null ? void 0 : _a2.includes(response.status);
311
+ }
312
+ );
313
+ if (!refreshableCredentials.length && !shouldRetrySignature || !isReplayableRequest(requestOptions) || !isReplayableRequest(signedRequest.options))
314
+ return response;
315
+ if ((_b = requestOptions.signal) == null ? void 0 : _b.aborted) throw createAbortError();
241
316
  const refreshedTokens = /* @__PURE__ */ new Map();
242
317
  await Promise.all(
243
318
  refreshableCredentials.map(async ({ credential }) => {
@@ -245,24 +320,111 @@ function createAuthenticatedFetch(options) {
245
320
  if (token) refreshedTokens.set(credential, token);
246
321
  })
247
322
  );
248
- if (!refreshedTokens.size) return response;
249
- await ((_b = response.body) == null ? void 0 : _b.cancel().catch(() => {
323
+ if (!refreshedTokens.size && !shouldRetrySignature) return response;
324
+ await ((_c = response.body) == null ? void 0 : _c.cancel().catch(() => {
250
325
  }));
251
- if ((_c = requestOptions.signal) == null ? void 0 : _c.aborted) throw createAbortError();
252
- const replayAuthorization = await authorizeRequest(
326
+ if ((_d = requestOptions.signal) == null ? void 0 : _d.aborted) throw createAbortError();
327
+ const replayAuthorization = resolvedURL ? await authorizeRequest(
253
328
  resolvedURL,
254
329
  requestOptions,
255
- options.credentials,
330
+ tokenCredentials,
256
331
  refreshedTokens,
257
332
  authorization.credentials
333
+ ) : { url, options: requestOptions };
334
+ const replayRequest = await authenticateRequest(
335
+ replayAuthorization,
336
+ requestCredentials,
337
+ "retry",
338
+ response
258
339
  );
259
- return baseFetch(replayAuthorization.url, replayAuthorization.options);
340
+ return baseFetch(replayRequest.url, replayRequest.options);
260
341
  };
261
342
  Object.defineProperty(authenticatedFetch, AUTHENTICATED_FETCH, {
262
- value: options.credentials
343
+ value: {
344
+ fetch: baseFetch,
345
+ credentials,
346
+ credentialResolutions,
347
+ fetchOptions
348
+ }
263
349
  });
264
350
  return authenticatedFetch;
265
351
  }
352
+ function getAuthenticatedFetch(options = {}) {
353
+ var _a, _b, _c;
354
+ const fetchOption = options.fetch ?? ((_a = options.core) == null ? void 0 : _a.fetch);
355
+ let fetchFunction;
356
+ if (typeof fetchOption === "function") {
357
+ fetchFunction = fetchOption;
358
+ } else {
359
+ fetchFunction = (url, requestOptions) => fetch(url, requestOptions);
360
+ }
361
+ return createAuthenticatedFetch({
362
+ fetch: fetchFunction,
363
+ fetchOptions: typeof fetchOption === "object" && fetchOption ? fetchOption : void 0,
364
+ credentials: ((_b = options.core) == null ? void 0 : _b.credentials) || [],
365
+ authentications: (_c = options.core) == null ? void 0 : _c.authentications
366
+ });
367
+ }
368
+ function mergeFetchOptions(defaultOptions, requestOptions) {
369
+ const mergedOptions = { ...defaultOptions, ...requestOptions };
370
+ if (defaultOptions.headers || (requestOptions == null ? void 0 : requestOptions.headers)) {
371
+ const headers = new Headers(defaultOptions.headers);
372
+ new Headers(requestOptions == null ? void 0 : requestOptions.headers).forEach((value, key) => headers.set(key, value));
373
+ mergedOptions.headers = headers;
374
+ }
375
+ return mergedOptions;
376
+ }
377
+ async function authenticateRequest(request, credentials, reason, response) {
378
+ const appliedCredentials = [];
379
+ const signal = request.options.signal;
380
+ for (const credential of credentials) {
381
+ const origin = getRequestOrigin(request.url);
382
+ if (!origin || !normalizeRequestOrigins(credential.origins).includes(origin)) continue;
383
+ if (signal == null ? void 0 : signal.aborted) throw createAbortError();
384
+ const authenticatedRequest = await credential.authenticate({
385
+ url: request.url,
386
+ options: { ...request.options, headers: new Headers(request.options.headers) },
387
+ reason,
388
+ response: response ? { status: response.status, headers: new Headers(response.headers) } : void 0
389
+ });
390
+ if (!authenticatedRequest || typeof authenticatedRequest.url !== "string" || !authenticatedRequest.options || typeof authenticatedRequest.options !== "object") {
391
+ throw new Error("Authentication callback returned an invalid request.");
392
+ }
393
+ request = {
394
+ url: authenticatedRequest.url,
395
+ options: { ...authenticatedRequest.options, ...signal ? { signal } : {} }
396
+ };
397
+ appliedCredentials.push(credential);
398
+ }
399
+ if (signal == null ? void 0 : signal.aborted) throw createAbortError();
400
+ return { ...request, credentials: appliedCredentials };
401
+ }
402
+ function getRequestOrigin(url) {
403
+ try {
404
+ const parsedURL = new URL(url);
405
+ if (!parsedURL.host || parsedURL.username || parsedURL.password) return null;
406
+ return parsedURL.origin !== "null" ? parsedURL.origin : `${parsedURL.protocol}//${parsedURL.host}`;
407
+ } catch {
408
+ return null;
409
+ }
410
+ }
411
+ function normalizeRequestOrigins(origins) {
412
+ if (!origins.length)
413
+ throw new Error("Request authentication requires at least one exact origin.");
414
+ return origins.map((origin) => {
415
+ const resolvedOrigin = getRequestOrigin(origin);
416
+ let url;
417
+ try {
418
+ url = new URL(origin);
419
+ } catch {
420
+ throw new Error("Invalid request authentication origin.");
421
+ }
422
+ if (!resolvedOrigin || url.pathname && url.pathname !== "/" || url.search || url.hash) {
423
+ throw new Error("Invalid request authentication origin.");
424
+ }
425
+ return resolvedOrigin;
426
+ });
427
+ }
266
428
  async function authorizeRequest(sourceURL, requestOptions, credentials, tokenOverrides = /* @__PURE__ */ new Map(), previousCredentials = []) {
267
429
  const url = new URL(sourceURL);
268
430
  const headers = new Headers(requestOptions.headers);
@@ -331,6 +493,7 @@ var AUTHENTICATED_FETCH, refreshPromises;
331
493
  var init_request_credentials = __esm({
332
494
  "../loader-utils/src/lib/request-utils/request-credentials.ts"() {
333
495
  "use strict";
496
+ init_authentication();
334
497
  AUTHENTICATED_FETCH = /* @__PURE__ */ Symbol("loaders.gl.authenticated-fetch");
335
498
  refreshPromises = /* @__PURE__ */ new WeakMap();
336
499
  }
@@ -387,39 +550,25 @@ var init_memory_conversion_utils = __esm({
387
550
 
388
551
  // ../loader-utils/src/lib/sources/data-source.ts
389
552
  function getFetchFunction(options) {
390
- var _a, _b;
391
- const fetchOption = (options == null ? void 0 : options.fetch) ?? ((_a = options == null ? void 0 : options.core) == null ? void 0 : _a.fetch);
392
- let fetchFunction;
393
- if (typeof fetchOption === "function") {
394
- fetchFunction = (url, fetchOptions) => fetchOption(url, fetchOptions);
395
- } else if (fetchOption) {
396
- fetchFunction = (url, requestOptions) => fetch(url, mergeFetchOptions(fetchOption, requestOptions));
397
- } else {
398
- fetchFunction = (url, requestOptions) => fetch(url, requestOptions);
399
- }
400
- return createAuthenticatedFetch({
401
- fetch: fetchFunction,
402
- credentials: ((_b = options == null ? void 0 : options.core) == null ? void 0 : _b.credentials) || []
403
- });
553
+ return getAuthenticatedFetch(options);
404
554
  }
405
- function mergeFetchOptions(fetchOptions, requestOptions) {
406
- const mergedOptions = { ...fetchOptions, ...requestOptions };
407
- if (fetchOptions.headers || (requestOptions == null ? void 0 : requestOptions.headers)) {
408
- mergedOptions.headers = mergeHeaders(fetchOptions.headers, requestOptions == null ? void 0 : requestOptions.headers);
409
- }
410
- return mergedOptions;
411
- }
412
- function mergeHeaders(defaultHeaders, requestHeaders) {
413
- const headers = new Headers(defaultHeaders);
414
- if (requestHeaders) {
415
- new Headers(requestHeaders).forEach((value, key) => headers.set(key, value));
555
+ function getSourceLoaderOptions(options) {
556
+ var _a;
557
+ if (options.loadOptions !== void 0 || ((_a = options.core) == null ? void 0 : _a.loadOptions) !== void 0) {
558
+ throw new Error(
559
+ "Source loadOptions and core.loadOptions were removed. Use core and root loader namespaces directly."
560
+ );
416
561
  }
417
- return headers;
418
- }
419
- function normalizeDirectLoaderOptions(options) {
420
562
  const loadOptions = { ...options };
421
563
  if (options == null ? void 0 : options.core) {
422
564
  loadOptions.core = { ...options.core };
565
+ const parserCore = loadOptions.core;
566
+ for (const key of ["type", "attributions", "loaders", "onError", "loadOptions"]) {
567
+ delete parserCore[key];
568
+ }
569
+ if (Object.keys(parserCore).length === 0) {
570
+ delete loadOptions.core;
571
+ }
423
572
  }
424
573
  const topLevelBaseUri = typeof loadOptions.baseUri === "string" ? loadOptions.baseUri : void 0;
425
574
  const topLevelBaseUrl = typeof loadOptions.baseUrl === "string" ? loadOptions.baseUrl : void 0;
@@ -457,6 +606,7 @@ var init_data_source = __esm({
457
606
  init_file_aliases();
458
607
  init_log();
459
608
  init_request_credentials();
609
+ init_authentication();
460
610
  UNAVAILABLE_CORE_API = {
461
611
  fetchFile: unavailableCoreApiMethod("fetchFile"),
462
612
  parse: unavailableCoreApiMethod("parse"),
@@ -471,7 +621,6 @@ var init_data_source = __esm({
471
621
  core: {
472
622
  type: "auto",
473
623
  attributions: [],
474
- loadOptions: {},
475
624
  loaders: [],
476
625
  onError: void 0
477
626
  }
@@ -480,9 +629,9 @@ var init_data_source = __esm({
480
629
  options;
481
630
  data;
482
631
  url;
483
- /** The actual load options, if calling a loaders.gl loader */
632
+ /** Shared parser options derived from the source options, excluding source-only core controls. */
484
633
  loadOptions;
485
- /** A resolved fetch function extracted from loadOptions prop */
634
+ /** A resolved fetch function extracted from the shared core options. */
486
635
  fetch;
487
636
  /** Shared source-level runtime hooks, when supplied by the source factory. */
488
637
  coreApi;
@@ -490,15 +639,13 @@ var init_data_source = __esm({
490
639
  hasCoreApi;
491
640
  _needsRefresh = true;
492
641
  constructor(data, options, defaultOptions, coreApi) {
493
- var _a;
494
- if (defaultOptions) {
495
- this.options = mergeOptions({ ...defaultOptions, core: _DataSource.defaultOptions }, options);
496
- } else {
497
- this.options = { ...options };
498
- }
642
+ this.options = mergeOptions(
643
+ mergeOptions(_DataSource.defaultOptions, defaultOptions || {}),
644
+ options
645
+ );
499
646
  this.data = data;
500
647
  this.url = typeof data === "string" ? resolvePath(data) : "";
501
- const loadOptions = normalizeDirectLoaderOptions((_a = this.options.core) == null ? void 0 : _a.loadOptions);
648
+ const loadOptions = resolveAuthenticationOptions(getSourceLoaderOptions(this.options));
502
649
  this.loadOptions = loadOptions;
503
650
  const fetch2 = getFetchFunction(loadOptions);
504
651
  this.coreApi = coreApi || UNAVAILABLE_CORE_API;
@@ -506,7 +653,11 @@ var init_data_source = __esm({
506
653
  this.fetch = fetch2;
507
654
  }
508
655
  setProps(options) {
509
- this.options = Object.assign(this.options, options);
656
+ const mergedOptions = mergeOptions(this.options, options);
657
+ const loadOptions = resolveAuthenticationOptions(getSourceLoaderOptions(mergedOptions));
658
+ this.options = mergedOptions;
659
+ this.loadOptions = loadOptions;
660
+ this.fetch = getFetchFunction(loadOptions);
510
661
  this.setNeedsRefresh();
511
662
  }
512
663
  /** Mark this data source as needing a refresh (redraw) */
@@ -1900,7 +2051,7 @@ var init_splat_loader_types = __esm({
1900
2051
  "dist/splat-loader-types.js"() {
1901
2052
  "use strict";
1902
2053
  init_splats_format();
1903
- VERSION2 = true ? "5.0.0-alpha.7" : "latest";
2054
+ VERSION2 = true ? "5.0.0-alpha.9" : "latest";
1904
2055
  SPLATLoader = {
1905
2056
  dataType: null,
1906
2057
  batchType: null,
@@ -2225,7 +2376,7 @@ var init_ksplat_loader_types = __esm({
2225
2376
  "dist/ksplat-loader-types.js"() {
2226
2377
  "use strict";
2227
2378
  init_splats_format();
2228
- VERSION3 = true ? "5.0.0-alpha.7" : "latest";
2379
+ VERSION3 = true ? "5.0.0-alpha.9" : "latest";
2229
2380
  KSPLATLoader = {
2230
2381
  dataType: null,
2231
2382
  batchType: null,
@@ -2270,7 +2421,7 @@ var init_spz_loader_types = __esm({
2270
2421
  "dist/spz-loader-types.js"() {
2271
2422
  "use strict";
2272
2423
  init_splats_format();
2273
- VERSION4 = true ? "5.0.0-alpha.7" : "latest";
2424
+ VERSION4 = true ? "5.0.0-alpha.9" : "latest";
2274
2425
  SPZLoader = {
2275
2426
  dataType: null,
2276
2427
  batchType: null,
@@ -3021,7 +3172,7 @@ var init_rad_loader_types = __esm({
3021
3172
  "dist/rad-loader-types.js"() {
3022
3173
  "use strict";
3023
3174
  init_splats_format();
3024
- VERSION5 = true ? "5.0.0-alpha.7" : "latest";
3175
+ VERSION5 = true ? "5.0.0-alpha.9" : "latest";
3025
3176
  RADLoader = {
3026
3177
  dataType: null,
3027
3178
  batchType: null,
@@ -3066,7 +3217,7 @@ init_parse_rad_chunk();
3066
3217
  init_splats_arrow_table();
3067
3218
  var DEFAULT_RAD_HEADER_BYTE_LENGTHS = [64 * 1024, 256 * 1024, 1024 * 1024];
3068
3219
  var DEFAULT_RAD_MAX_CONCURRENT_CHUNK_REQUESTS = 4;
3069
- var VERSION6 = true ? "5.0.0-alpha.7" : "latest";
3220
+ var VERSION6 = true ? "5.0.0-alpha.9" : "latest";
3070
3221
  var RADSourceLoader = {
3071
3222
  dataType: null,
3072
3223
  batchType: null,