@walkthru-earth/objex 1.2.0 → 1.2.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.
Files changed (36) hide show
  1. package/dist/components/browser/FileTreeSidebar.svelte +1 -1
  2. package/dist/components/layout/Sidebar.svelte +27 -0
  3. package/dist/components/viewers/ArchiveViewer.svelte +4 -4
  4. package/dist/components/viewers/CodeViewer.svelte +21 -5
  5. package/dist/components/viewers/CogViewer.svelte +21 -3
  6. package/dist/components/viewers/CopcViewer.svelte +20 -2
  7. package/dist/components/viewers/FlatGeobufViewer.svelte +15 -9
  8. package/dist/components/viewers/PmtilesViewer.svelte +2 -2
  9. package/dist/components/viewers/StacMapViewer.svelte +25 -9
  10. package/dist/components/viewers/TableViewer.svelte +50 -21
  11. package/dist/components/viewers/ZarrMapViewer.svelte +4 -4
  12. package/dist/components/viewers/ZarrViewer.svelte +2 -2
  13. package/dist/components/viewers/pmtiles/PmtilesMapView.svelte +0 -1
  14. package/dist/i18n/ar.js +1 -0
  15. package/dist/i18n/en.js +1 -0
  16. package/dist/query/index.d.ts +1 -1
  17. package/dist/query/index.js +1 -1
  18. package/dist/query/source.d.ts +12 -0
  19. package/dist/query/source.js +25 -8
  20. package/dist/query/wasm.js +130 -23
  21. package/dist/storage/adapter.d.ts +9 -0
  22. package/dist/storage/adapter.js +13 -1
  23. package/dist/storage/browser-azure.d.ts +1 -1
  24. package/dist/storage/browser-azure.js +4 -0
  25. package/dist/storage/browser-cloud.d.ts +1 -1
  26. package/dist/storage/browser-cloud.js +7 -0
  27. package/dist/storage/presign.d.ts +13 -0
  28. package/dist/storage/presign.js +55 -0
  29. package/dist/storage/providers.d.ts +6 -0
  30. package/dist/storage/providers.js +13 -2
  31. package/dist/stores/browser.svelte.d.ts +2 -0
  32. package/dist/stores/browser.svelte.js +17 -1
  33. package/dist/utils/url.d.ts +13 -0
  34. package/dist/utils/url.js +36 -0
  35. package/dist/utils/wkb.js +22 -8
  36. package/package.json +1 -1
@@ -4,6 +4,12 @@ import type { Tab } from '../types.js';
4
4
  * Works for any viewer that needs an HTTP-accessible URL (COG, PMTiles, Zarr, etc.)
5
5
  */
6
6
  export declare function buildHttpsUrl(tab: Tab): string;
7
+ /**
8
+ * Async counterpart of `buildHttpsUrl`. For `signed-s3` connections, returns a
9
+ * presigned HTTPS URL (SigV4 query-string auth). For public or SAS connections
10
+ * it returns the same URL as the sync version.
11
+ */
12
+ export declare function buildHttpsUrlAsync(tab: Tab, expiresIn?: number): Promise<string>;
7
13
  /**
8
14
  * Build a provider-native protocol URL (s3://bucket/path, sj://bucket/path, etc.).
9
15
  */
@@ -21,6 +27,13 @@ export declare function buildStorageUrl(tab: Tab): string;
21
27
  * (e.g. Arabic filenames `%D9%85` → `%25D9%2585`).
22
28
  */
23
29
  export declare function buildDuckDbUrl(tab: Tab): string;
30
+ /**
31
+ * Async counterpart of `buildDuckDbUrl`. Returns a presigned HTTPS URL for
32
+ * `signed-s3` connections so DuckDB httpfs can fetch with `Range` only, no
33
+ * `Authorization` preflight (which breaks on GCS's S3-compat endpoint when
34
+ * the bucket CORS `responseHeader` list desyncs from the browser's request).
35
+ */
36
+ export declare function buildDuckDbUrlAsync(tab: Tab, expiresIn?: number): Promise<string>;
24
37
  /**
25
38
  * True when any HTTP client (fetch/img/video/deck.gl/COG/Zarr/PMTiles) can
26
39
  * load the tab's file directly via its HTTPS URL. False when SigV4 signing
package/dist/utils/url.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { presignHttpsUrl } from '../storage/presign.js';
1
2
  import { buildProviderBaseUrl, isPubliclyStreamable } from '../storage/providers.js';
2
3
  import { connections } from '../stores/connections.svelte.js';
3
4
  import { credentialStore } from '../stores/credentials.svelte.js';
@@ -20,6 +21,15 @@ export function buildHttpsUrl(tab) {
20
21
  }
21
22
  return `${buildProviderBaseUrl(conn.provider, conn.endpoint, conn.bucket, conn.region)}/${cleanPath}`;
22
23
  }
24
+ /**
25
+ * Async counterpart of `buildHttpsUrl`. For `signed-s3` connections, returns a
26
+ * presigned HTTPS URL (SigV4 query-string auth). For public or SAS connections
27
+ * it returns the same URL as the sync version.
28
+ */
29
+ export async function buildHttpsUrlAsync(tab, expiresIn) {
30
+ const presigned = await tryPresignTab(tab, expiresIn);
31
+ return presigned ?? buildHttpsUrl(tab);
32
+ }
23
33
  /**
24
34
  * Build a provider-native protocol URL (s3://bucket/path, sj://bucket/path, etc.).
25
35
  */
@@ -53,6 +63,32 @@ export function buildDuckDbUrl(tab) {
53
63
  const rawPath = safeDecodeURIComponent(tab.path.replace(/^\//, ''));
54
64
  return `s3://${conn.bucket}/${rawPath}`;
55
65
  }
66
+ /**
67
+ * Async counterpart of `buildDuckDbUrl`. Returns a presigned HTTPS URL for
68
+ * `signed-s3` connections so DuckDB httpfs can fetch with `Range` only, no
69
+ * `Authorization` preflight (which breaks on GCS's S3-compat endpoint when
70
+ * the bucket CORS `responseHeader` list desyncs from the browser's request).
71
+ */
72
+ export async function buildDuckDbUrlAsync(tab, expiresIn) {
73
+ const presigned = await tryPresignTab(tab, expiresIn);
74
+ return presigned ?? buildDuckDbUrl(tab);
75
+ }
76
+ /** Presign the tab's HTTPS URL for `signed-s3` connections; null otherwise. */
77
+ async function tryPresignTab(tab, expiresIn) {
78
+ const conn = tab.connectionId ? connections.getById(tab.connectionId) : null;
79
+ if (!conn || isPubliclyStreamable(conn))
80
+ return null;
81
+ try {
82
+ return await presignHttpsUrl(conn, tab.path, expiresIn);
83
+ }
84
+ catch (err) {
85
+ // Silent fallback would route the caller back to `s3://...` + SigV4
86
+ // header signing — exactly the CORS preflight path presigning was added
87
+ // to avoid. Surface the failure so it is debuggable.
88
+ console.warn('[presign] falling back to signed-s3 path:', err);
89
+ return null;
90
+ }
91
+ }
56
92
  /**
57
93
  * True when any HTTP client (fetch/img/video/deck.gl/COG/Zarr/PMTiles) can
58
94
  * load the tab's file directly via its HTTPS URL. False when SigV4 signing
package/dist/utils/wkb.js CHANGED
@@ -190,8 +190,22 @@ const GEO_TYPE_KEYWORDS = [
190
190
  'geometrycollection',
191
191
  'sdo_geometry'
192
192
  ];
193
- /** Substrings in column names that hint at geometry content. */
194
- const GEO_NAME_HINTS = ['geom', 'geometry', 'geo_', '_geo', 'wkb', 'wkt', 'shape', 'spatial'];
193
+ /**
194
+ * Tokens in column names that hint at geometry content. Matched against
195
+ * snake_case / kebab-case / camelCase tokens only — never as loose substrings
196
+ * (e.g. `_geographic_` must not match `geo` via the `_geo` substring, because
197
+ * count columns like `n_geographic_entities` are INT, not geometry).
198
+ */
199
+ const GEO_NAME_HINTS = ['geom', 'geometry', 'wkb', 'wkt', 'shape', 'spatial', 'geo'];
200
+ /** Split a column name into lowercase tokens for hint matching. */
201
+ function tokenizeColumnName(name) {
202
+ return name
203
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
204
+ .replace(/([a-z])([0-9])/g, '$1_$2')
205
+ .toLowerCase()
206
+ .split(/[^a-z0-9]+/)
207
+ .filter(Boolean);
208
+ }
195
209
  /** Valid GeoJSON geometry type names. */
196
210
  const GEOJSON_TYPES = [
197
211
  'Point',
@@ -242,18 +256,18 @@ export function findGeoColumn(schema) {
242
256
  if (GEO_NAMES.includes(f.name.toLowerCase()))
243
257
  return f.name;
244
258
  }
245
- // Priority 4: name contains geo hint with binary type
259
+ // Priority 4: name token matches geo hint with binary type
246
260
  for (const f of schema) {
247
- const n = f.name.toLowerCase();
261
+ const tokens = tokenizeColumnName(f.name);
248
262
  const t = f.type.toLowerCase();
249
263
  const isBinary = t.includes('blob') || t.includes('binary') || t.includes('bytea');
250
- if (isBinary && GEO_NAME_HINTS.some((hint) => n.includes(hint)))
264
+ if (isBinary && tokens.some((tok) => GEO_NAME_HINTS.includes(tok)))
251
265
  return f.name;
252
266
  }
253
- // Priority 5: name contains geo hint, any type
267
+ // Priority 5: name token matches geo hint, any type
254
268
  for (const f of schema) {
255
- const n = f.name.toLowerCase();
256
- if (GEO_NAME_HINTS.some((hint) => n.includes(hint)))
269
+ const tokens = tokenizeColumnName(f.name);
270
+ if (tokens.some((tok) => GEO_NAME_HINTS.includes(tok)))
257
271
  return f.name;
258
272
  }
259
273
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walkthru-earth/objex",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Svelte 5 components and utilities for exploring geospatial object storage — S3, GCS, Azure, R2",
5
5
  "author": "Youssef Harby <yharby@walkthru.earth>",
6
6
  "license": "CC-BY-4.0",