@walkthru-earth/objex-utils 1.2.1 → 1.3.1

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/README.md CHANGED
@@ -29,6 +29,13 @@ import {
29
29
  extractEpsgFromGeoMeta,
30
30
  extractBounds,
31
31
 
32
+ // stac-geoparquet (detection + row → STAC Item)
33
+ isStacGeoparquetSchema,
34
+ stacRowToItem,
35
+ flattenStacBbox,
36
+ pickStacPrimaryAsset,
37
+ resolveStacAssetHref,
38
+
32
39
  // Storage URLs
33
40
  parseStorageUrl,
34
41
  resolveCloudUrl,
@@ -67,6 +74,7 @@ Full per-module developer reference lives in [`docs/`](./docs/README.md). Each p
67
74
  | [`docs/geometry.md`](./docs/geometry.md) | WKB parser, GeoArrow builder, geometry-column detection |
68
75
  | [`docs/cog.md`](./docs/cog.md) | Cloud-Optimized GeoTIFF pipeline helpers, band configs, color ramps |
69
76
  | [`docs/parquet-metadata.md`](./docs/parquet-metadata.md) | `readParquetMetadata` + CRS / bounds / geometry-type extractors |
77
+ | [`docs/stac-geoparquet.md`](./docs/stac-geoparquet.md) | stac-geoparquet detection + row → STAC Item transforms |
70
78
  | [`docs/storage.md`](./docs/storage.md) | URL parsing, provider registry, `StorageAdapter`, `UrlAdapter` |
71
79
  | [`docs/query-engine.md`](./docs/query-engine.md) | `QueryEngine` interface + handle / result types |
72
80
  | [`docs/file-types.md`](./docs/file-types.md) | File-type registry: `getFileTypeInfo`, `getViewerKind`, `getDuckDbReadFn`, … |
package/dist/index.cjs CHANGED
@@ -1,10 +1,5 @@
1
1
  'use strict';
2
2
 
3
- require('@developmentseed/epsg/all');
4
- require('@developmentseed/epsg/all.csv.gz?url');
5
- require('@developmentseed/geotiff');
6
- require('@developmentseed/proj');
7
- require('proj4');
8
3
  var apacheArrow = require('apache-arrow');
9
4
 
10
5
  // ../../src/lib/constants.ts
@@ -1462,6 +1457,8 @@ function resolveCloudUrl(url) {
1462
1457
  }
1463
1458
  return url;
1464
1459
  }
1460
+
1461
+ // ../../src/lib/utils/cog-pure.ts
1465
1462
  var SF_LABELS = {
1466
1463
  1: "uint",
1467
1464
  2: "int",
@@ -2477,6 +2474,15 @@ async function readParquetMetadata(url) {
2477
2474
  name: col.name,
2478
2475
  type: mapParquetType(col)
2479
2476
  }));
2477
+ const topLevelColumns = [];
2478
+ const root = metadata.schema[0];
2479
+ const rootChildren = root?.num_children ?? 0;
2480
+ let cursor = 1;
2481
+ for (let i = 0; i < rootChildren && cursor < metadata.schema.length; i++) {
2482
+ const el = metadata.schema[cursor];
2483
+ if (el?.name) topLevelColumns.push(el.name);
2484
+ cursor += countSubtree(metadata.schema, cursor);
2485
+ }
2480
2486
  let geo = null;
2481
2487
  let legacyGeoParquet = false;
2482
2488
  const geoKv = metadata.key_value_metadata?.find((kv) => kv.key === "geo");
@@ -2518,7 +2524,26 @@ async function readParquetMetadata(url) {
2518
2524
  compression = [...codecs].join(", ");
2519
2525
  }
2520
2526
  }
2521
- return { rowCount, schema, geo, legacyGeoParquet, createdBy, numRowGroups, compression };
2527
+ return {
2528
+ rowCount,
2529
+ schema,
2530
+ topLevelColumns,
2531
+ geo,
2532
+ legacyGeoParquet,
2533
+ createdBy,
2534
+ numRowGroups,
2535
+ compression
2536
+ };
2537
+ }
2538
+ function countSubtree(schema, start) {
2539
+ const el = schema[start];
2540
+ if (!el) return 0;
2541
+ const n = el.num_children ?? 0;
2542
+ let cursor = start + 1;
2543
+ for (let i = 0; i < n; i++) {
2544
+ cursor += countSubtree(schema, cursor);
2545
+ }
2546
+ return cursor - start;
2522
2547
  }
2523
2548
  function extractEpsgFromGeoMeta(geo) {
2524
2549
  const primaryCol = geo.columns[geo.primaryColumn];
@@ -2557,6 +2582,144 @@ function extractBounds(geo) {
2557
2582
  return [primaryCol.bbox[0], primaryCol.bbox[1], primaryCol.bbox[2], primaryCol.bbox[3]];
2558
2583
  }
2559
2584
 
2585
+ // ../../src/lib/utils/stac-geoparquet.ts
2586
+ var STAC_GEOPARQUET_REQUIRED_COLUMNS = [
2587
+ "stac_version",
2588
+ "type",
2589
+ "geometry",
2590
+ "assets"
2591
+ ];
2592
+ function isStacGeoparquetSchema(schema) {
2593
+ if (!Array.isArray(schema) || schema.length === 0) return false;
2594
+ const names = new Set(schema.map((c) => c.name));
2595
+ return STAC_GEOPARQUET_REQUIRED_COLUMNS.every((c) => names.has(c));
2596
+ }
2597
+ function flattenStacBbox(bbox) {
2598
+ if (!bbox) return null;
2599
+ if (Array.isArray(bbox)) {
2600
+ if (bbox.length < 4) return null;
2601
+ const [minX, minY, maxX, maxY] = bbox;
2602
+ if (![minX, minY, maxX, maxY].every((v) => Number.isFinite(v))) return null;
2603
+ return [minX, minY, maxX, maxY];
2604
+ }
2605
+ if (typeof bbox === "object") {
2606
+ const { xmin, ymin, xmax, ymax } = bbox;
2607
+ if (![xmin, ymin, xmax, ymax].every((v) => Number.isFinite(v))) return null;
2608
+ return [xmin, ymin, xmax, ymax];
2609
+ }
2610
+ return null;
2611
+ }
2612
+ function resolveStacAssetHref(href, baseUrl) {
2613
+ if (!href) return href;
2614
+ if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(href)) return href;
2615
+ try {
2616
+ return new URL(href, baseUrl).toString();
2617
+ } catch {
2618
+ return href;
2619
+ }
2620
+ }
2621
+ function pickStacPrimaryAsset(assets, preferredKeys) {
2622
+ if (!assets || typeof assets !== "object") return null;
2623
+ const entries = Object.entries(assets).filter(
2624
+ ([, a]) => a && typeof a === "object" && typeof a.href === "string"
2625
+ );
2626
+ if (entries.length === 0) return null;
2627
+ if (preferredKeys) {
2628
+ for (const key of preferredKeys) {
2629
+ const match = entries.find(([k]) => k === key);
2630
+ if (match) return { key: match[0], asset: match[1] };
2631
+ }
2632
+ }
2633
+ const data = entries.find(([k]) => k === "data");
2634
+ if (data) return { key: data[0], asset: data[1] };
2635
+ const byRole = entries.find(([, a]) => Array.isArray(a.roles) && a.roles.includes("data"));
2636
+ if (byRole) return { key: byRole[0], asset: byRole[1] };
2637
+ return { key: entries[0][0], asset: entries[0][1] };
2638
+ }
2639
+ function normalizeAssetsField(value, baseUrl) {
2640
+ if (!value || typeof value !== "object") return void 0;
2641
+ const out = {};
2642
+ for (const [key, raw] of Object.entries(value)) {
2643
+ if (!raw || typeof raw !== "object") continue;
2644
+ const asset = raw;
2645
+ if (typeof asset.href !== "string" || !asset.href) continue;
2646
+ out[key] = {
2647
+ ...asset,
2648
+ href: resolveStacAssetHref(asset.href, baseUrl)
2649
+ };
2650
+ }
2651
+ return Object.keys(out).length > 0 ? out : void 0;
2652
+ }
2653
+ function normalizeLinksField(value, baseUrl) {
2654
+ if (!Array.isArray(value)) return void 0;
2655
+ const links = [];
2656
+ for (const raw of value) {
2657
+ if (!raw || typeof raw !== "object") continue;
2658
+ const link = raw;
2659
+ if (typeof link.href !== "string" || typeof link.rel !== "string") continue;
2660
+ links.push({ ...link, href: resolveStacAssetHref(link.href, baseUrl) });
2661
+ }
2662
+ return links.length > 0 ? links : void 0;
2663
+ }
2664
+ function stacRowToItem(row, baseUrl, opts = {}) {
2665
+ const { wkbParser, wkbColumn = "geom_wkb", geometryColumn = "geometry" } = opts;
2666
+ let geometry = row[geometryColumn];
2667
+ if (!geometry) {
2668
+ const wkb = row[wkbColumn];
2669
+ if (wkb && wkbParser) {
2670
+ const bytes = wkb instanceof Uint8Array ? wkb : toUint8Array(wkb);
2671
+ if (bytes) {
2672
+ try {
2673
+ geometry = wkbParser(bytes) ?? void 0;
2674
+ } catch {
2675
+ geometry = void 0;
2676
+ }
2677
+ }
2678
+ }
2679
+ }
2680
+ const bbox = flattenStacBbox(row.bbox) ?? void 0;
2681
+ const assets = normalizeAssetsField(row.assets, baseUrl);
2682
+ const links = normalizeLinksField(row.links, baseUrl);
2683
+ const properties = {};
2684
+ for (const [key, value] of Object.entries(row)) {
2685
+ if (value === null || value === void 0) continue;
2686
+ if (key.startsWith("proj:") || key.startsWith("raster:") || key.startsWith("eo:")) {
2687
+ properties[key] = value;
2688
+ }
2689
+ if (key === "datetime") {
2690
+ properties.datetime = value instanceof Date ? value.toISOString() : String(value);
2691
+ }
2692
+ if (key === "bands") {
2693
+ properties.bands = value;
2694
+ }
2695
+ }
2696
+ const item = {
2697
+ type: "Feature",
2698
+ stac_version: typeof row.stac_version === "string" ? row.stac_version : "1.0.0",
2699
+ id: typeof row.id === "string" ? row.id : String(row.id ?? ""),
2700
+ properties
2701
+ };
2702
+ if (typeof row.collection === "string") item.collection = row.collection;
2703
+ if (Array.isArray(row.stac_extensions)) {
2704
+ item.stac_extensions = row.stac_extensions;
2705
+ }
2706
+ if (bbox) item.bbox = bbox;
2707
+ if (geometry) item.geometry = geometry;
2708
+ if (assets) item.assets = assets;
2709
+ if (links) item.links = links;
2710
+ return item;
2711
+ }
2712
+ function toUint8Array(value) {
2713
+ if (value instanceof Uint8Array) return value;
2714
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
2715
+ if (ArrayBuffer.isView(value)) {
2716
+ const view = value;
2717
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
2718
+ }
2719
+ if (Array.isArray(value)) return new Uint8Array(value);
2720
+ return null;
2721
+ }
2722
+
2560
2723
  // ../../src/lib/utils/storage-url.ts
2561
2724
  function buildSchemeMap() {
2562
2725
  const map = {};
@@ -2570,6 +2733,32 @@ function buildSchemeMap() {
2570
2733
  return map;
2571
2734
  }
2572
2735
  var SCHEME_MAP = buildSchemeMap();
2736
+ var AWS_VHOST_RE = /^(.+)\.s3[.-]([a-z0-9-]+)\.amazonaws\.com$/;
2737
+ var AWS_PATH_RE = /^s3[.-]([a-z0-9-]+)\.amazonaws\.com$/;
2738
+ var AWS_GLOBAL_HOST = "s3.amazonaws.com";
2739
+ var R2_RE = /^([a-z0-9]+)\.r2\.cloudflarestorage\.com$/;
2740
+ var GCS_GLOBAL_HOST = "storage.googleapis.com";
2741
+ var GCS_VHOST_RE = /^(.+)\.storage\.googleapis\.com$/;
2742
+ var DO_VHOST_RE = /^(.+)\.([a-z0-9-]+)\.digitaloceanspaces\.com$/;
2743
+ var DO_PATH_RE = /^([a-z0-9-]+)\.digitaloceanspaces\.com$/;
2744
+ var WASABI_RE = /^s3\.([a-z0-9-]+)\.wasabisys\.com$/;
2745
+ var B2_S3_RE = /^(.+)\.s3\.([a-z0-9-]+)\.backblazeb2\.com$/;
2746
+ var B2_NATIVE_RE = /^f[a-z0-9]+\.backblazeb2\.com$/;
2747
+ var OSS_RE = /^(.+)\.(oss-[a-z0-9-]+)\.aliyuncs\.com$/;
2748
+ var COS_RE = /^(.+)\.cos\.([a-z0-9-]+)\.myqcloud\.com$/;
2749
+ var YANDEX_HOST = "storage.yandexcloud.net";
2750
+ var CONTABO_RE = /^([a-z0-9]+)\.contabostorage\.com$/;
2751
+ var HETZNER_RE = /^([a-z0-9]+)\.your-objectstorage\.com$/;
2752
+ var LINODE_VHOST_RE = /^(.+)\.([a-z0-9-]+)\.linodeobjects\.com$/;
2753
+ var LINODE_PATH_RE = /^([a-z0-9-]+)\.linodeobjects\.com$/;
2754
+ var OVH_RE = /^s3\.([a-z0-9-]+)\.io\.cloud\.ovh\.(?:net|us)$/;
2755
+ var AZURE_BLOB_RE = /^([a-z0-9]+)\.blob\.core\.windows\.net$/;
2756
+ var STORJ_GATEWAY_RE = /^gateway\.(?:([a-z0-9]+)\.)?storjshare\.io$/;
2757
+ var STORJ_LINK_RE = /^link\.(?:([a-z0-9]+)\.)?storjshare\.io$/;
2758
+ function isMinioLikeHost(host) {
2759
+ return host.includes("minio") || host === "localhost" || host === "127.0.0.1" || host.startsWith("192.168.") || host.startsWith("10.");
2760
+ }
2761
+ var STAC_API_PATH_RE = /\/(collections|items|catalogs|search)(\/|\?|$)/i;
2573
2762
  function defaultResult(defaults) {
2574
2763
  return {
2575
2764
  bucket: "",
@@ -2610,7 +2799,7 @@ function parseStorageUrl(input, defaults = {}) {
2610
2799
  const url = new URL(trimmed);
2611
2800
  const host = url.hostname;
2612
2801
  const pathParts = url.pathname.replace(/^\//, "").split("/").filter(Boolean);
2613
- const awsVhost = host.match(/^(.+)\.s3[.-]([a-z0-9-]+)\.amazonaws\.com$/);
2802
+ const awsVhost = host.match(AWS_VHOST_RE);
2614
2803
  if (awsVhost) {
2615
2804
  return {
2616
2805
  bucket: awsVhost[1],
@@ -2620,7 +2809,7 @@ function parseStorageUrl(input, defaults = {}) {
2620
2809
  prefix: pathParts.join("/")
2621
2810
  };
2622
2811
  }
2623
- const awsPath = host.match(/^s3[.-]([a-z0-9-]+)\.amazonaws\.com$/);
2812
+ const awsPath = host.match(AWS_PATH_RE);
2624
2813
  if (awsPath && pathParts.length > 0) {
2625
2814
  return {
2626
2815
  bucket: pathParts[0],
@@ -2630,7 +2819,7 @@ function parseStorageUrl(input, defaults = {}) {
2630
2819
  prefix: pathParts.slice(1).join("/")
2631
2820
  };
2632
2821
  }
2633
- if (host === "s3.amazonaws.com" && pathParts.length > 0) {
2822
+ if (host === AWS_GLOBAL_HOST && pathParts.length > 0) {
2634
2823
  return {
2635
2824
  bucket: pathParts[0],
2636
2825
  region: defaults.region || "us-east-1",
@@ -2639,7 +2828,7 @@ function parseStorageUrl(input, defaults = {}) {
2639
2828
  prefix: pathParts.slice(1).join("/")
2640
2829
  };
2641
2830
  }
2642
- const r2Match = host.match(/^([a-z0-9]+)\.r2\.cloudflarestorage\.com$/);
2831
+ const r2Match = host.match(R2_RE);
2643
2832
  if (r2Match && pathParts.length > 0) {
2644
2833
  return {
2645
2834
  bucket: pathParts[0],
@@ -2649,7 +2838,7 @@ function parseStorageUrl(input, defaults = {}) {
2649
2838
  prefix: pathParts.slice(1).join("/")
2650
2839
  };
2651
2840
  }
2652
- if (host === "storage.googleapis.com" && pathParts.length > 0) {
2841
+ if (host === GCS_GLOBAL_HOST && pathParts.length > 0) {
2653
2842
  return {
2654
2843
  bucket: pathParts[0],
2655
2844
  region: defaults.region || "us",
@@ -2658,7 +2847,7 @@ function parseStorageUrl(input, defaults = {}) {
2658
2847
  prefix: pathParts.slice(1).join("/")
2659
2848
  };
2660
2849
  }
2661
- const gcsVhost = host.match(/^(.+)\.storage\.googleapis\.com$/);
2850
+ const gcsVhost = host.match(GCS_VHOST_RE);
2662
2851
  if (gcsVhost) {
2663
2852
  return {
2664
2853
  bucket: gcsVhost[1],
@@ -2668,7 +2857,7 @@ function parseStorageUrl(input, defaults = {}) {
2668
2857
  prefix: pathParts.join("/")
2669
2858
  };
2670
2859
  }
2671
- const doVhost = host.match(/^(.+)\.([a-z0-9-]+)\.digitaloceanspaces\.com$/);
2860
+ const doVhost = host.match(DO_VHOST_RE);
2672
2861
  if (doVhost) {
2673
2862
  return {
2674
2863
  bucket: doVhost[1],
@@ -2678,7 +2867,7 @@ function parseStorageUrl(input, defaults = {}) {
2678
2867
  prefix: pathParts.join("/")
2679
2868
  };
2680
2869
  }
2681
- const doPath = host.match(/^([a-z0-9-]+)\.digitaloceanspaces\.com$/);
2870
+ const doPath = host.match(DO_PATH_RE);
2682
2871
  if (doPath && pathParts.length > 0) {
2683
2872
  return {
2684
2873
  bucket: pathParts[0],
@@ -2688,7 +2877,7 @@ function parseStorageUrl(input, defaults = {}) {
2688
2877
  prefix: pathParts.slice(1).join("/")
2689
2878
  };
2690
2879
  }
2691
- const wasabiMatch = host.match(/^s3\.([a-z0-9-]+)\.wasabisys\.com$/);
2880
+ const wasabiMatch = host.match(WASABI_RE);
2692
2881
  if (wasabiMatch && pathParts.length > 0) {
2693
2882
  return {
2694
2883
  bucket: pathParts[0],
@@ -2698,7 +2887,7 @@ function parseStorageUrl(input, defaults = {}) {
2698
2887
  prefix: pathParts.slice(1).join("/")
2699
2888
  };
2700
2889
  }
2701
- const b2S3 = host.match(/^(.+)\.s3\.([a-z0-9-]+)\.backblazeb2\.com$/);
2890
+ const b2S3 = host.match(B2_S3_RE);
2702
2891
  if (b2S3) {
2703
2892
  return {
2704
2893
  bucket: b2S3[1],
@@ -2708,7 +2897,7 @@ function parseStorageUrl(input, defaults = {}) {
2708
2897
  prefix: pathParts.join("/")
2709
2898
  };
2710
2899
  }
2711
- const b2Native = host.match(/^f[a-z0-9]+\.backblazeb2\.com$/);
2900
+ const b2Native = host.match(B2_NATIVE_RE);
2712
2901
  if (b2Native && pathParts[0] === "file" && pathParts.length > 1) {
2713
2902
  return {
2714
2903
  bucket: pathParts[1],
@@ -2718,7 +2907,7 @@ function parseStorageUrl(input, defaults = {}) {
2718
2907
  prefix: pathParts.slice(2).join("/")
2719
2908
  };
2720
2909
  }
2721
- const ossMatch = host.match(/^(.+)\.(oss-[a-z0-9-]+)\.aliyuncs\.com$/);
2910
+ const ossMatch = host.match(OSS_RE);
2722
2911
  if (ossMatch) {
2723
2912
  return {
2724
2913
  bucket: ossMatch[1],
@@ -2728,7 +2917,7 @@ function parseStorageUrl(input, defaults = {}) {
2728
2917
  prefix: pathParts.join("/")
2729
2918
  };
2730
2919
  }
2731
- const cosMatch = host.match(/^(.+)\.cos\.([a-z0-9-]+)\.myqcloud\.com$/);
2920
+ const cosMatch = host.match(COS_RE);
2732
2921
  if (cosMatch) {
2733
2922
  return {
2734
2923
  bucket: cosMatch[1],
@@ -2738,7 +2927,7 @@ function parseStorageUrl(input, defaults = {}) {
2738
2927
  prefix: pathParts.join("/")
2739
2928
  };
2740
2929
  }
2741
- if (host === "storage.yandexcloud.net" && pathParts.length > 0) {
2930
+ if (host === YANDEX_HOST && pathParts.length > 0) {
2742
2931
  return {
2743
2932
  bucket: pathParts[0],
2744
2933
  region: defaults.region || "ru-central1",
@@ -2747,7 +2936,7 @@ function parseStorageUrl(input, defaults = {}) {
2747
2936
  prefix: pathParts.slice(1).join("/")
2748
2937
  };
2749
2938
  }
2750
- const contaboMatch = host.match(/^([a-z0-9]+)\.contabostorage\.com$/);
2939
+ const contaboMatch = host.match(CONTABO_RE);
2751
2940
  if (contaboMatch && pathParts.length > 0) {
2752
2941
  return {
2753
2942
  bucket: pathParts[0],
@@ -2757,7 +2946,7 @@ function parseStorageUrl(input, defaults = {}) {
2757
2946
  prefix: pathParts.slice(1).join("/")
2758
2947
  };
2759
2948
  }
2760
- const hetznerMatch = host.match(/^([a-z0-9]+)\.your-objectstorage\.com$/);
2949
+ const hetznerMatch = host.match(HETZNER_RE);
2761
2950
  if (hetznerMatch && pathParts.length > 0) {
2762
2951
  return {
2763
2952
  bucket: pathParts[0],
@@ -2767,7 +2956,7 @@ function parseStorageUrl(input, defaults = {}) {
2767
2956
  prefix: pathParts.slice(1).join("/")
2768
2957
  };
2769
2958
  }
2770
- const linodeVhost = host.match(/^(.+)\.([a-z0-9-]+)\.linodeobjects\.com$/);
2959
+ const linodeVhost = host.match(LINODE_VHOST_RE);
2771
2960
  if (linodeVhost) {
2772
2961
  return {
2773
2962
  bucket: linodeVhost[1],
@@ -2777,7 +2966,7 @@ function parseStorageUrl(input, defaults = {}) {
2777
2966
  prefix: pathParts.join("/")
2778
2967
  };
2779
2968
  }
2780
- const linodePath = host.match(/^([a-z0-9-]+)\.linodeobjects\.com$/);
2969
+ const linodePath = host.match(LINODE_PATH_RE);
2781
2970
  if (linodePath && pathParts.length > 0) {
2782
2971
  return {
2783
2972
  bucket: pathParts[0],
@@ -2787,7 +2976,7 @@ function parseStorageUrl(input, defaults = {}) {
2787
2976
  prefix: pathParts.slice(1).join("/")
2788
2977
  };
2789
2978
  }
2790
- const ovhMatch = host.match(/^s3\.([a-z0-9-]+)\.io\.cloud\.ovh\.(?:net|us)$/);
2979
+ const ovhMatch = host.match(OVH_RE);
2791
2980
  if (ovhMatch && pathParts.length > 0) {
2792
2981
  return {
2793
2982
  bucket: pathParts[0],
@@ -2797,8 +2986,7 @@ function parseStorageUrl(input, defaults = {}) {
2797
2986
  prefix: pathParts.slice(1).join("/")
2798
2987
  };
2799
2988
  }
2800
- const isMinioLike = host.includes("minio") || host === "localhost" || host === "127.0.0.1" || host.startsWith("192.168.") || host.startsWith("10.");
2801
- if (isMinioLike && pathParts.length > 0) {
2989
+ if (isMinioLikeHost(host) && pathParts.length > 0) {
2802
2990
  return {
2803
2991
  bucket: pathParts[0],
2804
2992
  region: defaults.region || "us-east-1",
@@ -2807,7 +2995,7 @@ function parseStorageUrl(input, defaults = {}) {
2807
2995
  prefix: pathParts.slice(1).join("/")
2808
2996
  };
2809
2997
  }
2810
- const azureBlob = host.match(/^([a-z0-9]+)\.blob\.core\.windows\.net$/);
2998
+ const azureBlob = host.match(AZURE_BLOB_RE);
2811
2999
  if (azureBlob && pathParts.length > 0) {
2812
3000
  return {
2813
3001
  bucket: pathParts[0],
@@ -2817,7 +3005,7 @@ function parseStorageUrl(input, defaults = {}) {
2817
3005
  prefix: pathParts.slice(1).join("/")
2818
3006
  };
2819
3007
  }
2820
- const storjGateway = host.match(/^gateway\.(?:([a-z0-9]+)\.)?storjshare\.io$/);
3008
+ const storjGateway = host.match(STORJ_GATEWAY_RE);
2821
3009
  if (storjGateway && pathParts.length > 0) {
2822
3010
  return {
2823
3011
  bucket: pathParts[0],
@@ -2827,7 +3015,7 @@ function parseStorageUrl(input, defaults = {}) {
2827
3015
  prefix: pathParts.slice(1).join("/")
2828
3016
  };
2829
3017
  }
2830
- const storjLink = host.match(/^link\.(?:([a-z0-9]+)\.)?storjshare\.io$/);
3018
+ const storjLink = host.match(STORJ_LINK_RE);
2831
3019
  if (storjLink && pathParts.length >= 3 && (pathParts[0] === "raw" || pathParts[0] === "s")) {
2832
3020
  return {
2833
3021
  bucket: pathParts[2],
@@ -2837,6 +3025,12 @@ function parseStorageUrl(input, defaults = {}) {
2837
3025
  prefix: pathParts.slice(3).join("/")
2838
3026
  };
2839
3027
  }
3028
+ if (STAC_API_PATH_RE.test(url.pathname)) {
3029
+ return {
3030
+ ...defaultResult(defaults),
3031
+ endpoint: `${url.protocol}//${url.host}`
3032
+ };
3033
+ }
2840
3034
  if (pathParts.length > 0) {
2841
3035
  const endpoint = `${url.protocol}//${url.host}`;
2842
3036
  return {
@@ -3146,6 +3340,7 @@ exports.PROVIDER_IDS = PROVIDER_IDS;
3146
3340
  exports.QueryCancelledError = QueryCancelledError;
3147
3341
  exports.SF_LABELS = SF_LABELS;
3148
3342
  exports.SQL_PREVIEW_LENGTH = SQL_PREVIEW_LENGTH;
3343
+ exports.STAC_GEOPARQUET_REQUIRED_COLUMNS = STAC_GEOPARQUET_REQUIRED_COLUMNS;
3149
3344
  exports.STORAGE_KEYS = STORAGE_KEYS;
3150
3345
  exports.UrlAdapter = UrlAdapter;
3151
3346
  exports.VIEWER_DIR_EXTENSIONS = VIEWER_DIR_EXTENSIONS;
@@ -3166,6 +3361,7 @@ exports.extractEpsgFromGeoMeta = extractEpsgFromGeoMeta;
3166
3361
  exports.extractGeometryTypes = extractGeometryTypes;
3167
3362
  exports.findGeoColumn = findGeoColumn;
3168
3363
  exports.findGeoColumnFromRows = findGeoColumnFromRows;
3364
+ exports.flattenStacBbox = flattenStacBbox;
3169
3365
  exports.formatDate = formatDate;
3170
3366
  exports.formatFileSize = formatFileSize;
3171
3367
  exports.formatValue = formatValue;
@@ -3184,6 +3380,7 @@ exports.isCloudNativeFormat = isCloudNativeFormat;
3184
3380
  exports.isGcsProvider = isGcsProvider;
3185
3381
  exports.isPubliclyStreamable = isPubliclyStreamable;
3186
3382
  exports.isQueryable = isQueryable;
3383
+ exports.isStacGeoparquetSchema = isStacGeoparquetSchema;
3187
3384
  exports.jsonReplacerBigInt = jsonReplacerBigInt;
3188
3385
  exports.loadFromStorage = loadFromStorage;
3189
3386
  exports.looksLikeUrl = looksLikeUrl;
@@ -3193,14 +3390,17 @@ exports.parseMarkdownDocument = parseMarkdownDocument;
3193
3390
  exports.parseStorageUrl = parseStorageUrl;
3194
3391
  exports.parseWKB = parseWKB;
3195
3392
  exports.persistToStorage = persistToStorage;
3393
+ exports.pickStacPrimaryAsset = pickStacPrimaryAsset;
3196
3394
  exports.readParquetMetadata = readParquetMetadata;
3197
3395
  exports.resolveCloudUrl = resolveCloudUrl;
3198
3396
  exports.resolveProviderEndpoint = resolveProviderEndpoint;
3397
+ exports.resolveStacAssetHref = resolveStacAssetHref;
3199
3398
  exports.safeClamp = safeClamp;
3200
3399
  exports.safeDecodeURIComponent = safeDecodeURIComponent;
3201
3400
  exports.serializeToCsv = serializeToCsv;
3202
3401
  exports.serializeToJson = serializeToJson;
3203
3402
  exports.sortFileEntries = sortFileEntries;
3403
+ exports.stacRowToItem = stacRowToItem;
3204
3404
  exports.toBinary = toBinary;
3205
3405
  exports.toggleSortField = toggleSortField;
3206
3406
  exports.typeBadgeClass = typeBadgeClass;