@walkthru-earth/objex-utils 1.2.0 → 1.3.0
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 +8 -0
- package/dist/index.cjs +280 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +178 -2
- package/dist/index.d.ts +178 -2
- package/dist/index.js +270 -31
- package/dist/index.js.map +1 -1
- package/docs/README.md +1 -0
- package/docs/cog.md +14 -225
- package/docs/parquet-metadata.md +9 -1
- package/docs/stac-geoparquet.md +198 -0
- package/docs/storage.md +2 -0
- package/package.json +9 -4
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
|
@@ -1357,6 +1357,11 @@ function buildEndpointFromTemplate(id, region) {
|
|
|
1357
1357
|
if (!def?.endpointTemplate) return "";
|
|
1358
1358
|
return def.endpointTemplate.replace("{region}", region);
|
|
1359
1359
|
}
|
|
1360
|
+
function resolveProviderEndpoint(provider, region) {
|
|
1361
|
+
const def = PROVIDERS[provider];
|
|
1362
|
+
if (!def?.endpointTemplate) return "";
|
|
1363
|
+
return buildEndpointFromTemplate(provider, region || def.defaultRegion);
|
|
1364
|
+
}
|
|
1360
1365
|
function buildProviderBaseUrl(provider, endpoint, bucket, region) {
|
|
1361
1366
|
if (endpoint) {
|
|
1362
1367
|
return `${endpoint.replace(/\/$/, "")}/${bucket}`;
|
|
@@ -1371,6 +1376,15 @@ function buildProviderBaseUrl(provider, endpoint, bucket, region) {
|
|
|
1371
1376
|
function isGcsProvider(provider, endpoint) {
|
|
1372
1377
|
return provider === "gcs" || !!endpoint && /storage\.googleapis\.com/i.test(endpoint);
|
|
1373
1378
|
}
|
|
1379
|
+
function getAccessMode(conn) {
|
|
1380
|
+
if (conn.provider === "azure") return "sas-https";
|
|
1381
|
+
if (conn.anonymous) return "public-https";
|
|
1382
|
+
return "signed-s3";
|
|
1383
|
+
}
|
|
1384
|
+
function isPubliclyStreamable(conn) {
|
|
1385
|
+
const mode = getAccessMode(conn);
|
|
1386
|
+
return mode === "public-https" || mode === "sas-https";
|
|
1387
|
+
}
|
|
1374
1388
|
|
|
1375
1389
|
// ../../src/lib/storage/url-adapter.ts
|
|
1376
1390
|
var UrlAdapter = class {
|
|
@@ -1640,6 +1654,17 @@ function formatValue(value) {
|
|
|
1640
1654
|
}
|
|
1641
1655
|
|
|
1642
1656
|
// ../../src/lib/utils/export.ts
|
|
1657
|
+
function triggerDownload(content, filename, mimeType) {
|
|
1658
|
+
const blob = new Blob([content], { type: mimeType });
|
|
1659
|
+
const url = URL.createObjectURL(blob);
|
|
1660
|
+
const a = document.createElement("a");
|
|
1661
|
+
a.href = url;
|
|
1662
|
+
a.download = filename;
|
|
1663
|
+
document.body.appendChild(a);
|
|
1664
|
+
a.click();
|
|
1665
|
+
document.body.removeChild(a);
|
|
1666
|
+
URL.revokeObjectURL(url);
|
|
1667
|
+
}
|
|
1643
1668
|
function formatCellValue(value) {
|
|
1644
1669
|
if (value === null || value === void 0) return "";
|
|
1645
1670
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -1674,6 +1699,20 @@ function serializeToJson(columns, rows) {
|
|
|
1674
1699
|
});
|
|
1675
1700
|
return JSON.stringify(data, jsonReplacerBigInt, 2);
|
|
1676
1701
|
}
|
|
1702
|
+
function exportToCsv(columns, rows, filename) {
|
|
1703
|
+
triggerDownload(
|
|
1704
|
+
serializeToCsv(columns, rows),
|
|
1705
|
+
filename.endsWith(".csv") ? filename : `${filename}.csv`,
|
|
1706
|
+
"text/csv;charset=utf-8;"
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
function exportToJson(columns, rows, filename) {
|
|
1710
|
+
triggerDownload(
|
|
1711
|
+
serializeToJson(columns, rows),
|
|
1712
|
+
filename.endsWith(".json") ? filename : `${filename}.json`,
|
|
1713
|
+
"application/json"
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1677
1716
|
|
|
1678
1717
|
// ../../src/lib/utils/file-sort.ts
|
|
1679
1718
|
function sortFileEntries(entries, config) {
|
|
@@ -2438,6 +2477,15 @@ async function readParquetMetadata(url) {
|
|
|
2438
2477
|
name: col.name,
|
|
2439
2478
|
type: mapParquetType(col)
|
|
2440
2479
|
}));
|
|
2480
|
+
const topLevelColumns = [];
|
|
2481
|
+
const root = metadata.schema[0];
|
|
2482
|
+
const rootChildren = root?.num_children ?? 0;
|
|
2483
|
+
let cursor = 1;
|
|
2484
|
+
for (let i = 0; i < rootChildren && cursor < metadata.schema.length; i++) {
|
|
2485
|
+
const el = metadata.schema[cursor];
|
|
2486
|
+
if (el?.name) topLevelColumns.push(el.name);
|
|
2487
|
+
cursor += countSubtree(metadata.schema, cursor);
|
|
2488
|
+
}
|
|
2441
2489
|
let geo = null;
|
|
2442
2490
|
let legacyGeoParquet = false;
|
|
2443
2491
|
const geoKv = metadata.key_value_metadata?.find((kv) => kv.key === "geo");
|
|
@@ -2479,7 +2527,26 @@ async function readParquetMetadata(url) {
|
|
|
2479
2527
|
compression = [...codecs].join(", ");
|
|
2480
2528
|
}
|
|
2481
2529
|
}
|
|
2482
|
-
return {
|
|
2530
|
+
return {
|
|
2531
|
+
rowCount,
|
|
2532
|
+
schema,
|
|
2533
|
+
topLevelColumns,
|
|
2534
|
+
geo,
|
|
2535
|
+
legacyGeoParquet,
|
|
2536
|
+
createdBy,
|
|
2537
|
+
numRowGroups,
|
|
2538
|
+
compression
|
|
2539
|
+
};
|
|
2540
|
+
}
|
|
2541
|
+
function countSubtree(schema, start) {
|
|
2542
|
+
const el = schema[start];
|
|
2543
|
+
if (!el) return 0;
|
|
2544
|
+
const n = el.num_children ?? 0;
|
|
2545
|
+
let cursor = start + 1;
|
|
2546
|
+
for (let i = 0; i < n; i++) {
|
|
2547
|
+
cursor += countSubtree(schema, cursor);
|
|
2548
|
+
}
|
|
2549
|
+
return cursor - start;
|
|
2483
2550
|
}
|
|
2484
2551
|
function extractEpsgFromGeoMeta(geo) {
|
|
2485
2552
|
const primaryCol = geo.columns[geo.primaryColumn];
|
|
@@ -2518,6 +2585,144 @@ function extractBounds(geo) {
|
|
|
2518
2585
|
return [primaryCol.bbox[0], primaryCol.bbox[1], primaryCol.bbox[2], primaryCol.bbox[3]];
|
|
2519
2586
|
}
|
|
2520
2587
|
|
|
2588
|
+
// ../../src/lib/utils/stac-geoparquet.ts
|
|
2589
|
+
var STAC_GEOPARQUET_REQUIRED_COLUMNS = [
|
|
2590
|
+
"stac_version",
|
|
2591
|
+
"type",
|
|
2592
|
+
"geometry",
|
|
2593
|
+
"assets"
|
|
2594
|
+
];
|
|
2595
|
+
function isStacGeoparquetSchema(schema) {
|
|
2596
|
+
if (!Array.isArray(schema) || schema.length === 0) return false;
|
|
2597
|
+
const names = new Set(schema.map((c) => c.name));
|
|
2598
|
+
return STAC_GEOPARQUET_REQUIRED_COLUMNS.every((c) => names.has(c));
|
|
2599
|
+
}
|
|
2600
|
+
function flattenStacBbox(bbox) {
|
|
2601
|
+
if (!bbox) return null;
|
|
2602
|
+
if (Array.isArray(bbox)) {
|
|
2603
|
+
if (bbox.length < 4) return null;
|
|
2604
|
+
const [minX, minY, maxX, maxY] = bbox;
|
|
2605
|
+
if (![minX, minY, maxX, maxY].every((v) => Number.isFinite(v))) return null;
|
|
2606
|
+
return [minX, minY, maxX, maxY];
|
|
2607
|
+
}
|
|
2608
|
+
if (typeof bbox === "object") {
|
|
2609
|
+
const { xmin, ymin, xmax, ymax } = bbox;
|
|
2610
|
+
if (![xmin, ymin, xmax, ymax].every((v) => Number.isFinite(v))) return null;
|
|
2611
|
+
return [xmin, ymin, xmax, ymax];
|
|
2612
|
+
}
|
|
2613
|
+
return null;
|
|
2614
|
+
}
|
|
2615
|
+
function resolveStacAssetHref(href, baseUrl) {
|
|
2616
|
+
if (!href) return href;
|
|
2617
|
+
if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(href)) return href;
|
|
2618
|
+
try {
|
|
2619
|
+
return new URL(href, baseUrl).toString();
|
|
2620
|
+
} catch {
|
|
2621
|
+
return href;
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
function pickStacPrimaryAsset(assets, preferredKeys) {
|
|
2625
|
+
if (!assets || typeof assets !== "object") return null;
|
|
2626
|
+
const entries = Object.entries(assets).filter(
|
|
2627
|
+
([, a]) => a && typeof a === "object" && typeof a.href === "string"
|
|
2628
|
+
);
|
|
2629
|
+
if (entries.length === 0) return null;
|
|
2630
|
+
if (preferredKeys) {
|
|
2631
|
+
for (const key of preferredKeys) {
|
|
2632
|
+
const match = entries.find(([k]) => k === key);
|
|
2633
|
+
if (match) return { key: match[0], asset: match[1] };
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
const data = entries.find(([k]) => k === "data");
|
|
2637
|
+
if (data) return { key: data[0], asset: data[1] };
|
|
2638
|
+
const byRole = entries.find(([, a]) => Array.isArray(a.roles) && a.roles.includes("data"));
|
|
2639
|
+
if (byRole) return { key: byRole[0], asset: byRole[1] };
|
|
2640
|
+
return { key: entries[0][0], asset: entries[0][1] };
|
|
2641
|
+
}
|
|
2642
|
+
function normalizeAssetsField(value, baseUrl) {
|
|
2643
|
+
if (!value || typeof value !== "object") return void 0;
|
|
2644
|
+
const out = {};
|
|
2645
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
2646
|
+
if (!raw || typeof raw !== "object") continue;
|
|
2647
|
+
const asset = raw;
|
|
2648
|
+
if (typeof asset.href !== "string" || !asset.href) continue;
|
|
2649
|
+
out[key] = {
|
|
2650
|
+
...asset,
|
|
2651
|
+
href: resolveStacAssetHref(asset.href, baseUrl)
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2655
|
+
}
|
|
2656
|
+
function normalizeLinksField(value, baseUrl) {
|
|
2657
|
+
if (!Array.isArray(value)) return void 0;
|
|
2658
|
+
const links = [];
|
|
2659
|
+
for (const raw of value) {
|
|
2660
|
+
if (!raw || typeof raw !== "object") continue;
|
|
2661
|
+
const link = raw;
|
|
2662
|
+
if (typeof link.href !== "string" || typeof link.rel !== "string") continue;
|
|
2663
|
+
links.push({ ...link, href: resolveStacAssetHref(link.href, baseUrl) });
|
|
2664
|
+
}
|
|
2665
|
+
return links.length > 0 ? links : void 0;
|
|
2666
|
+
}
|
|
2667
|
+
function stacRowToItem(row, baseUrl, opts = {}) {
|
|
2668
|
+
const { wkbParser, wkbColumn = "geom_wkb", geometryColumn = "geometry" } = opts;
|
|
2669
|
+
let geometry = row[geometryColumn];
|
|
2670
|
+
if (!geometry) {
|
|
2671
|
+
const wkb = row[wkbColumn];
|
|
2672
|
+
if (wkb && wkbParser) {
|
|
2673
|
+
const bytes = wkb instanceof Uint8Array ? wkb : toUint8Array(wkb);
|
|
2674
|
+
if (bytes) {
|
|
2675
|
+
try {
|
|
2676
|
+
geometry = wkbParser(bytes) ?? void 0;
|
|
2677
|
+
} catch {
|
|
2678
|
+
geometry = void 0;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
const bbox = flattenStacBbox(row.bbox) ?? void 0;
|
|
2684
|
+
const assets = normalizeAssetsField(row.assets, baseUrl);
|
|
2685
|
+
const links = normalizeLinksField(row.links, baseUrl);
|
|
2686
|
+
const properties = {};
|
|
2687
|
+
for (const [key, value] of Object.entries(row)) {
|
|
2688
|
+
if (value === null || value === void 0) continue;
|
|
2689
|
+
if (key.startsWith("proj:") || key.startsWith("raster:") || key.startsWith("eo:")) {
|
|
2690
|
+
properties[key] = value;
|
|
2691
|
+
}
|
|
2692
|
+
if (key === "datetime") {
|
|
2693
|
+
properties.datetime = value instanceof Date ? value.toISOString() : String(value);
|
|
2694
|
+
}
|
|
2695
|
+
if (key === "bands") {
|
|
2696
|
+
properties.bands = value;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
const item = {
|
|
2700
|
+
type: "Feature",
|
|
2701
|
+
stac_version: typeof row.stac_version === "string" ? row.stac_version : "1.0.0",
|
|
2702
|
+
id: typeof row.id === "string" ? row.id : String(row.id ?? ""),
|
|
2703
|
+
properties
|
|
2704
|
+
};
|
|
2705
|
+
if (typeof row.collection === "string") item.collection = row.collection;
|
|
2706
|
+
if (Array.isArray(row.stac_extensions)) {
|
|
2707
|
+
item.stac_extensions = row.stac_extensions;
|
|
2708
|
+
}
|
|
2709
|
+
if (bbox) item.bbox = bbox;
|
|
2710
|
+
if (geometry) item.geometry = geometry;
|
|
2711
|
+
if (assets) item.assets = assets;
|
|
2712
|
+
if (links) item.links = links;
|
|
2713
|
+
return item;
|
|
2714
|
+
}
|
|
2715
|
+
function toUint8Array(value) {
|
|
2716
|
+
if (value instanceof Uint8Array) return value;
|
|
2717
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
2718
|
+
if (ArrayBuffer.isView(value)) {
|
|
2719
|
+
const view = value;
|
|
2720
|
+
return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
|
|
2721
|
+
}
|
|
2722
|
+
if (Array.isArray(value)) return new Uint8Array(value);
|
|
2723
|
+
return null;
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2521
2726
|
// ../../src/lib/utils/storage-url.ts
|
|
2522
2727
|
function buildSchemeMap() {
|
|
2523
2728
|
const map = {};
|
|
@@ -2531,6 +2736,32 @@ function buildSchemeMap() {
|
|
|
2531
2736
|
return map;
|
|
2532
2737
|
}
|
|
2533
2738
|
var SCHEME_MAP = buildSchemeMap();
|
|
2739
|
+
var AWS_VHOST_RE = /^(.+)\.s3[.-]([a-z0-9-]+)\.amazonaws\.com$/;
|
|
2740
|
+
var AWS_PATH_RE = /^s3[.-]([a-z0-9-]+)\.amazonaws\.com$/;
|
|
2741
|
+
var AWS_GLOBAL_HOST = "s3.amazonaws.com";
|
|
2742
|
+
var R2_RE = /^([a-z0-9]+)\.r2\.cloudflarestorage\.com$/;
|
|
2743
|
+
var GCS_GLOBAL_HOST = "storage.googleapis.com";
|
|
2744
|
+
var GCS_VHOST_RE = /^(.+)\.storage\.googleapis\.com$/;
|
|
2745
|
+
var DO_VHOST_RE = /^(.+)\.([a-z0-9-]+)\.digitaloceanspaces\.com$/;
|
|
2746
|
+
var DO_PATH_RE = /^([a-z0-9-]+)\.digitaloceanspaces\.com$/;
|
|
2747
|
+
var WASABI_RE = /^s3\.([a-z0-9-]+)\.wasabisys\.com$/;
|
|
2748
|
+
var B2_S3_RE = /^(.+)\.s3\.([a-z0-9-]+)\.backblazeb2\.com$/;
|
|
2749
|
+
var B2_NATIVE_RE = /^f[a-z0-9]+\.backblazeb2\.com$/;
|
|
2750
|
+
var OSS_RE = /^(.+)\.(oss-[a-z0-9-]+)\.aliyuncs\.com$/;
|
|
2751
|
+
var COS_RE = /^(.+)\.cos\.([a-z0-9-]+)\.myqcloud\.com$/;
|
|
2752
|
+
var YANDEX_HOST = "storage.yandexcloud.net";
|
|
2753
|
+
var CONTABO_RE = /^([a-z0-9]+)\.contabostorage\.com$/;
|
|
2754
|
+
var HETZNER_RE = /^([a-z0-9]+)\.your-objectstorage\.com$/;
|
|
2755
|
+
var LINODE_VHOST_RE = /^(.+)\.([a-z0-9-]+)\.linodeobjects\.com$/;
|
|
2756
|
+
var LINODE_PATH_RE = /^([a-z0-9-]+)\.linodeobjects\.com$/;
|
|
2757
|
+
var OVH_RE = /^s3\.([a-z0-9-]+)\.io\.cloud\.ovh\.(?:net|us)$/;
|
|
2758
|
+
var AZURE_BLOB_RE = /^([a-z0-9]+)\.blob\.core\.windows\.net$/;
|
|
2759
|
+
var STORJ_GATEWAY_RE = /^gateway\.(?:([a-z0-9]+)\.)?storjshare\.io$/;
|
|
2760
|
+
var STORJ_LINK_RE = /^link\.(?:([a-z0-9]+)\.)?storjshare\.io$/;
|
|
2761
|
+
function isMinioLikeHost(host) {
|
|
2762
|
+
return host.includes("minio") || host === "localhost" || host === "127.0.0.1" || host.startsWith("192.168.") || host.startsWith("10.");
|
|
2763
|
+
}
|
|
2764
|
+
var STAC_API_PATH_RE = /\/(collections|items|catalogs|search)(\/|\?|$)/i;
|
|
2534
2765
|
function defaultResult(defaults) {
|
|
2535
2766
|
return {
|
|
2536
2767
|
bucket: "",
|
|
@@ -2571,7 +2802,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2571
2802
|
const url = new URL(trimmed);
|
|
2572
2803
|
const host = url.hostname;
|
|
2573
2804
|
const pathParts = url.pathname.replace(/^\//, "").split("/").filter(Boolean);
|
|
2574
|
-
const awsVhost = host.match(
|
|
2805
|
+
const awsVhost = host.match(AWS_VHOST_RE);
|
|
2575
2806
|
if (awsVhost) {
|
|
2576
2807
|
return {
|
|
2577
2808
|
bucket: awsVhost[1],
|
|
@@ -2581,7 +2812,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2581
2812
|
prefix: pathParts.join("/")
|
|
2582
2813
|
};
|
|
2583
2814
|
}
|
|
2584
|
-
const awsPath = host.match(
|
|
2815
|
+
const awsPath = host.match(AWS_PATH_RE);
|
|
2585
2816
|
if (awsPath && pathParts.length > 0) {
|
|
2586
2817
|
return {
|
|
2587
2818
|
bucket: pathParts[0],
|
|
@@ -2591,7 +2822,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2591
2822
|
prefix: pathParts.slice(1).join("/")
|
|
2592
2823
|
};
|
|
2593
2824
|
}
|
|
2594
|
-
if (host ===
|
|
2825
|
+
if (host === AWS_GLOBAL_HOST && pathParts.length > 0) {
|
|
2595
2826
|
return {
|
|
2596
2827
|
bucket: pathParts[0],
|
|
2597
2828
|
region: defaults.region || "us-east-1",
|
|
@@ -2600,7 +2831,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2600
2831
|
prefix: pathParts.slice(1).join("/")
|
|
2601
2832
|
};
|
|
2602
2833
|
}
|
|
2603
|
-
const r2Match = host.match(
|
|
2834
|
+
const r2Match = host.match(R2_RE);
|
|
2604
2835
|
if (r2Match && pathParts.length > 0) {
|
|
2605
2836
|
return {
|
|
2606
2837
|
bucket: pathParts[0],
|
|
@@ -2610,7 +2841,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2610
2841
|
prefix: pathParts.slice(1).join("/")
|
|
2611
2842
|
};
|
|
2612
2843
|
}
|
|
2613
|
-
if (host ===
|
|
2844
|
+
if (host === GCS_GLOBAL_HOST && pathParts.length > 0) {
|
|
2614
2845
|
return {
|
|
2615
2846
|
bucket: pathParts[0],
|
|
2616
2847
|
region: defaults.region || "us",
|
|
@@ -2619,7 +2850,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2619
2850
|
prefix: pathParts.slice(1).join("/")
|
|
2620
2851
|
};
|
|
2621
2852
|
}
|
|
2622
|
-
const gcsVhost = host.match(
|
|
2853
|
+
const gcsVhost = host.match(GCS_VHOST_RE);
|
|
2623
2854
|
if (gcsVhost) {
|
|
2624
2855
|
return {
|
|
2625
2856
|
bucket: gcsVhost[1],
|
|
@@ -2629,7 +2860,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2629
2860
|
prefix: pathParts.join("/")
|
|
2630
2861
|
};
|
|
2631
2862
|
}
|
|
2632
|
-
const doVhost = host.match(
|
|
2863
|
+
const doVhost = host.match(DO_VHOST_RE);
|
|
2633
2864
|
if (doVhost) {
|
|
2634
2865
|
return {
|
|
2635
2866
|
bucket: doVhost[1],
|
|
@@ -2639,7 +2870,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2639
2870
|
prefix: pathParts.join("/")
|
|
2640
2871
|
};
|
|
2641
2872
|
}
|
|
2642
|
-
const doPath = host.match(
|
|
2873
|
+
const doPath = host.match(DO_PATH_RE);
|
|
2643
2874
|
if (doPath && pathParts.length > 0) {
|
|
2644
2875
|
return {
|
|
2645
2876
|
bucket: pathParts[0],
|
|
@@ -2649,7 +2880,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2649
2880
|
prefix: pathParts.slice(1).join("/")
|
|
2650
2881
|
};
|
|
2651
2882
|
}
|
|
2652
|
-
const wasabiMatch = host.match(
|
|
2883
|
+
const wasabiMatch = host.match(WASABI_RE);
|
|
2653
2884
|
if (wasabiMatch && pathParts.length > 0) {
|
|
2654
2885
|
return {
|
|
2655
2886
|
bucket: pathParts[0],
|
|
@@ -2659,7 +2890,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2659
2890
|
prefix: pathParts.slice(1).join("/")
|
|
2660
2891
|
};
|
|
2661
2892
|
}
|
|
2662
|
-
const b2S3 = host.match(
|
|
2893
|
+
const b2S3 = host.match(B2_S3_RE);
|
|
2663
2894
|
if (b2S3) {
|
|
2664
2895
|
return {
|
|
2665
2896
|
bucket: b2S3[1],
|
|
@@ -2669,7 +2900,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2669
2900
|
prefix: pathParts.join("/")
|
|
2670
2901
|
};
|
|
2671
2902
|
}
|
|
2672
|
-
const b2Native = host.match(
|
|
2903
|
+
const b2Native = host.match(B2_NATIVE_RE);
|
|
2673
2904
|
if (b2Native && pathParts[0] === "file" && pathParts.length > 1) {
|
|
2674
2905
|
return {
|
|
2675
2906
|
bucket: pathParts[1],
|
|
@@ -2679,7 +2910,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2679
2910
|
prefix: pathParts.slice(2).join("/")
|
|
2680
2911
|
};
|
|
2681
2912
|
}
|
|
2682
|
-
const ossMatch = host.match(
|
|
2913
|
+
const ossMatch = host.match(OSS_RE);
|
|
2683
2914
|
if (ossMatch) {
|
|
2684
2915
|
return {
|
|
2685
2916
|
bucket: ossMatch[1],
|
|
@@ -2689,7 +2920,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2689
2920
|
prefix: pathParts.join("/")
|
|
2690
2921
|
};
|
|
2691
2922
|
}
|
|
2692
|
-
const cosMatch = host.match(
|
|
2923
|
+
const cosMatch = host.match(COS_RE);
|
|
2693
2924
|
if (cosMatch) {
|
|
2694
2925
|
return {
|
|
2695
2926
|
bucket: cosMatch[1],
|
|
@@ -2699,7 +2930,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2699
2930
|
prefix: pathParts.join("/")
|
|
2700
2931
|
};
|
|
2701
2932
|
}
|
|
2702
|
-
if (host ===
|
|
2933
|
+
if (host === YANDEX_HOST && pathParts.length > 0) {
|
|
2703
2934
|
return {
|
|
2704
2935
|
bucket: pathParts[0],
|
|
2705
2936
|
region: defaults.region || "ru-central1",
|
|
@@ -2708,7 +2939,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2708
2939
|
prefix: pathParts.slice(1).join("/")
|
|
2709
2940
|
};
|
|
2710
2941
|
}
|
|
2711
|
-
const contaboMatch = host.match(
|
|
2942
|
+
const contaboMatch = host.match(CONTABO_RE);
|
|
2712
2943
|
if (contaboMatch && pathParts.length > 0) {
|
|
2713
2944
|
return {
|
|
2714
2945
|
bucket: pathParts[0],
|
|
@@ -2718,7 +2949,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2718
2949
|
prefix: pathParts.slice(1).join("/")
|
|
2719
2950
|
};
|
|
2720
2951
|
}
|
|
2721
|
-
const hetznerMatch = host.match(
|
|
2952
|
+
const hetznerMatch = host.match(HETZNER_RE);
|
|
2722
2953
|
if (hetznerMatch && pathParts.length > 0) {
|
|
2723
2954
|
return {
|
|
2724
2955
|
bucket: pathParts[0],
|
|
@@ -2728,7 +2959,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2728
2959
|
prefix: pathParts.slice(1).join("/")
|
|
2729
2960
|
};
|
|
2730
2961
|
}
|
|
2731
|
-
const linodeVhost = host.match(
|
|
2962
|
+
const linodeVhost = host.match(LINODE_VHOST_RE);
|
|
2732
2963
|
if (linodeVhost) {
|
|
2733
2964
|
return {
|
|
2734
2965
|
bucket: linodeVhost[1],
|
|
@@ -2738,7 +2969,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2738
2969
|
prefix: pathParts.join("/")
|
|
2739
2970
|
};
|
|
2740
2971
|
}
|
|
2741
|
-
const linodePath = host.match(
|
|
2972
|
+
const linodePath = host.match(LINODE_PATH_RE);
|
|
2742
2973
|
if (linodePath && pathParts.length > 0) {
|
|
2743
2974
|
return {
|
|
2744
2975
|
bucket: pathParts[0],
|
|
@@ -2748,7 +2979,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2748
2979
|
prefix: pathParts.slice(1).join("/")
|
|
2749
2980
|
};
|
|
2750
2981
|
}
|
|
2751
|
-
const ovhMatch = host.match(
|
|
2982
|
+
const ovhMatch = host.match(OVH_RE);
|
|
2752
2983
|
if (ovhMatch && pathParts.length > 0) {
|
|
2753
2984
|
return {
|
|
2754
2985
|
bucket: pathParts[0],
|
|
@@ -2758,8 +2989,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2758
2989
|
prefix: pathParts.slice(1).join("/")
|
|
2759
2990
|
};
|
|
2760
2991
|
}
|
|
2761
|
-
|
|
2762
|
-
if (isMinioLike && pathParts.length > 0) {
|
|
2992
|
+
if (isMinioLikeHost(host) && pathParts.length > 0) {
|
|
2763
2993
|
return {
|
|
2764
2994
|
bucket: pathParts[0],
|
|
2765
2995
|
region: defaults.region || "us-east-1",
|
|
@@ -2768,7 +2998,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2768
2998
|
prefix: pathParts.slice(1).join("/")
|
|
2769
2999
|
};
|
|
2770
3000
|
}
|
|
2771
|
-
const azureBlob = host.match(
|
|
3001
|
+
const azureBlob = host.match(AZURE_BLOB_RE);
|
|
2772
3002
|
if (azureBlob && pathParts.length > 0) {
|
|
2773
3003
|
return {
|
|
2774
3004
|
bucket: pathParts[0],
|
|
@@ -2778,7 +3008,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2778
3008
|
prefix: pathParts.slice(1).join("/")
|
|
2779
3009
|
};
|
|
2780
3010
|
}
|
|
2781
|
-
const storjGateway = host.match(
|
|
3011
|
+
const storjGateway = host.match(STORJ_GATEWAY_RE);
|
|
2782
3012
|
if (storjGateway && pathParts.length > 0) {
|
|
2783
3013
|
return {
|
|
2784
3014
|
bucket: pathParts[0],
|
|
@@ -2788,7 +3018,7 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2788
3018
|
prefix: pathParts.slice(1).join("/")
|
|
2789
3019
|
};
|
|
2790
3020
|
}
|
|
2791
|
-
const storjLink = host.match(
|
|
3021
|
+
const storjLink = host.match(STORJ_LINK_RE);
|
|
2792
3022
|
if (storjLink && pathParts.length >= 3 && (pathParts[0] === "raw" || pathParts[0] === "s")) {
|
|
2793
3023
|
return {
|
|
2794
3024
|
bucket: pathParts[2],
|
|
@@ -2798,6 +3028,12 @@ function parseStorageUrl(input, defaults = {}) {
|
|
|
2798
3028
|
prefix: pathParts.slice(3).join("/")
|
|
2799
3029
|
};
|
|
2800
3030
|
}
|
|
3031
|
+
if (STAC_API_PATH_RE.test(url.pathname)) {
|
|
3032
|
+
return {
|
|
3033
|
+
...defaultResult(defaults),
|
|
3034
|
+
endpoint: `${url.protocol}//${url.host}`
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
2801
3037
|
if (pathParts.length > 0) {
|
|
2802
3038
|
const endpoint = `${url.protocol}//${url.host}`;
|
|
2803
3039
|
return {
|
|
@@ -3000,7 +3236,10 @@ var GEO_TYPE_KEYWORDS = [
|
|
|
3000
3236
|
"geometrycollection",
|
|
3001
3237
|
"sdo_geometry"
|
|
3002
3238
|
];
|
|
3003
|
-
var GEO_NAME_HINTS = ["geom", "geometry", "
|
|
3239
|
+
var GEO_NAME_HINTS = ["geom", "geometry", "wkb", "wkt", "shape", "spatial", "geo"];
|
|
3240
|
+
function tokenizeColumnName(name) {
|
|
3241
|
+
return name.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([a-z])([0-9])/g, "$1_$2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
3242
|
+
}
|
|
3004
3243
|
var GEOJSON_TYPES = [
|
|
3005
3244
|
"Point",
|
|
3006
3245
|
"LineString",
|
|
@@ -3030,14 +3269,14 @@ function findGeoColumn(schema) {
|
|
|
3030
3269
|
if (GEO_NAMES.includes(f.name.toLowerCase())) return f.name;
|
|
3031
3270
|
}
|
|
3032
3271
|
for (const f of schema) {
|
|
3033
|
-
const
|
|
3272
|
+
const tokens = tokenizeColumnName(f.name);
|
|
3034
3273
|
const t = f.type.toLowerCase();
|
|
3035
3274
|
const isBinary = t.includes("blob") || t.includes("binary") || t.includes("bytea");
|
|
3036
|
-
if (isBinary &&
|
|
3275
|
+
if (isBinary && tokens.some((tok) => GEO_NAME_HINTS.includes(tok))) return f.name;
|
|
3037
3276
|
}
|
|
3038
3277
|
for (const f of schema) {
|
|
3039
|
-
const
|
|
3040
|
-
if (
|
|
3278
|
+
const tokens = tokenizeColumnName(f.name);
|
|
3279
|
+
if (tokens.some((tok) => GEO_NAME_HINTS.includes(tok))) return f.name;
|
|
3041
3280
|
}
|
|
3042
3281
|
return null;
|
|
3043
3282
|
}
|
|
@@ -3104,6 +3343,7 @@ exports.PROVIDER_IDS = PROVIDER_IDS;
|
|
|
3104
3343
|
exports.QueryCancelledError = QueryCancelledError;
|
|
3105
3344
|
exports.SF_LABELS = SF_LABELS;
|
|
3106
3345
|
exports.SQL_PREVIEW_LENGTH = SQL_PREVIEW_LENGTH;
|
|
3346
|
+
exports.STAC_GEOPARQUET_REQUIRED_COLUMNS = STAC_GEOPARQUET_REQUIRED_COLUMNS;
|
|
3107
3347
|
exports.STORAGE_KEYS = STORAGE_KEYS;
|
|
3108
3348
|
exports.UrlAdapter = UrlAdapter;
|
|
3109
3349
|
exports.VIEWER_DIR_EXTENSIONS = VIEWER_DIR_EXTENSIONS;
|
|
@@ -3117,15 +3357,19 @@ exports.clampBounds = clampBounds;
|
|
|
3117
3357
|
exports.classifyType = classifyType;
|
|
3118
3358
|
exports.describeParseResult = describeParseResult;
|
|
3119
3359
|
exports.escapeCsvField = escapeCsvField;
|
|
3360
|
+
exports.exportToCsv = exportToCsv;
|
|
3361
|
+
exports.exportToJson = exportToJson;
|
|
3120
3362
|
exports.extractBounds = extractBounds;
|
|
3121
3363
|
exports.extractEpsgFromGeoMeta = extractEpsgFromGeoMeta;
|
|
3122
3364
|
exports.extractGeometryTypes = extractGeometryTypes;
|
|
3123
3365
|
exports.findGeoColumn = findGeoColumn;
|
|
3124
3366
|
exports.findGeoColumnFromRows = findGeoColumnFromRows;
|
|
3367
|
+
exports.flattenStacBbox = flattenStacBbox;
|
|
3125
3368
|
exports.formatDate = formatDate;
|
|
3126
3369
|
exports.formatFileSize = formatFileSize;
|
|
3127
3370
|
exports.formatValue = formatValue;
|
|
3128
3371
|
exports.generateHexDump = generateHexDump;
|
|
3372
|
+
exports.getAccessMode = getAccessMode;
|
|
3129
3373
|
exports.getDuckDbReadFn = getDuckDbReadFn;
|
|
3130
3374
|
exports.getFileExtension = getFileExtension;
|
|
3131
3375
|
exports.getFileTypeInfo = getFileTypeInfo;
|
|
@@ -3137,7 +3381,9 @@ exports.handleLoadError = handleLoadError;
|
|
|
3137
3381
|
exports.interpolateTemplates = interpolateTemplates;
|
|
3138
3382
|
exports.isCloudNativeFormat = isCloudNativeFormat;
|
|
3139
3383
|
exports.isGcsProvider = isGcsProvider;
|
|
3384
|
+
exports.isPubliclyStreamable = isPubliclyStreamable;
|
|
3140
3385
|
exports.isQueryable = isQueryable;
|
|
3386
|
+
exports.isStacGeoparquetSchema = isStacGeoparquetSchema;
|
|
3141
3387
|
exports.jsonReplacerBigInt = jsonReplacerBigInt;
|
|
3142
3388
|
exports.loadFromStorage = loadFromStorage;
|
|
3143
3389
|
exports.looksLikeUrl = looksLikeUrl;
|
|
@@ -3147,13 +3393,17 @@ exports.parseMarkdownDocument = parseMarkdownDocument;
|
|
|
3147
3393
|
exports.parseStorageUrl = parseStorageUrl;
|
|
3148
3394
|
exports.parseWKB = parseWKB;
|
|
3149
3395
|
exports.persistToStorage = persistToStorage;
|
|
3396
|
+
exports.pickStacPrimaryAsset = pickStacPrimaryAsset;
|
|
3150
3397
|
exports.readParquetMetadata = readParquetMetadata;
|
|
3151
3398
|
exports.resolveCloudUrl = resolveCloudUrl;
|
|
3399
|
+
exports.resolveProviderEndpoint = resolveProviderEndpoint;
|
|
3400
|
+
exports.resolveStacAssetHref = resolveStacAssetHref;
|
|
3152
3401
|
exports.safeClamp = safeClamp;
|
|
3153
3402
|
exports.safeDecodeURIComponent = safeDecodeURIComponent;
|
|
3154
3403
|
exports.serializeToCsv = serializeToCsv;
|
|
3155
3404
|
exports.serializeToJson = serializeToJson;
|
|
3156
3405
|
exports.sortFileEntries = sortFileEntries;
|
|
3406
|
+
exports.stacRowToItem = stacRowToItem;
|
|
3157
3407
|
exports.toBinary = toBinary;
|
|
3158
3408
|
exports.toggleSortField = toggleSortField;
|
|
3159
3409
|
exports.typeBadgeClass = typeBadgeClass;
|