@walkthru-earth/objex 1.3.0 → 1.4.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.
Files changed (182) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +20 -12
  3. package/dist/components/browser/FileTreeSidebar.svelte +32 -17
  4. package/dist/components/layout/AboutSheet.svelte +5 -2
  5. package/dist/components/layout/ConnectionDialog.svelte +1 -1
  6. package/dist/components/layout/SettingsSheet.svelte +237 -0
  7. package/dist/components/layout/SettingsSheet.svelte.d.ts +6 -0
  8. package/dist/components/layout/Sidebar.svelte +73 -6
  9. package/dist/components/layout/Sidebar.svelte.d.ts +4 -1
  10. package/dist/components/layout/StatusBar.svelte +1 -1
  11. package/dist/components/layout/TabBar.svelte +2 -2
  12. package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
  13. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
  14. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
  15. package/dist/components/ui/input/input.svelte.d.ts +1 -1
  16. package/dist/components/ui/resizable/index.d.ts +1 -1
  17. package/dist/components/ui/resizable/index.js +2 -2
  18. package/dist/components/ui/slider/index.d.ts +3 -0
  19. package/dist/components/ui/slider/index.js +5 -0
  20. package/dist/components/ui/slider/range-slider.svelte +94 -0
  21. package/dist/components/ui/slider/range-slider.svelte.d.ts +21 -0
  22. package/dist/components/ui/slider/slider.svelte +83 -0
  23. package/dist/components/ui/slider/slider.svelte.d.ts +7 -0
  24. package/dist/components/viewers/ArchiveViewer.svelte +2 -2
  25. package/dist/components/viewers/CodeViewer.svelte +31 -22
  26. package/dist/components/viewers/CogControls.svelte +338 -184
  27. package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
  28. package/dist/components/viewers/CogViewer.svelte +320 -119
  29. package/dist/components/viewers/CopcViewer.svelte +1 -1
  30. package/dist/components/viewers/FlatGeobufViewer.svelte +1 -1
  31. package/dist/components/viewers/GeoParquetMapViewer.svelte +6 -6
  32. package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
  33. package/dist/components/viewers/ImageViewer.svelte +2 -2
  34. package/dist/components/viewers/MarkdownViewer.svelte +12 -9
  35. package/dist/components/viewers/MediaViewer.svelte +2 -2
  36. package/dist/components/viewers/ModelViewer.svelte +1 -1
  37. package/dist/components/viewers/MultiCogViewer.svelte +467 -102
  38. package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
  39. package/dist/components/viewers/NotebookViewer.svelte +6 -3
  40. package/dist/components/viewers/PdfViewer.svelte +2 -2
  41. package/dist/components/viewers/PmtilesViewer.svelte +3 -6
  42. package/dist/components/viewers/RawViewer.svelte +6 -3
  43. package/dist/components/viewers/StacMapViewer.svelte +10 -2
  44. package/dist/components/viewers/StacMosaicViewer.svelte +1800 -362
  45. package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
  46. package/dist/components/viewers/StacTabViewer.svelte +24 -13
  47. package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
  48. package/dist/components/viewers/TableGrid.svelte +4 -4
  49. package/dist/components/viewers/TableStatusBar.svelte +1 -1
  50. package/dist/components/viewers/TableToolbar.svelte +1 -1
  51. package/dist/components/viewers/TableViewer.svelte +25 -17
  52. package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
  53. package/dist/components/viewers/ViewerRouter.svelte +16 -8
  54. package/dist/components/viewers/ZarrMapViewer.svelte +11 -9
  55. package/dist/components/viewers/ZarrViewer.svelte +4 -4
  56. package/dist/components/viewers/cog/ChannelPicker.svelte +83 -0
  57. package/dist/components/viewers/cog/ChannelPicker.svelte.d.ts +13 -0
  58. package/dist/components/viewers/cog/PixelInspectorPanel.svelte +87 -0
  59. package/dist/components/viewers/cog/PixelInspectorPanel.svelte.d.ts +17 -0
  60. package/dist/components/viewers/cog/buildRgbLayer.d.ts +78 -0
  61. package/dist/components/viewers/cog/buildRgbLayer.js +176 -0
  62. package/dist/components/viewers/map/AttributeTable.svelte +1 -1
  63. package/dist/components/viewers/map/MapContainer.svelte +37 -11
  64. package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +1 -1
  65. package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +1 -1
  66. package/dist/components/viewers/stac/StacDatetimeBar.svelte +175 -0
  67. package/dist/components/viewers/stac/StacDatetimeBar.svelte.d.ts +10 -0
  68. package/dist/components/viewers/stac/StacFilterPanel.svelte +243 -0
  69. package/dist/components/viewers/stac/StacFilterPanel.svelte.d.ts +14 -0
  70. package/dist/components/viewers/stac/StacItemInspector.svelte +223 -0
  71. package/dist/components/viewers/stac/StacItemInspector.svelte.d.ts +10 -0
  72. package/dist/components/viewers/stac/StacItemStrip.svelte +228 -0
  73. package/dist/components/viewers/stac/StacItemStrip.svelte.d.ts +12 -0
  74. package/dist/file-icons/index.d.ts +1 -1
  75. package/dist/file-icons/index.js +1 -1
  76. package/dist/i18n/ar.js +110 -2
  77. package/dist/i18n/en.js +110 -2
  78. package/dist/index.d.ts +2 -28
  79. package/dist/index.js +7 -23
  80. package/dist/query/engine.d.ts +10 -0
  81. package/dist/query/source.js +1 -1
  82. package/dist/query/stac-source-factory.d.ts +65 -0
  83. package/dist/query/stac-source-factory.js +77 -0
  84. package/dist/query/stac-source-parquet.d.ts +135 -0
  85. package/dist/query/stac-source-parquet.js +465 -0
  86. package/dist/query/wasm.d.ts +8 -0
  87. package/dist/query/wasm.js +304 -2
  88. package/dist/storage/presign.js +1 -1
  89. package/dist/storage/providers.js +5 -5
  90. package/dist/stores/config.svelte.d.ts +15 -0
  91. package/dist/stores/config.svelte.js +46 -0
  92. package/dist/stores/connections.svelte.d.ts +2 -2
  93. package/dist/stores/connections.svelte.js +1 -2
  94. package/dist/stores/files.svelte.d.ts +1 -1
  95. package/dist/stores/files.svelte.js +1 -1
  96. package/dist/stores/query-history.svelte.js +1 -1
  97. package/dist/stores/settings.svelte.d.ts +16 -1
  98. package/dist/stores/settings.svelte.js +104 -48
  99. package/dist/stores/tabs.svelte.d.ts +3 -0
  100. package/dist/stores/tabs.svelte.js +17 -0
  101. package/dist/utils/cog-histogram.d.ts +121 -0
  102. package/dist/utils/cog-histogram.js +424 -0
  103. package/dist/utils/cog.d.ts +200 -60
  104. package/dist/utils/cog.js +377 -114
  105. package/dist/utils/colormap-sprite.d.ts +0 -9
  106. package/dist/utils/colormap-sprite.js +0 -21
  107. package/dist/utils/deck.d.ts +16 -12
  108. package/dist/utils/deck.js +10 -4
  109. package/dist/utils/pmtiles-tile.js +2 -2
  110. package/dist/utils/{url.d.ts → signed-url.d.ts} +15 -1
  111. package/dist/utils/{url.js → signed-url.js} +32 -10
  112. package/dist/utils/url-state.d.ts +36 -0
  113. package/dist/utils/url-state.js +72 -2
  114. package/dist/utils/zarr-tab.d.ts +1 -2
  115. package/dist/utils/zarr-tab.js +1 -2
  116. package/dist/utils/zarr.d.ts +0 -17
  117. package/dist/utils/zarr.js +1 -45
  118. package/package.json +55 -84
  119. package/dist/components/browser/Breadcrumb.svelte +0 -50
  120. package/dist/components/browser/Breadcrumb.svelte.d.ts +0 -7
  121. package/dist/components/browser/CreateFolderDialog.svelte +0 -98
  122. package/dist/components/browser/CreateFolderDialog.svelte.d.ts +0 -6
  123. package/dist/components/browser/DeleteConfirmDialog.svelte +0 -90
  124. package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +0 -8
  125. package/dist/components/browser/DropZone.svelte +0 -83
  126. package/dist/components/browser/DropZone.svelte.d.ts +0 -7
  127. package/dist/components/browser/FileBrowser.svelte +0 -252
  128. package/dist/components/browser/FileBrowser.svelte.d.ts +0 -3
  129. package/dist/components/browser/FileRow.svelte +0 -117
  130. package/dist/components/browser/FileRow.svelte.d.ts +0 -9
  131. package/dist/components/browser/RenameDialog.svelte +0 -101
  132. package/dist/components/browser/RenameDialog.svelte.d.ts +0 -8
  133. package/dist/components/browser/SearchBar.svelte +0 -40
  134. package/dist/components/browser/SearchBar.svelte.d.ts +0 -6
  135. package/dist/components/browser/UploadButton.svelte +0 -65
  136. package/dist/components/browser/UploadButton.svelte.d.ts +0 -3
  137. package/dist/query/stac-geoparquet.d.ts +0 -31
  138. package/dist/query/stac-geoparquet.js +0 -136
  139. package/dist/utils/clipboard.d.ts +0 -13
  140. package/dist/utils/clipboard.js +0 -38
  141. package/dist/utils/cloud-url.d.ts +0 -27
  142. package/dist/utils/cloud-url.js +0 -61
  143. package/dist/utils/column-types.d.ts +0 -5
  144. package/dist/utils/column-types.js +0 -137
  145. package/dist/utils/connection-identity.d.ts +0 -51
  146. package/dist/utils/connection-identity.js +0 -97
  147. package/dist/utils/error.d.ts +0 -8
  148. package/dist/utils/error.js +0 -12
  149. package/dist/utils/evidence-context.d.ts +0 -22
  150. package/dist/utils/evidence-context.js +0 -56
  151. package/dist/utils/export.d.ts +0 -22
  152. package/dist/utils/export.js +0 -76
  153. package/dist/utils/file-sort.d.ts +0 -20
  154. package/dist/utils/file-sort.js +0 -41
  155. package/dist/utils/format.d.ts +0 -24
  156. package/dist/utils/format.js +0 -78
  157. package/dist/utils/geoarrow.d.ts +0 -32
  158. package/dist/utils/geoarrow.js +0 -672
  159. package/dist/utils/geometry-type.d.ts +0 -52
  160. package/dist/utils/geometry-type.js +0 -76
  161. package/dist/utils/hex.d.ts +0 -10
  162. package/dist/utils/hex.js +0 -27
  163. package/dist/utils/host-detection.d.ts +0 -23
  164. package/dist/utils/host-detection.js +0 -95
  165. package/dist/utils/local-storage.d.ts +0 -16
  166. package/dist/utils/local-storage.js +0 -37
  167. package/dist/utils/markdown-sql.d.ts +0 -30
  168. package/dist/utils/markdown-sql.js +0 -72
  169. package/dist/utils/notebook.d.ts +0 -59
  170. package/dist/utils/notebook.js +0 -211
  171. package/dist/utils/parquet-metadata.d.ts +0 -64
  172. package/dist/utils/parquet-metadata.js +0 -262
  173. package/dist/utils/stac-geoparquet.d.ts +0 -90
  174. package/dist/utils/stac-geoparquet.js +0 -223
  175. package/dist/utils/stac-hydrate.d.ts +0 -38
  176. package/dist/utils/stac-hydrate.js +0 -243
  177. package/dist/utils/stac.d.ts +0 -136
  178. package/dist/utils/stac.js +0 -176
  179. package/dist/utils/storage-url.d.ts +0 -90
  180. package/dist/utils/storage-url.js +0 -568
  181. package/dist/utils/wkb.d.ts +0 -43
  182. package/dist/utils/wkb.js +0 -359
@@ -1,568 +0,0 @@
1
- /**
2
- * Universal cloud storage URL / bucket parser.
3
- *
4
- * Accepts the many URI/URL formats that users commonly paste and extracts
5
- * the correct bucket, region, endpoint, and provider.
6
- *
7
- * Supported URI schemes:
8
- * s3:// s3a:// s3n:// aws:// — Amazon S3 / S3-compatible
9
- * r2:// — Cloudflare R2
10
- * gs:// gcs:// — Google Cloud Storage
11
- * azure:// az:// — Azure Blob Storage
12
- * abfs:// abfss:// — Azure Data Lake (ADLS Gen2)
13
- * wasbs:// — Azure Blob (Hadoop WASB driver)
14
- * swift:// — OpenStack Swift
15
- * file:// filesystem:// — Local filesystem
16
- *
17
- * Supported HTTPS URL patterns:
18
- * https://<bucket>.s3.<region>.amazonaws.com[/prefix] — AWS virtual-hosted
19
- * https://s3.<region>.amazonaws.com/<bucket>[/prefix] — AWS path-style
20
- * https://s3.amazonaws.com/<bucket> — AWS global
21
- * https://<account>.r2.cloudflarestorage.com/<bucket> — Cloudflare R2
22
- * https://storage.googleapis.com/<bucket> — Google Cloud Storage
23
- * https://<bucket>.storage.googleapis.com[/prefix] — GCS virtual-hosted
24
- * https://<bucket>.<region>.digitaloceanspaces.com — DigitalOcean Spaces
25
- * https://<region>.digitaloceanspaces.com/<bucket> — DO Spaces path-style
26
- * https://s3.<region>.wasabisys.com/<bucket> — Wasabi
27
- * https://f<id>.backblazeb2.com/file/<bucket> — Backblaze B2
28
- * https://<bucket>.s3.<region>.backblazeb2.com — B2 S3-compatible
29
- * https://<bucket>.oss-<region>.aliyuncs.com — Alibaba Cloud OSS
30
- * https://<bucket>.cos.<region>.myqcloud.com — Tencent COS
31
- * https://storage.yandexcloud.net/<bucket> — Yandex Cloud
32
- * https://gateway.storjshare.io/<bucket> — Storj S3 gateway
33
- * https://link.storjshare.io/raw/<access>/<bucket> — Storj linksharing
34
- * https://<custom-endpoint>/<bucket> — Generic S3-compatible
35
- *
36
- * Also handles plain bucket names (no protocol).
37
- */
38
- import { PROVIDERS } from '../storage/providers.js';
39
- /**
40
- * Build SCHEME_MAP from the provider registry's `schemes` arrays.
41
- * Each scheme like "s3" generates an entry `"s3://": { provider: "s3", strip: 5 }`.
42
- */
43
- function buildSchemeMap() {
44
- const map = {};
45
- for (const [id, def] of Object.entries(PROVIDERS)) {
46
- for (const scheme of def.schemes) {
47
- const key = `${scheme}://`;
48
- map[key] = { provider: id, strip: key.length };
49
- }
50
- }
51
- // Non-registry schemes (no corresponding provider)
52
- map['swift://'] = { provider: 'unknown', strip: 8 };
53
- return map;
54
- }
55
- /** All recognized URI scheme prefixes (lowercase), derived from provider registry */
56
- const SCHEME_MAP = buildSchemeMap();
57
- /**
58
- * Shared host matchers. Used by both `parseStorageUrl` and `isKnownBucketHost`
59
- * so provider recognition has a single source of truth.
60
- */
61
- const AWS_VHOST_RE = /^(.+)\.s3[.-]([a-z0-9-]+)\.amazonaws\.com$/;
62
- const AWS_PATH_RE = /^s3[.-]([a-z0-9-]+)\.amazonaws\.com$/;
63
- const AWS_GLOBAL_HOST = 's3.amazonaws.com';
64
- const R2_RE = /^([a-z0-9]+)\.r2\.cloudflarestorage\.com$/;
65
- const GCS_GLOBAL_HOST = 'storage.googleapis.com';
66
- const GCS_VHOST_RE = /^(.+)\.storage\.googleapis\.com$/;
67
- const DO_VHOST_RE = /^(.+)\.([a-z0-9-]+)\.digitaloceanspaces\.com$/;
68
- const DO_PATH_RE = /^([a-z0-9-]+)\.digitaloceanspaces\.com$/;
69
- const WASABI_RE = /^s3\.([a-z0-9-]+)\.wasabisys\.com$/;
70
- const B2_S3_RE = /^(.+)\.s3\.([a-z0-9-]+)\.backblazeb2\.com$/;
71
- const B2_NATIVE_RE = /^f[a-z0-9]+\.backblazeb2\.com$/;
72
- const OSS_RE = /^(.+)\.(oss-[a-z0-9-]+)\.aliyuncs\.com$/;
73
- const COS_RE = /^(.+)\.cos\.([a-z0-9-]+)\.myqcloud\.com$/;
74
- const YANDEX_HOST = 'storage.yandexcloud.net';
75
- const CONTABO_RE = /^([a-z0-9]+)\.contabostorage\.com$/;
76
- const HETZNER_RE = /^([a-z0-9]+)\.your-objectstorage\.com$/;
77
- const LINODE_VHOST_RE = /^(.+)\.([a-z0-9-]+)\.linodeobjects\.com$/;
78
- const LINODE_PATH_RE = /^([a-z0-9-]+)\.linodeobjects\.com$/;
79
- const OVH_RE = /^s3\.([a-z0-9-]+)\.io\.cloud\.ovh\.(?:net|us)$/;
80
- const AZURE_BLOB_RE = /^([a-z0-9]+)\.blob\.core\.windows\.net$/;
81
- const STORJ_GATEWAY_RE = /^gateway\.(?:([a-z0-9]+)\.)?storjshare\.io$/;
82
- const STORJ_LINK_RE = /^link\.(?:([a-z0-9]+)\.)?storjshare\.io$/;
83
- function isMinioLikeHost(host) {
84
- return (host.includes('minio') ||
85
- host === 'localhost' ||
86
- host === '127.0.0.1' ||
87
- host.startsWith('192.168.') ||
88
- host.startsWith('10.'));
89
- }
90
- /** STAC API path test, one source of truth. Tests pathname only. */
91
- export const STAC_API_PATH_RE = /\/(collections|items|catalogs|search)(\/|\?|$)/i;
92
- /**
93
- * Returns true when the host matches any of the provider host patterns
94
- * that `parseStorageUrl` recognizes on the HTTPS branch.
95
- */
96
- export function isKnownBucketHost(host) {
97
- if (!host)
98
- return false;
99
- if (AWS_VHOST_RE.test(host))
100
- return true;
101
- if (AWS_PATH_RE.test(host))
102
- return true;
103
- if (host === AWS_GLOBAL_HOST)
104
- return true;
105
- if (R2_RE.test(host))
106
- return true;
107
- if (host === GCS_GLOBAL_HOST)
108
- return true;
109
- if (GCS_VHOST_RE.test(host))
110
- return true;
111
- if (DO_VHOST_RE.test(host))
112
- return true;
113
- if (DO_PATH_RE.test(host))
114
- return true;
115
- if (WASABI_RE.test(host))
116
- return true;
117
- if (B2_S3_RE.test(host))
118
- return true;
119
- if (B2_NATIVE_RE.test(host))
120
- return true;
121
- if (OSS_RE.test(host))
122
- return true;
123
- if (COS_RE.test(host))
124
- return true;
125
- if (host === YANDEX_HOST)
126
- return true;
127
- if (CONTABO_RE.test(host))
128
- return true;
129
- if (HETZNER_RE.test(host))
130
- return true;
131
- if (LINODE_VHOST_RE.test(host))
132
- return true;
133
- if (LINODE_PATH_RE.test(host))
134
- return true;
135
- if (OVH_RE.test(host))
136
- return true;
137
- if (AZURE_BLOB_RE.test(host))
138
- return true;
139
- if (STORJ_GATEWAY_RE.test(host))
140
- return true;
141
- if (STORJ_LINK_RE.test(host))
142
- return true;
143
- if (isMinioLikeHost(host))
144
- return true;
145
- return false;
146
- }
147
- function defaultResult(defaults) {
148
- return {
149
- bucket: '',
150
- region: defaults.region || 'us-east-1',
151
- endpoint: defaults.endpoint || '',
152
- provider: defaults.provider || 's3',
153
- prefix: ''
154
- };
155
- }
156
- function splitBucketPrefix(rest) {
157
- const slashIdx = rest.indexOf('/');
158
- if (slashIdx >= 0) {
159
- return {
160
- bucket: rest.slice(0, slashIdx),
161
- prefix: rest.slice(slashIdx + 1).replace(/\/+$/, '')
162
- };
163
- }
164
- return { bucket: rest, prefix: '' };
165
- }
166
- /**
167
- * Parse a user-provided bucket/URL string into structured storage connection parts.
168
- */
169
- export function parseStorageUrl(input, defaults = {}) {
170
- const trimmed = input.trim();
171
- // ── Custom URI schemes (s3://, gs://, r2://, az://, etc.) ──────────
172
- const lower = trimmed.toLowerCase();
173
- for (const [scheme, { provider, strip }] of Object.entries(SCHEME_MAP)) {
174
- if (lower.startsWith(scheme)) {
175
- const rest = trimmed.slice(strip);
176
- const { bucket, prefix } = splitBucketPrefix(rest);
177
- return {
178
- bucket,
179
- region: defaults.region || 'us-east-1',
180
- endpoint: defaults.endpoint || '',
181
- provider,
182
- prefix
183
- };
184
- }
185
- }
186
- // ── HTTP(S) URL ─────────────────────────────────────────────────
187
- if (lower.startsWith('http://') || lower.startsWith('https://')) {
188
- try {
189
- const url = new URL(trimmed);
190
- const host = url.hostname;
191
- const pathParts = url.pathname.replace(/^\//, '').split('/').filter(Boolean);
192
- // --- AWS S3 ---
193
- // Virtual-hosted: <bucket>.s3.<region>.amazonaws.com
194
- const awsVhost = host.match(AWS_VHOST_RE);
195
- if (awsVhost) {
196
- return {
197
- bucket: awsVhost[1],
198
- region: awsVhost[2],
199
- endpoint: '',
200
- provider: 's3',
201
- prefix: pathParts.join('/')
202
- };
203
- }
204
- // Path-style: s3.<region>.amazonaws.com/<bucket>
205
- const awsPath = host.match(AWS_PATH_RE);
206
- if (awsPath && pathParts.length > 0) {
207
- return {
208
- bucket: pathParts[0],
209
- region: awsPath[1],
210
- endpoint: '',
211
- provider: 's3',
212
- prefix: pathParts.slice(1).join('/')
213
- };
214
- }
215
- // Global: s3.amazonaws.com/<bucket>
216
- if (host === AWS_GLOBAL_HOST && pathParts.length > 0) {
217
- return {
218
- bucket: pathParts[0],
219
- region: defaults.region || 'us-east-1',
220
- endpoint: '',
221
- provider: 's3',
222
- prefix: pathParts.slice(1).join('/')
223
- };
224
- }
225
- // --- Cloudflare R2 ---
226
- // <account>.r2.cloudflarestorage.com/<bucket>
227
- const r2Match = host.match(R2_RE);
228
- if (r2Match && pathParts.length > 0) {
229
- return {
230
- bucket: pathParts[0],
231
- region: 'auto',
232
- endpoint: `${url.protocol}//${url.host}`,
233
- provider: 'r2',
234
- prefix: pathParts.slice(1).join('/')
235
- };
236
- }
237
- // --- Google Cloud Storage ---
238
- // storage.googleapis.com/<bucket>
239
- if (host === GCS_GLOBAL_HOST && pathParts.length > 0) {
240
- return {
241
- bucket: pathParts[0],
242
- region: defaults.region || 'us',
243
- endpoint: '',
244
- provider: 'gcs',
245
- prefix: pathParts.slice(1).join('/')
246
- };
247
- }
248
- // <bucket>.storage.googleapis.com
249
- const gcsVhost = host.match(GCS_VHOST_RE);
250
- if (gcsVhost) {
251
- return {
252
- bucket: gcsVhost[1],
253
- region: defaults.region || 'us',
254
- endpoint: '',
255
- provider: 'gcs',
256
- prefix: pathParts.join('/')
257
- };
258
- }
259
- // --- DigitalOcean Spaces ---
260
- // <bucket>.<region>.digitaloceanspaces.com
261
- const doVhost = host.match(DO_VHOST_RE);
262
- if (doVhost) {
263
- return {
264
- bucket: doVhost[1],
265
- region: doVhost[2],
266
- endpoint: `${url.protocol}//${doVhost[2]}.digitaloceanspaces.com`,
267
- provider: 'digitalocean',
268
- prefix: pathParts.join('/')
269
- };
270
- }
271
- // <region>.digitaloceanspaces.com/<bucket>
272
- const doPath = host.match(DO_PATH_RE);
273
- if (doPath && pathParts.length > 0) {
274
- return {
275
- bucket: pathParts[0],
276
- region: doPath[1],
277
- endpoint: `${url.protocol}//${url.host}`,
278
- provider: 'digitalocean',
279
- prefix: pathParts.slice(1).join('/')
280
- };
281
- }
282
- // --- Wasabi ---
283
- // s3.<region>.wasabisys.com/<bucket>
284
- const wasabiMatch = host.match(WASABI_RE);
285
- if (wasabiMatch && pathParts.length > 0) {
286
- return {
287
- bucket: pathParts[0],
288
- region: wasabiMatch[1],
289
- endpoint: `${url.protocol}//${url.host}`,
290
- provider: 'wasabi',
291
- prefix: pathParts.slice(1).join('/')
292
- };
293
- }
294
- // --- Backblaze B2 ---
295
- // <bucket>.s3.<region>.backblazeb2.com (S3-compatible)
296
- const b2S3 = host.match(B2_S3_RE);
297
- if (b2S3) {
298
- return {
299
- bucket: b2S3[1],
300
- region: b2S3[2],
301
- endpoint: `${url.protocol}//s3.${b2S3[2]}.backblazeb2.com`,
302
- provider: 'b2',
303
- prefix: pathParts.join('/')
304
- };
305
- }
306
- // f<id>.backblazeb2.com/file/<bucket>
307
- const b2Native = host.match(B2_NATIVE_RE);
308
- if (b2Native && pathParts[0] === 'file' && pathParts.length > 1) {
309
- return {
310
- bucket: pathParts[1],
311
- region: defaults.region || 'us-west-000',
312
- endpoint: `${url.protocol}//${url.host}`,
313
- provider: 'b2',
314
- prefix: pathParts.slice(2).join('/')
315
- };
316
- }
317
- // --- Alibaba Cloud OSS ---
318
- // <bucket>.oss-<region>.aliyuncs.com
319
- const ossMatch = host.match(OSS_RE);
320
- if (ossMatch) {
321
- return {
322
- bucket: ossMatch[1],
323
- region: ossMatch[2],
324
- endpoint: `${url.protocol}//${ossMatch[2]}.aliyuncs.com`,
325
- provider: 's3',
326
- prefix: pathParts.join('/')
327
- };
328
- }
329
- // --- Tencent Cloud COS ---
330
- // <bucket>.cos.<region>.myqcloud.com
331
- const cosMatch = host.match(COS_RE);
332
- if (cosMatch) {
333
- return {
334
- bucket: cosMatch[1],
335
- region: cosMatch[2],
336
- endpoint: `${url.protocol}//cos.${cosMatch[2]}.myqcloud.com`,
337
- provider: 's3',
338
- prefix: pathParts.join('/')
339
- };
340
- }
341
- // --- Yandex Cloud ---
342
- // storage.yandexcloud.net/<bucket>
343
- if (host === YANDEX_HOST && pathParts.length > 0) {
344
- return {
345
- bucket: pathParts[0],
346
- region: defaults.region || 'ru-central1',
347
- endpoint: `${url.protocol}//${url.host}`,
348
- provider: 's3',
349
- prefix: pathParts.slice(1).join('/')
350
- };
351
- }
352
- // --- Contabo ---
353
- // <region>.contabostorage.com/<bucket>
354
- const contaboMatch = host.match(CONTABO_RE);
355
- if (contaboMatch && pathParts.length > 0) {
356
- return {
357
- bucket: pathParts[0],
358
- region: contaboMatch[1],
359
- endpoint: `${url.protocol}//${url.host}`,
360
- provider: 'contabo',
361
- prefix: pathParts.slice(1).join('/')
362
- };
363
- }
364
- // --- Hetzner ---
365
- // <region>.your-objectstorage.com/<bucket>
366
- const hetznerMatch = host.match(HETZNER_RE);
367
- if (hetznerMatch && pathParts.length > 0) {
368
- return {
369
- bucket: pathParts[0],
370
- region: hetznerMatch[1],
371
- endpoint: `${url.protocol}//${url.host}`,
372
- provider: 'hetzner',
373
- prefix: pathParts.slice(1).join('/')
374
- };
375
- }
376
- // --- Linode / Akamai ---
377
- // <bucket>.<region>.linodeobjects.com or <region>.linodeobjects.com/<bucket>
378
- const linodeVhost = host.match(LINODE_VHOST_RE);
379
- if (linodeVhost) {
380
- return {
381
- bucket: linodeVhost[1],
382
- region: linodeVhost[2],
383
- endpoint: `${url.protocol}//${linodeVhost[2]}.linodeobjects.com`,
384
- provider: 'linode',
385
- prefix: pathParts.join('/')
386
- };
387
- }
388
- const linodePath = host.match(LINODE_PATH_RE);
389
- if (linodePath && pathParts.length > 0) {
390
- return {
391
- bucket: pathParts[0],
392
- region: linodePath[1],
393
- endpoint: `${url.protocol}//${url.host}`,
394
- provider: 'linode',
395
- prefix: pathParts.slice(1).join('/')
396
- };
397
- }
398
- // --- OVHcloud ---
399
- // s3.<region>.io.cloud.ovh.net/<bucket>
400
- const ovhMatch = host.match(OVH_RE);
401
- if (ovhMatch && pathParts.length > 0) {
402
- return {
403
- bucket: pathParts[0],
404
- region: ovhMatch[1],
405
- endpoint: `${url.protocol}//${url.host}`,
406
- provider: 'ovhcloud',
407
- prefix: pathParts.slice(1).join('/')
408
- };
409
- }
410
- // --- MinIO ---
411
- // Common patterns: minio.<domain>, localhost with port
412
- if (isMinioLikeHost(host) && pathParts.length > 0) {
413
- return {
414
- bucket: pathParts[0],
415
- region: defaults.region || 'us-east-1',
416
- endpoint: `${url.protocol}//${url.host}`,
417
- provider: 'minio',
418
- prefix: pathParts.slice(1).join('/')
419
- };
420
- }
421
- // --- Azure Blob Storage ---
422
- // <account>.blob.core.windows.net/<container>
423
- const azureBlob = host.match(AZURE_BLOB_RE);
424
- if (azureBlob && pathParts.length > 0) {
425
- return {
426
- bucket: pathParts[0],
427
- region: defaults.region || '',
428
- endpoint: `${url.protocol}//${url.host}`,
429
- provider: 'azure',
430
- prefix: pathParts.slice(1).join('/')
431
- };
432
- }
433
- // --- Storj ---
434
- // S3 gateway: gateway.storjshare.io/<bucket> (or gateway.<region>.storjshare.io)
435
- const storjGateway = host.match(STORJ_GATEWAY_RE);
436
- if (storjGateway && pathParts.length > 0) {
437
- return {
438
- bucket: pathParts[0],
439
- region: storjGateway[1] || defaults.region || 'us1',
440
- endpoint: `${url.protocol}//${url.host}`,
441
- provider: 'storj',
442
- prefix: pathParts.slice(1).join('/')
443
- };
444
- }
445
- // Linksharing: link.storjshare.io/raw/<access>/<bucket>/... or /s/<access>/<bucket>/...
446
- const storjLink = host.match(STORJ_LINK_RE);
447
- if (storjLink && pathParts.length >= 3 && (pathParts[0] === 'raw' || pathParts[0] === 's')) {
448
- return {
449
- bucket: pathParts[2],
450
- region: storjLink[1] || defaults.region || 'us1',
451
- endpoint: `${url.protocol}//${url.host}/${pathParts[0]}/${pathParts[1]}`,
452
- provider: 'storj',
453
- prefix: pathParts.slice(3).join('/')
454
- };
455
- }
456
- // --- STAC API endpoints (Element 84, MPC, etc.) ---
457
- // Paths like /v1/collections/.../items/... are not S3 buckets, the
458
- // first path segment is an API version, not a bucket name. Return
459
- // no bucket so detectHostBucket() falls through and the URL opens
460
- // as a direct remote fetch.
461
- if (STAC_API_PATH_RE.test(url.pathname)) {
462
- return {
463
- ...defaultResult(defaults),
464
- endpoint: `${url.protocol}//${url.host}`
465
- };
466
- }
467
- // --- Generic custom endpoint with bucket in path ---
468
- if (pathParts.length > 0) {
469
- const endpoint = `${url.protocol}//${url.host}`;
470
- return {
471
- bucket: pathParts[0],
472
- region: defaults.region || 'us-east-1',
473
- endpoint,
474
- provider: defaults.provider || 's3',
475
- prefix: pathParts.slice(1).join('/')
476
- };
477
- }
478
- // Just a host, no path — treat as endpoint with no bucket
479
- return {
480
- ...defaultResult(defaults),
481
- endpoint: `${url.protocol}//${url.host}`
482
- };
483
- }
484
- catch {
485
- // Not a valid URL, fall through to plain bucket name
486
- }
487
- }
488
- // ── Plain bucket name (no protocol) ─────────────────────────────
489
- const cleaned = trimmed.replace(/^\/+|\/+$/g, '');
490
- return {
491
- bucket: cleaned,
492
- region: defaults.region || 'us-east-1',
493
- endpoint: defaults.endpoint || '',
494
- provider: defaults.provider || 's3',
495
- prefix: ''
496
- };
497
- }
498
- /**
499
- * Returns true if the input looks like a URL/URI rather than a plain bucket name.
500
- * Covers all recognized cloud storage URI schemes.
501
- */
502
- export function looksLikeUrl(input) {
503
- const lower = input.trim().toLowerCase();
504
- if (lower.startsWith('http://') || lower.startsWith('https://'))
505
- return true;
506
- for (const scheme of Object.keys(SCHEME_MAP)) {
507
- if (lower.startsWith(scheme))
508
- return true;
509
- }
510
- return false;
511
- }
512
- /**
513
- * Given a parsed URL result, build a human-readable summary of what was detected.
514
- */
515
- export function describeParseResult(parsed) {
516
- const parts = [];
517
- if (parsed.bucket)
518
- parts.push(`bucket="${parsed.bucket}"`);
519
- if (parsed.endpoint)
520
- parts.push(`endpoint="${parsed.endpoint}"`);
521
- if (parsed.region && parsed.region !== 'us-east-1')
522
- parts.push(`region="${parsed.region}"`);
523
- if (parsed.provider !== 's3')
524
- parts.push(`provider=${parsed.provider}`);
525
- if (parsed.prefix)
526
- parts.push(`prefix="${parsed.prefix}"`);
527
- return parts.length > 0 ? `Detected: ${parts.join(', ')}` : '';
528
- }
529
- /**
530
- * Classify a user-supplied URL/URI into one of four buckets. Unparseable or
531
- * plain inputs fall through to `remote-file` with a best-effort URL parse,
532
- * returning a synthetic `https://` URL when `new URL()` would throw.
533
- */
534
- export function classifyUrl(input) {
535
- const trimmed = input.trim();
536
- const lower = trimmed.toLowerCase();
537
- for (const scheme of Object.keys(SCHEME_MAP)) {
538
- if (lower.startsWith(scheme)) {
539
- return { kind: 'scheme', parsed: parseStorageUrl(trimmed) };
540
- }
541
- }
542
- if (lower.startsWith('http://') || lower.startsWith('https://')) {
543
- let url;
544
- try {
545
- url = new URL(trimmed);
546
- }
547
- catch {
548
- return {
549
- kind: 'remote-file',
550
- url: new URL(`https://${trimmed.replace(/^https?:\/\//i, '')}`)
551
- };
552
- }
553
- const parsed = parseStorageUrl(trimmed);
554
- if (parsed.bucket && isKnownBucketHost(url.hostname)) {
555
- return { kind: 'object-storage', parsed };
556
- }
557
- if (STAC_API_PATH_RE.test(url.pathname)) {
558
- return { kind: 'stac-api', url };
559
- }
560
- return { kind: 'remote-file', url };
561
- }
562
- try {
563
- return { kind: 'remote-file', url: new URL(trimmed) };
564
- }
565
- catch {
566
- return { kind: 'remote-file', url: new URL(`https://${trimmed}`) };
567
- }
568
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * Lightweight WKB (Well-Known Binary) parser for extracting coordinates.
3
- * Supports Point, LineString, Polygon, and Multi* variants.
4
- * Handles standard WKB, ISO WKB (with Z/M), and EWKB (PostGIS SRID).
5
- */
6
- export type GeoType = 'Point' | 'LineString' | 'Polygon' | 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' | 'Unknown';
7
- export interface ParsedGeometry {
8
- type: GeoType;
9
- coordinates: number[] | number[][] | number[][][] | number[][][][];
10
- }
11
- /**
12
- * Normalize binary data from various formats to Uint8Array.
13
- * Handles Uint8Array, ArrayBuffer, number arrays, hex strings,
14
- * and DuckDB toJSON() blob objects ({0: byte, 1: byte, ...}).
15
- */
16
- export declare function toBinary(value: unknown): Uint8Array | null;
17
- /**
18
- * Parse a WKB binary blob into coordinates and geometry type.
19
- */
20
- export declare function parseWKB(data: Uint8Array): ParsedGeometry | null;
21
- /**
22
- * Find the geometry column name from a schema.
23
- *
24
- * Detection priority:
25
- * 1. Column type contains a geometry keyword (GEOMETRY, POINT, WKB, etc.)
26
- * 2. Exact well-known column name with BLOB/BINARY type
27
- * 3. Exact well-known column name regardless of type
28
- * 4. Column name contains a geo-related substring with BLOB/BINARY type
29
- * 5. Column name contains a geo-related substring regardless of type
30
- */
31
- export declare function findGeoColumn(schema: {
32
- name: string;
33
- type: string;
34
- }[]): string | null;
35
- /**
36
- * Fallback: probe actual row data to find a column containing WKB geometry.
37
- * Use this when schema-only detection via `findGeoColumn()` returns null.
38
- * Samples the first row and checks each BLOB/binary column for WKB magic bytes.
39
- */
40
- export declare function findGeoColumnFromRows(rows: Record<string, unknown>[], schema: {
41
- name: string;
42
- type: string;
43
- }[]): string | null;