@walkthru-earth/objex-utils 0.1.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/LICENSE +396 -0
- package/dist/index.cjs +2543 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +433 -0
- package/dist/index.d.ts +433 -0
- package/dist/index.js +2512 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2543 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var apacheArrow = require('apache-arrow');
|
|
4
|
+
|
|
5
|
+
// ../../src/lib/file-icons/index.ts
|
|
6
|
+
var DEFAULT_INFO = {
|
|
7
|
+
icon: "File",
|
|
8
|
+
color: "text-zinc-400 dark:text-zinc-500",
|
|
9
|
+
label: "File",
|
|
10
|
+
category: "other",
|
|
11
|
+
viewer: "raw",
|
|
12
|
+
queryable: false,
|
|
13
|
+
duckdbReadFn: null,
|
|
14
|
+
mimeType: "application/octet-stream"
|
|
15
|
+
};
|
|
16
|
+
var FOLDER_INFO = {
|
|
17
|
+
icon: "Folder",
|
|
18
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
19
|
+
label: "Folder",
|
|
20
|
+
category: "other",
|
|
21
|
+
viewer: "raw",
|
|
22
|
+
queryable: false,
|
|
23
|
+
duckdbReadFn: null,
|
|
24
|
+
mimeType: "inode/directory"
|
|
25
|
+
};
|
|
26
|
+
var EXTENSIONS = {
|
|
27
|
+
// ── Data / Tabular ──────────────────────────────────────────────────
|
|
28
|
+
".parquet": {
|
|
29
|
+
icon: "Columns3",
|
|
30
|
+
color: "text-purple-600 dark:text-purple-400",
|
|
31
|
+
label: "Apache Parquet",
|
|
32
|
+
category: "data",
|
|
33
|
+
viewer: "table",
|
|
34
|
+
queryable: true,
|
|
35
|
+
duckdbReadFn: "read_parquet",
|
|
36
|
+
mimeType: "application/vnd.apache.parquet"
|
|
37
|
+
},
|
|
38
|
+
".geoparquet": {
|
|
39
|
+
icon: "Globe",
|
|
40
|
+
color: "text-purple-500 dark:text-purple-400",
|
|
41
|
+
label: "GeoParquet",
|
|
42
|
+
category: "geo",
|
|
43
|
+
viewer: "table",
|
|
44
|
+
queryable: true,
|
|
45
|
+
duckdbReadFn: "read_parquet",
|
|
46
|
+
mimeType: "application/vnd.apache.parquet"
|
|
47
|
+
},
|
|
48
|
+
".gpq": {
|
|
49
|
+
icon: "Globe",
|
|
50
|
+
color: "text-purple-500 dark:text-purple-400",
|
|
51
|
+
label: "GeoParquet",
|
|
52
|
+
category: "geo",
|
|
53
|
+
viewer: "table",
|
|
54
|
+
queryable: true,
|
|
55
|
+
duckdbReadFn: "read_parquet",
|
|
56
|
+
mimeType: "application/vnd.apache.parquet"
|
|
57
|
+
},
|
|
58
|
+
".gparquet": {
|
|
59
|
+
icon: "Globe",
|
|
60
|
+
color: "text-purple-500 dark:text-purple-400",
|
|
61
|
+
label: "GeoParquet",
|
|
62
|
+
category: "geo",
|
|
63
|
+
viewer: "table",
|
|
64
|
+
queryable: true,
|
|
65
|
+
duckdbReadFn: "read_parquet",
|
|
66
|
+
mimeType: "application/vnd.apache.parquet"
|
|
67
|
+
},
|
|
68
|
+
".csv": {
|
|
69
|
+
icon: "Table",
|
|
70
|
+
color: "text-green-600 dark:text-green-400",
|
|
71
|
+
label: "CSV",
|
|
72
|
+
category: "data",
|
|
73
|
+
viewer: "table",
|
|
74
|
+
queryable: true,
|
|
75
|
+
duckdbReadFn: "read_csv",
|
|
76
|
+
mimeType: "text/csv"
|
|
77
|
+
},
|
|
78
|
+
".tsv": {
|
|
79
|
+
icon: "Table",
|
|
80
|
+
color: "text-green-600 dark:text-green-400",
|
|
81
|
+
label: "TSV",
|
|
82
|
+
category: "data",
|
|
83
|
+
viewer: "table",
|
|
84
|
+
queryable: true,
|
|
85
|
+
duckdbReadFn: "read_csv",
|
|
86
|
+
mimeType: "text/tab-separated-values"
|
|
87
|
+
},
|
|
88
|
+
".json": {
|
|
89
|
+
icon: "Braces",
|
|
90
|
+
color: "text-yellow-600 dark:text-yellow-400",
|
|
91
|
+
label: "JSON",
|
|
92
|
+
category: "config",
|
|
93
|
+
viewer: "code",
|
|
94
|
+
queryable: false,
|
|
95
|
+
duckdbReadFn: null,
|
|
96
|
+
mimeType: "application/json"
|
|
97
|
+
},
|
|
98
|
+
".jsonl": {
|
|
99
|
+
icon: "Braces",
|
|
100
|
+
color: "text-yellow-500 dark:text-yellow-400",
|
|
101
|
+
label: "JSON Lines",
|
|
102
|
+
category: "data",
|
|
103
|
+
viewer: "table",
|
|
104
|
+
queryable: true,
|
|
105
|
+
duckdbReadFn: "read_json",
|
|
106
|
+
mimeType: "application/x-jsonlines"
|
|
107
|
+
},
|
|
108
|
+
".ndjson": {
|
|
109
|
+
icon: "Braces",
|
|
110
|
+
color: "text-yellow-500 dark:text-yellow-400",
|
|
111
|
+
label: "NDJSON",
|
|
112
|
+
category: "data",
|
|
113
|
+
viewer: "table",
|
|
114
|
+
queryable: true,
|
|
115
|
+
duckdbReadFn: "read_json",
|
|
116
|
+
mimeType: "application/x-ndjson"
|
|
117
|
+
},
|
|
118
|
+
".geojson": {
|
|
119
|
+
icon: "Globe",
|
|
120
|
+
color: "text-emerald-600 dark:text-emerald-400",
|
|
121
|
+
label: "GeoJSON",
|
|
122
|
+
category: "geo",
|
|
123
|
+
viewer: "table",
|
|
124
|
+
queryable: true,
|
|
125
|
+
duckdbReadFn: "read_json",
|
|
126
|
+
mimeType: "application/geo+json"
|
|
127
|
+
},
|
|
128
|
+
".arrow": {
|
|
129
|
+
icon: "Zap",
|
|
130
|
+
color: "text-orange-500 dark:text-orange-400",
|
|
131
|
+
label: "Apache Arrow",
|
|
132
|
+
category: "data",
|
|
133
|
+
viewer: "raw",
|
|
134
|
+
queryable: false,
|
|
135
|
+
duckdbReadFn: null,
|
|
136
|
+
mimeType: "application/vnd.apache.arrow.file"
|
|
137
|
+
},
|
|
138
|
+
".feather": {
|
|
139
|
+
icon: "Zap",
|
|
140
|
+
color: "text-orange-500 dark:text-orange-400",
|
|
141
|
+
label: "Feather",
|
|
142
|
+
category: "data",
|
|
143
|
+
viewer: "raw",
|
|
144
|
+
queryable: false,
|
|
145
|
+
duckdbReadFn: null,
|
|
146
|
+
mimeType: "application/vnd.apache.arrow.file"
|
|
147
|
+
},
|
|
148
|
+
".ipc": {
|
|
149
|
+
icon: "Zap",
|
|
150
|
+
color: "text-orange-500 dark:text-orange-400",
|
|
151
|
+
label: "Arrow IPC",
|
|
152
|
+
category: "data",
|
|
153
|
+
viewer: "raw",
|
|
154
|
+
queryable: false,
|
|
155
|
+
duckdbReadFn: null,
|
|
156
|
+
mimeType: "application/vnd.apache.arrow.stream"
|
|
157
|
+
},
|
|
158
|
+
// ── Images ──────────────────────────────────────────────────────────
|
|
159
|
+
".png": {
|
|
160
|
+
icon: "Image",
|
|
161
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
162
|
+
label: "PNG Image",
|
|
163
|
+
category: "image",
|
|
164
|
+
viewer: "image",
|
|
165
|
+
queryable: false,
|
|
166
|
+
duckdbReadFn: null,
|
|
167
|
+
mimeType: "image/png"
|
|
168
|
+
},
|
|
169
|
+
".jpg": {
|
|
170
|
+
icon: "Image",
|
|
171
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
172
|
+
label: "JPEG Image",
|
|
173
|
+
category: "image",
|
|
174
|
+
viewer: "image",
|
|
175
|
+
queryable: false,
|
|
176
|
+
duckdbReadFn: null,
|
|
177
|
+
mimeType: "image/jpeg"
|
|
178
|
+
},
|
|
179
|
+
".jpeg": {
|
|
180
|
+
icon: "Image",
|
|
181
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
182
|
+
label: "JPEG Image",
|
|
183
|
+
category: "image",
|
|
184
|
+
viewer: "image",
|
|
185
|
+
queryable: false,
|
|
186
|
+
duckdbReadFn: null,
|
|
187
|
+
mimeType: "image/jpeg"
|
|
188
|
+
},
|
|
189
|
+
".gif": {
|
|
190
|
+
icon: "Image",
|
|
191
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
192
|
+
label: "GIF Image",
|
|
193
|
+
category: "image",
|
|
194
|
+
viewer: "image",
|
|
195
|
+
queryable: false,
|
|
196
|
+
duckdbReadFn: null,
|
|
197
|
+
mimeType: "image/gif"
|
|
198
|
+
},
|
|
199
|
+
".webp": {
|
|
200
|
+
icon: "Image",
|
|
201
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
202
|
+
label: "WebP Image",
|
|
203
|
+
category: "image",
|
|
204
|
+
viewer: "image",
|
|
205
|
+
queryable: false,
|
|
206
|
+
duckdbReadFn: null,
|
|
207
|
+
mimeType: "image/webp"
|
|
208
|
+
},
|
|
209
|
+
".avif": {
|
|
210
|
+
icon: "Image",
|
|
211
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
212
|
+
label: "AVIF Image",
|
|
213
|
+
category: "image",
|
|
214
|
+
viewer: "image",
|
|
215
|
+
queryable: false,
|
|
216
|
+
duckdbReadFn: null,
|
|
217
|
+
mimeType: "image/avif"
|
|
218
|
+
},
|
|
219
|
+
".svg": {
|
|
220
|
+
icon: "Palette",
|
|
221
|
+
color: "text-pink-600 dark:text-pink-400",
|
|
222
|
+
label: "SVG",
|
|
223
|
+
category: "image",
|
|
224
|
+
viewer: "image",
|
|
225
|
+
queryable: false,
|
|
226
|
+
duckdbReadFn: null,
|
|
227
|
+
mimeType: "image/svg+xml"
|
|
228
|
+
},
|
|
229
|
+
".bmp": {
|
|
230
|
+
icon: "Image",
|
|
231
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
232
|
+
label: "BMP Image",
|
|
233
|
+
category: "image",
|
|
234
|
+
viewer: "image",
|
|
235
|
+
queryable: false,
|
|
236
|
+
duckdbReadFn: null,
|
|
237
|
+
mimeType: "image/bmp"
|
|
238
|
+
},
|
|
239
|
+
".ico": {
|
|
240
|
+
icon: "Image",
|
|
241
|
+
color: "text-pink-500 dark:text-pink-400",
|
|
242
|
+
label: "Icon",
|
|
243
|
+
category: "image",
|
|
244
|
+
viewer: "image",
|
|
245
|
+
queryable: false,
|
|
246
|
+
duckdbReadFn: null,
|
|
247
|
+
mimeType: "image/x-icon"
|
|
248
|
+
},
|
|
249
|
+
// ── Video ───────────────────────────────────────────────────────────
|
|
250
|
+
".mp4": {
|
|
251
|
+
icon: "Film",
|
|
252
|
+
color: "text-violet-500 dark:text-violet-400",
|
|
253
|
+
label: "MP4 Video",
|
|
254
|
+
category: "video",
|
|
255
|
+
viewer: "video",
|
|
256
|
+
queryable: false,
|
|
257
|
+
duckdbReadFn: null,
|
|
258
|
+
mimeType: "video/mp4"
|
|
259
|
+
},
|
|
260
|
+
".webm": {
|
|
261
|
+
icon: "Film",
|
|
262
|
+
color: "text-violet-500 dark:text-violet-400",
|
|
263
|
+
label: "WebM Video",
|
|
264
|
+
category: "video",
|
|
265
|
+
viewer: "video",
|
|
266
|
+
queryable: false,
|
|
267
|
+
duckdbReadFn: null,
|
|
268
|
+
mimeType: "video/webm"
|
|
269
|
+
},
|
|
270
|
+
".mov": {
|
|
271
|
+
icon: "Film",
|
|
272
|
+
color: "text-violet-500 dark:text-violet-400",
|
|
273
|
+
label: "MOV Video",
|
|
274
|
+
category: "video",
|
|
275
|
+
viewer: "video",
|
|
276
|
+
queryable: false,
|
|
277
|
+
duckdbReadFn: null,
|
|
278
|
+
mimeType: "video/quicktime"
|
|
279
|
+
},
|
|
280
|
+
".avi": {
|
|
281
|
+
icon: "Film",
|
|
282
|
+
color: "text-violet-500 dark:text-violet-400",
|
|
283
|
+
label: "AVI Video",
|
|
284
|
+
category: "video",
|
|
285
|
+
viewer: "video",
|
|
286
|
+
queryable: false,
|
|
287
|
+
duckdbReadFn: null,
|
|
288
|
+
mimeType: "video/x-msvideo"
|
|
289
|
+
},
|
|
290
|
+
".mkv": {
|
|
291
|
+
icon: "Film",
|
|
292
|
+
color: "text-violet-500 dark:text-violet-400",
|
|
293
|
+
label: "MKV Video",
|
|
294
|
+
category: "video",
|
|
295
|
+
viewer: "video",
|
|
296
|
+
queryable: false,
|
|
297
|
+
duckdbReadFn: null,
|
|
298
|
+
mimeType: "video/x-matroska"
|
|
299
|
+
},
|
|
300
|
+
// ── Audio ───────────────────────────────────────────────────────────
|
|
301
|
+
".mp3": {
|
|
302
|
+
icon: "Music",
|
|
303
|
+
color: "text-rose-500 dark:text-rose-400",
|
|
304
|
+
label: "MP3 Audio",
|
|
305
|
+
category: "audio",
|
|
306
|
+
viewer: "audio",
|
|
307
|
+
queryable: false,
|
|
308
|
+
duckdbReadFn: null,
|
|
309
|
+
mimeType: "audio/mpeg"
|
|
310
|
+
},
|
|
311
|
+
".wav": {
|
|
312
|
+
icon: "Music",
|
|
313
|
+
color: "text-rose-500 dark:text-rose-400",
|
|
314
|
+
label: "WAV Audio",
|
|
315
|
+
category: "audio",
|
|
316
|
+
viewer: "audio",
|
|
317
|
+
queryable: false,
|
|
318
|
+
duckdbReadFn: null,
|
|
319
|
+
mimeType: "audio/wav"
|
|
320
|
+
},
|
|
321
|
+
".ogg": {
|
|
322
|
+
icon: "Music",
|
|
323
|
+
color: "text-rose-500 dark:text-rose-400",
|
|
324
|
+
label: "OGG Audio",
|
|
325
|
+
category: "audio",
|
|
326
|
+
viewer: "audio",
|
|
327
|
+
queryable: false,
|
|
328
|
+
duckdbReadFn: null,
|
|
329
|
+
mimeType: "audio/ogg"
|
|
330
|
+
},
|
|
331
|
+
".flac": {
|
|
332
|
+
icon: "Music",
|
|
333
|
+
color: "text-rose-500 dark:text-rose-400",
|
|
334
|
+
label: "FLAC Audio",
|
|
335
|
+
category: "audio",
|
|
336
|
+
viewer: "audio",
|
|
337
|
+
queryable: false,
|
|
338
|
+
duckdbReadFn: null,
|
|
339
|
+
mimeType: "audio/flac"
|
|
340
|
+
},
|
|
341
|
+
".aac": {
|
|
342
|
+
icon: "Music",
|
|
343
|
+
color: "text-rose-500 dark:text-rose-400",
|
|
344
|
+
label: "AAC Audio",
|
|
345
|
+
category: "audio",
|
|
346
|
+
viewer: "audio",
|
|
347
|
+
queryable: false,
|
|
348
|
+
duckdbReadFn: null,
|
|
349
|
+
mimeType: "audio/aac"
|
|
350
|
+
},
|
|
351
|
+
// ── Code ────────────────────────────────────────────────────────────
|
|
352
|
+
".py": {
|
|
353
|
+
icon: "FileCode",
|
|
354
|
+
color: "text-sky-600 dark:text-sky-400",
|
|
355
|
+
label: "Python",
|
|
356
|
+
category: "code",
|
|
357
|
+
viewer: "code",
|
|
358
|
+
queryable: false,
|
|
359
|
+
duckdbReadFn: null,
|
|
360
|
+
mimeType: "text/x-python"
|
|
361
|
+
},
|
|
362
|
+
".ts": {
|
|
363
|
+
icon: "FileCode",
|
|
364
|
+
color: "text-blue-600 dark:text-blue-400",
|
|
365
|
+
label: "TypeScript",
|
|
366
|
+
category: "code",
|
|
367
|
+
viewer: "code",
|
|
368
|
+
queryable: false,
|
|
369
|
+
duckdbReadFn: null,
|
|
370
|
+
mimeType: "text/typescript"
|
|
371
|
+
},
|
|
372
|
+
".js": {
|
|
373
|
+
icon: "FileCode",
|
|
374
|
+
color: "text-yellow-500 dark:text-yellow-400",
|
|
375
|
+
label: "JavaScript",
|
|
376
|
+
category: "code",
|
|
377
|
+
viewer: "code",
|
|
378
|
+
queryable: false,
|
|
379
|
+
duckdbReadFn: null,
|
|
380
|
+
mimeType: "text/javascript"
|
|
381
|
+
},
|
|
382
|
+
".rs": {
|
|
383
|
+
icon: "FileCode",
|
|
384
|
+
color: "text-orange-700 dark:text-orange-400",
|
|
385
|
+
label: "Rust",
|
|
386
|
+
category: "code",
|
|
387
|
+
viewer: "code",
|
|
388
|
+
queryable: false,
|
|
389
|
+
duckdbReadFn: null,
|
|
390
|
+
mimeType: "text/x-rust"
|
|
391
|
+
},
|
|
392
|
+
".go": {
|
|
393
|
+
icon: "FileCode",
|
|
394
|
+
color: "text-cyan-600 dark:text-cyan-400",
|
|
395
|
+
label: "Go",
|
|
396
|
+
category: "code",
|
|
397
|
+
viewer: "code",
|
|
398
|
+
queryable: false,
|
|
399
|
+
duckdbReadFn: null,
|
|
400
|
+
mimeType: "text/x-go"
|
|
401
|
+
},
|
|
402
|
+
".java": {
|
|
403
|
+
icon: "FileCode",
|
|
404
|
+
color: "text-red-600 dark:text-red-400",
|
|
405
|
+
label: "Java",
|
|
406
|
+
category: "code",
|
|
407
|
+
viewer: "code",
|
|
408
|
+
queryable: false,
|
|
409
|
+
duckdbReadFn: null,
|
|
410
|
+
mimeType: "text/x-java"
|
|
411
|
+
},
|
|
412
|
+
".c": {
|
|
413
|
+
icon: "FileCode",
|
|
414
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
415
|
+
label: "C",
|
|
416
|
+
category: "code",
|
|
417
|
+
viewer: "code",
|
|
418
|
+
queryable: false,
|
|
419
|
+
duckdbReadFn: null,
|
|
420
|
+
mimeType: "text/x-c"
|
|
421
|
+
},
|
|
422
|
+
".cpp": {
|
|
423
|
+
icon: "FileCode",
|
|
424
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
425
|
+
label: "C++",
|
|
426
|
+
category: "code",
|
|
427
|
+
viewer: "code",
|
|
428
|
+
queryable: false,
|
|
429
|
+
duckdbReadFn: null,
|
|
430
|
+
mimeType: "text/x-c++"
|
|
431
|
+
},
|
|
432
|
+
".h": {
|
|
433
|
+
icon: "FileCode",
|
|
434
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
435
|
+
label: "C Header",
|
|
436
|
+
category: "code",
|
|
437
|
+
viewer: "code",
|
|
438
|
+
queryable: false,
|
|
439
|
+
duckdbReadFn: null,
|
|
440
|
+
mimeType: "text/x-c"
|
|
441
|
+
},
|
|
442
|
+
".hpp": {
|
|
443
|
+
icon: "FileCode",
|
|
444
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
445
|
+
label: "C++ Header",
|
|
446
|
+
category: "code",
|
|
447
|
+
viewer: "code",
|
|
448
|
+
queryable: false,
|
|
449
|
+
duckdbReadFn: null,
|
|
450
|
+
mimeType: "text/x-c++"
|
|
451
|
+
},
|
|
452
|
+
".rb": {
|
|
453
|
+
icon: "FileCode",
|
|
454
|
+
color: "text-red-500 dark:text-red-400",
|
|
455
|
+
label: "Ruby",
|
|
456
|
+
category: "code",
|
|
457
|
+
viewer: "code",
|
|
458
|
+
queryable: false,
|
|
459
|
+
duckdbReadFn: null,
|
|
460
|
+
mimeType: "text/x-ruby"
|
|
461
|
+
},
|
|
462
|
+
".php": {
|
|
463
|
+
icon: "FileCode",
|
|
464
|
+
color: "text-indigo-500 dark:text-indigo-400",
|
|
465
|
+
label: "PHP",
|
|
466
|
+
category: "code",
|
|
467
|
+
viewer: "code",
|
|
468
|
+
queryable: false,
|
|
469
|
+
duckdbReadFn: null,
|
|
470
|
+
mimeType: "text/x-php"
|
|
471
|
+
},
|
|
472
|
+
".swift": {
|
|
473
|
+
icon: "FileCode",
|
|
474
|
+
color: "text-orange-500 dark:text-orange-400",
|
|
475
|
+
label: "Swift",
|
|
476
|
+
category: "code",
|
|
477
|
+
viewer: "code",
|
|
478
|
+
queryable: false,
|
|
479
|
+
duckdbReadFn: null,
|
|
480
|
+
mimeType: "text/x-swift"
|
|
481
|
+
},
|
|
482
|
+
".kt": {
|
|
483
|
+
icon: "FileCode",
|
|
484
|
+
color: "text-violet-600 dark:text-violet-400",
|
|
485
|
+
label: "Kotlin",
|
|
486
|
+
category: "code",
|
|
487
|
+
viewer: "code",
|
|
488
|
+
queryable: false,
|
|
489
|
+
duckdbReadFn: null,
|
|
490
|
+
mimeType: "text/x-kotlin"
|
|
491
|
+
},
|
|
492
|
+
".scala": {
|
|
493
|
+
icon: "FileCode",
|
|
494
|
+
color: "text-red-600 dark:text-red-400",
|
|
495
|
+
label: "Scala",
|
|
496
|
+
category: "code",
|
|
497
|
+
viewer: "code",
|
|
498
|
+
queryable: false,
|
|
499
|
+
duckdbReadFn: null,
|
|
500
|
+
mimeType: "text/x-scala"
|
|
501
|
+
},
|
|
502
|
+
".r": {
|
|
503
|
+
icon: "FileCode",
|
|
504
|
+
color: "text-blue-600 dark:text-blue-400",
|
|
505
|
+
label: "R",
|
|
506
|
+
category: "code",
|
|
507
|
+
viewer: "code",
|
|
508
|
+
queryable: false,
|
|
509
|
+
duckdbReadFn: null,
|
|
510
|
+
mimeType: "text/x-r"
|
|
511
|
+
},
|
|
512
|
+
".lua": {
|
|
513
|
+
icon: "FileCode",
|
|
514
|
+
color: "text-blue-800 dark:text-blue-400",
|
|
515
|
+
label: "Lua",
|
|
516
|
+
category: "code",
|
|
517
|
+
viewer: "code",
|
|
518
|
+
queryable: false,
|
|
519
|
+
duckdbReadFn: null,
|
|
520
|
+
mimeType: "text/x-lua"
|
|
521
|
+
},
|
|
522
|
+
".html": {
|
|
523
|
+
icon: "Globe",
|
|
524
|
+
color: "text-orange-600 dark:text-orange-400",
|
|
525
|
+
label: "HTML",
|
|
526
|
+
category: "code",
|
|
527
|
+
viewer: "code",
|
|
528
|
+
queryable: false,
|
|
529
|
+
duckdbReadFn: null,
|
|
530
|
+
mimeType: "text/html"
|
|
531
|
+
},
|
|
532
|
+
".css": {
|
|
533
|
+
icon: "Paintbrush",
|
|
534
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
535
|
+
label: "CSS",
|
|
536
|
+
category: "code",
|
|
537
|
+
viewer: "code",
|
|
538
|
+
queryable: false,
|
|
539
|
+
duckdbReadFn: null,
|
|
540
|
+
mimeType: "text/css"
|
|
541
|
+
},
|
|
542
|
+
".sql": {
|
|
543
|
+
icon: "DatabaseZap",
|
|
544
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
545
|
+
label: "SQL",
|
|
546
|
+
category: "code",
|
|
547
|
+
viewer: "code",
|
|
548
|
+
queryable: false,
|
|
549
|
+
duckdbReadFn: null,
|
|
550
|
+
mimeType: "text/x-sql"
|
|
551
|
+
},
|
|
552
|
+
".sh": {
|
|
553
|
+
icon: "Terminal",
|
|
554
|
+
color: "text-green-600 dark:text-green-400",
|
|
555
|
+
label: "Shell Script",
|
|
556
|
+
category: "code",
|
|
557
|
+
viewer: "code",
|
|
558
|
+
queryable: false,
|
|
559
|
+
duckdbReadFn: null,
|
|
560
|
+
mimeType: "text/x-shellscript"
|
|
561
|
+
},
|
|
562
|
+
".bash": {
|
|
563
|
+
icon: "Terminal",
|
|
564
|
+
color: "text-green-600 dark:text-green-400",
|
|
565
|
+
label: "Bash Script",
|
|
566
|
+
category: "code",
|
|
567
|
+
viewer: "code",
|
|
568
|
+
queryable: false,
|
|
569
|
+
duckdbReadFn: null,
|
|
570
|
+
mimeType: "text/x-shellscript"
|
|
571
|
+
},
|
|
572
|
+
".vim": {
|
|
573
|
+
icon: "FileCode",
|
|
574
|
+
color: "text-green-700 dark:text-green-400",
|
|
575
|
+
label: "Vim Script",
|
|
576
|
+
category: "code",
|
|
577
|
+
viewer: "code",
|
|
578
|
+
queryable: false,
|
|
579
|
+
duckdbReadFn: null,
|
|
580
|
+
mimeType: "text/plain"
|
|
581
|
+
},
|
|
582
|
+
".dockerfile": {
|
|
583
|
+
icon: "FileCode",
|
|
584
|
+
color: "text-blue-600 dark:text-blue-400",
|
|
585
|
+
label: "Dockerfile",
|
|
586
|
+
category: "code",
|
|
587
|
+
viewer: "code",
|
|
588
|
+
queryable: false,
|
|
589
|
+
duckdbReadFn: null,
|
|
590
|
+
mimeType: "text/plain"
|
|
591
|
+
},
|
|
592
|
+
".makefile": {
|
|
593
|
+
icon: "FileCode",
|
|
594
|
+
color: "text-orange-600 dark:text-orange-400",
|
|
595
|
+
label: "Makefile",
|
|
596
|
+
category: "code",
|
|
597
|
+
viewer: "code",
|
|
598
|
+
queryable: false,
|
|
599
|
+
duckdbReadFn: null,
|
|
600
|
+
mimeType: "text/plain"
|
|
601
|
+
},
|
|
602
|
+
// ── Documents ───────────────────────────────────────────────────────
|
|
603
|
+
".md": {
|
|
604
|
+
icon: "BookText",
|
|
605
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
606
|
+
label: "Markdown",
|
|
607
|
+
category: "document",
|
|
608
|
+
viewer: "markdown",
|
|
609
|
+
queryable: false,
|
|
610
|
+
duckdbReadFn: null,
|
|
611
|
+
mimeType: "text/markdown"
|
|
612
|
+
},
|
|
613
|
+
".markdown": {
|
|
614
|
+
icon: "BookText",
|
|
615
|
+
color: "text-blue-500 dark:text-blue-400",
|
|
616
|
+
label: "Markdown",
|
|
617
|
+
category: "document",
|
|
618
|
+
viewer: "markdown",
|
|
619
|
+
queryable: false,
|
|
620
|
+
duckdbReadFn: null,
|
|
621
|
+
mimeType: "text/markdown"
|
|
622
|
+
},
|
|
623
|
+
".pdf": {
|
|
624
|
+
icon: "FileText",
|
|
625
|
+
color: "text-red-600 dark:text-red-400",
|
|
626
|
+
label: "PDF",
|
|
627
|
+
category: "document",
|
|
628
|
+
viewer: "pdf",
|
|
629
|
+
queryable: false,
|
|
630
|
+
duckdbReadFn: null,
|
|
631
|
+
mimeType: "application/pdf"
|
|
632
|
+
},
|
|
633
|
+
".txt": {
|
|
634
|
+
icon: "FileText",
|
|
635
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
636
|
+
label: "Text",
|
|
637
|
+
category: "document",
|
|
638
|
+
viewer: "code",
|
|
639
|
+
queryable: false,
|
|
640
|
+
duckdbReadFn: null,
|
|
641
|
+
mimeType: "text/plain"
|
|
642
|
+
},
|
|
643
|
+
".log": {
|
|
644
|
+
icon: "FileText",
|
|
645
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
646
|
+
label: "Log File",
|
|
647
|
+
category: "document",
|
|
648
|
+
viewer: "code",
|
|
649
|
+
queryable: false,
|
|
650
|
+
duckdbReadFn: null,
|
|
651
|
+
mimeType: "text/plain"
|
|
652
|
+
},
|
|
653
|
+
// ── Config ──────────────────────────────────────────────────────────
|
|
654
|
+
".xml": {
|
|
655
|
+
icon: "FileCode",
|
|
656
|
+
color: "text-orange-500 dark:text-orange-400",
|
|
657
|
+
label: "XML",
|
|
658
|
+
category: "config",
|
|
659
|
+
viewer: "code",
|
|
660
|
+
queryable: false,
|
|
661
|
+
duckdbReadFn: null,
|
|
662
|
+
mimeType: "application/xml"
|
|
663
|
+
},
|
|
664
|
+
".yaml": {
|
|
665
|
+
icon: "Settings",
|
|
666
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
667
|
+
label: "YAML",
|
|
668
|
+
category: "config",
|
|
669
|
+
viewer: "code",
|
|
670
|
+
queryable: false,
|
|
671
|
+
duckdbReadFn: null,
|
|
672
|
+
mimeType: "text/yaml"
|
|
673
|
+
},
|
|
674
|
+
".yml": {
|
|
675
|
+
icon: "Settings",
|
|
676
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
677
|
+
label: "YAML",
|
|
678
|
+
category: "config",
|
|
679
|
+
viewer: "code",
|
|
680
|
+
queryable: false,
|
|
681
|
+
duckdbReadFn: null,
|
|
682
|
+
mimeType: "text/yaml"
|
|
683
|
+
},
|
|
684
|
+
".toml": {
|
|
685
|
+
icon: "Settings",
|
|
686
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
687
|
+
label: "TOML",
|
|
688
|
+
category: "config",
|
|
689
|
+
viewer: "code",
|
|
690
|
+
queryable: false,
|
|
691
|
+
duckdbReadFn: null,
|
|
692
|
+
mimeType: "text/plain"
|
|
693
|
+
},
|
|
694
|
+
".ini": {
|
|
695
|
+
icon: "Settings",
|
|
696
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
697
|
+
label: "INI",
|
|
698
|
+
category: "config",
|
|
699
|
+
viewer: "code",
|
|
700
|
+
queryable: false,
|
|
701
|
+
duckdbReadFn: null,
|
|
702
|
+
mimeType: "text/plain"
|
|
703
|
+
},
|
|
704
|
+
".cfg": {
|
|
705
|
+
icon: "Settings",
|
|
706
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
707
|
+
label: "Config",
|
|
708
|
+
category: "config",
|
|
709
|
+
viewer: "code",
|
|
710
|
+
queryable: false,
|
|
711
|
+
duckdbReadFn: null,
|
|
712
|
+
mimeType: "text/plain"
|
|
713
|
+
},
|
|
714
|
+
".conf": {
|
|
715
|
+
icon: "Settings",
|
|
716
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
717
|
+
label: "Config",
|
|
718
|
+
category: "config",
|
|
719
|
+
viewer: "code",
|
|
720
|
+
queryable: false,
|
|
721
|
+
duckdbReadFn: null,
|
|
722
|
+
mimeType: "text/plain"
|
|
723
|
+
},
|
|
724
|
+
".env": {
|
|
725
|
+
icon: "Settings",
|
|
726
|
+
color: "text-zinc-500 dark:text-zinc-400",
|
|
727
|
+
label: "Environment",
|
|
728
|
+
category: "config",
|
|
729
|
+
viewer: "code",
|
|
730
|
+
queryable: false,
|
|
731
|
+
duckdbReadFn: null,
|
|
732
|
+
mimeType: "text/plain"
|
|
733
|
+
},
|
|
734
|
+
// ── Archives ────────────────────────────────────────────────────────
|
|
735
|
+
".zip": {
|
|
736
|
+
icon: "Archive",
|
|
737
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
738
|
+
label: "ZIP Archive",
|
|
739
|
+
category: "archive",
|
|
740
|
+
viewer: "archive",
|
|
741
|
+
queryable: false,
|
|
742
|
+
duckdbReadFn: null,
|
|
743
|
+
mimeType: "application/zip"
|
|
744
|
+
},
|
|
745
|
+
".tar": {
|
|
746
|
+
icon: "Archive",
|
|
747
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
748
|
+
label: "TAR Archive",
|
|
749
|
+
category: "archive",
|
|
750
|
+
viewer: "archive",
|
|
751
|
+
queryable: false,
|
|
752
|
+
duckdbReadFn: null,
|
|
753
|
+
mimeType: "application/x-tar"
|
|
754
|
+
},
|
|
755
|
+
".gz": {
|
|
756
|
+
icon: "Archive",
|
|
757
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
758
|
+
label: "GZIP",
|
|
759
|
+
category: "archive",
|
|
760
|
+
viewer: "archive",
|
|
761
|
+
queryable: false,
|
|
762
|
+
duckdbReadFn: null,
|
|
763
|
+
mimeType: "application/gzip"
|
|
764
|
+
},
|
|
765
|
+
".tgz": {
|
|
766
|
+
icon: "Archive",
|
|
767
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
768
|
+
label: "TGZ Archive",
|
|
769
|
+
category: "archive",
|
|
770
|
+
viewer: "archive",
|
|
771
|
+
queryable: false,
|
|
772
|
+
duckdbReadFn: null,
|
|
773
|
+
mimeType: "application/gzip"
|
|
774
|
+
},
|
|
775
|
+
".7z": {
|
|
776
|
+
icon: "Archive",
|
|
777
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
778
|
+
label: "7-Zip",
|
|
779
|
+
category: "archive",
|
|
780
|
+
viewer: "archive",
|
|
781
|
+
queryable: false,
|
|
782
|
+
duckdbReadFn: null,
|
|
783
|
+
mimeType: "application/x-7z-compressed"
|
|
784
|
+
},
|
|
785
|
+
".rar": {
|
|
786
|
+
icon: "Archive",
|
|
787
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
788
|
+
label: "RAR",
|
|
789
|
+
category: "archive",
|
|
790
|
+
viewer: "archive",
|
|
791
|
+
queryable: false,
|
|
792
|
+
duckdbReadFn: null,
|
|
793
|
+
mimeType: "application/vnd.rar"
|
|
794
|
+
},
|
|
795
|
+
".bz2": {
|
|
796
|
+
icon: "Archive",
|
|
797
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
798
|
+
label: "BZIP2",
|
|
799
|
+
category: "archive",
|
|
800
|
+
viewer: "archive",
|
|
801
|
+
queryable: false,
|
|
802
|
+
duckdbReadFn: null,
|
|
803
|
+
mimeType: "application/x-bzip2"
|
|
804
|
+
},
|
|
805
|
+
// ── Geo / Map ───────────────────────────────────────────────────────
|
|
806
|
+
".tif": {
|
|
807
|
+
icon: "Map",
|
|
808
|
+
color: "text-green-600 dark:text-green-400",
|
|
809
|
+
label: "GeoTIFF",
|
|
810
|
+
category: "geo",
|
|
811
|
+
viewer: "cog",
|
|
812
|
+
queryable: false,
|
|
813
|
+
duckdbReadFn: null,
|
|
814
|
+
mimeType: "image/tiff"
|
|
815
|
+
},
|
|
816
|
+
".tiff": {
|
|
817
|
+
icon: "Map",
|
|
818
|
+
color: "text-green-600 dark:text-green-400",
|
|
819
|
+
label: "GeoTIFF",
|
|
820
|
+
category: "geo",
|
|
821
|
+
viewer: "cog",
|
|
822
|
+
queryable: false,
|
|
823
|
+
duckdbReadFn: null,
|
|
824
|
+
mimeType: "image/tiff"
|
|
825
|
+
},
|
|
826
|
+
".pmtiles": {
|
|
827
|
+
icon: "Layers",
|
|
828
|
+
color: "text-teal-600 dark:text-teal-400",
|
|
829
|
+
label: "PMTiles",
|
|
830
|
+
category: "geo",
|
|
831
|
+
viewer: "pmtiles",
|
|
832
|
+
queryable: false,
|
|
833
|
+
duckdbReadFn: null,
|
|
834
|
+
mimeType: "application/octet-stream"
|
|
835
|
+
},
|
|
836
|
+
".fgb": {
|
|
837
|
+
icon: "Globe",
|
|
838
|
+
color: "text-teal-500 dark:text-teal-400",
|
|
839
|
+
label: "FlatGeobuf",
|
|
840
|
+
category: "geo",
|
|
841
|
+
viewer: "flatgeobuf",
|
|
842
|
+
queryable: false,
|
|
843
|
+
duckdbReadFn: null,
|
|
844
|
+
mimeType: "application/octet-stream"
|
|
845
|
+
},
|
|
846
|
+
".shp": {
|
|
847
|
+
icon: "Globe",
|
|
848
|
+
color: "text-green-600 dark:text-green-400",
|
|
849
|
+
label: "Shapefile",
|
|
850
|
+
category: "geo",
|
|
851
|
+
viewer: "table",
|
|
852
|
+
queryable: true,
|
|
853
|
+
duckdbReadFn: "ST_Read",
|
|
854
|
+
mimeType: "application/x-esri-shape"
|
|
855
|
+
},
|
|
856
|
+
".gpkg": {
|
|
857
|
+
icon: "Database",
|
|
858
|
+
color: "text-green-600 dark:text-green-400",
|
|
859
|
+
label: "GeoPackage",
|
|
860
|
+
category: "geo",
|
|
861
|
+
viewer: "table",
|
|
862
|
+
queryable: true,
|
|
863
|
+
duckdbReadFn: "ST_Read",
|
|
864
|
+
mimeType: "application/geopackage+sqlite3"
|
|
865
|
+
},
|
|
866
|
+
// ── Database ────────────────────────────────────────────────────────
|
|
867
|
+
".duckdb": {
|
|
868
|
+
icon: "Database",
|
|
869
|
+
color: "text-yellow-600 dark:text-yellow-400",
|
|
870
|
+
label: "DuckDB",
|
|
871
|
+
category: "database",
|
|
872
|
+
viewer: "database",
|
|
873
|
+
queryable: true,
|
|
874
|
+
duckdbReadFn: null,
|
|
875
|
+
mimeType: "application/octet-stream"
|
|
876
|
+
},
|
|
877
|
+
".sqlite": {
|
|
878
|
+
icon: "Database",
|
|
879
|
+
color: "text-sky-600 dark:text-sky-400",
|
|
880
|
+
label: "SQLite",
|
|
881
|
+
category: "database",
|
|
882
|
+
viewer: "database",
|
|
883
|
+
queryable: false,
|
|
884
|
+
duckdbReadFn: null,
|
|
885
|
+
mimeType: "application/x-sqlite3"
|
|
886
|
+
},
|
|
887
|
+
".db": {
|
|
888
|
+
icon: "Database",
|
|
889
|
+
color: "text-amber-500 dark:text-amber-400",
|
|
890
|
+
label: "Database",
|
|
891
|
+
category: "database",
|
|
892
|
+
viewer: "database",
|
|
893
|
+
queryable: false,
|
|
894
|
+
duckdbReadFn: null,
|
|
895
|
+
mimeType: "application/octet-stream"
|
|
896
|
+
},
|
|
897
|
+
// ── 3D Models ───────────────────────────────────────────────────────
|
|
898
|
+
".glb": {
|
|
899
|
+
icon: "Box",
|
|
900
|
+
color: "text-violet-600 dark:text-violet-400",
|
|
901
|
+
label: "GLB Model",
|
|
902
|
+
category: "3d",
|
|
903
|
+
viewer: "3d",
|
|
904
|
+
queryable: false,
|
|
905
|
+
duckdbReadFn: null,
|
|
906
|
+
mimeType: "model/gltf-binary"
|
|
907
|
+
},
|
|
908
|
+
".gltf": {
|
|
909
|
+
icon: "Box",
|
|
910
|
+
color: "text-violet-600 dark:text-violet-400",
|
|
911
|
+
label: "glTF Model",
|
|
912
|
+
category: "3d",
|
|
913
|
+
viewer: "3d",
|
|
914
|
+
queryable: false,
|
|
915
|
+
duckdbReadFn: null,
|
|
916
|
+
mimeType: "model/gltf+json"
|
|
917
|
+
},
|
|
918
|
+
".obj": {
|
|
919
|
+
icon: "Box",
|
|
920
|
+
color: "text-violet-600 dark:text-violet-400",
|
|
921
|
+
label: "OBJ Model",
|
|
922
|
+
category: "3d",
|
|
923
|
+
viewer: "3d",
|
|
924
|
+
queryable: false,
|
|
925
|
+
duckdbReadFn: null,
|
|
926
|
+
mimeType: "text/plain"
|
|
927
|
+
},
|
|
928
|
+
".stl": {
|
|
929
|
+
icon: "Box",
|
|
930
|
+
color: "text-violet-600 dark:text-violet-400",
|
|
931
|
+
label: "STL Model",
|
|
932
|
+
category: "3d",
|
|
933
|
+
viewer: "3d",
|
|
934
|
+
queryable: false,
|
|
935
|
+
duckdbReadFn: null,
|
|
936
|
+
mimeType: "model/stl"
|
|
937
|
+
},
|
|
938
|
+
".fbx": {
|
|
939
|
+
icon: "Box",
|
|
940
|
+
color: "text-violet-600 dark:text-violet-400",
|
|
941
|
+
label: "FBX Model",
|
|
942
|
+
category: "3d",
|
|
943
|
+
viewer: "3d",
|
|
944
|
+
queryable: false,
|
|
945
|
+
duckdbReadFn: null,
|
|
946
|
+
mimeType: "application/octet-stream"
|
|
947
|
+
},
|
|
948
|
+
// ── Notebooks ───────────────────────────────────────────────────────
|
|
949
|
+
".ipynb": {
|
|
950
|
+
icon: "BookOpen",
|
|
951
|
+
color: "text-orange-600 dark:text-orange-400",
|
|
952
|
+
label: "Jupyter Notebook",
|
|
953
|
+
category: "code",
|
|
954
|
+
viewer: "notebook",
|
|
955
|
+
queryable: false,
|
|
956
|
+
duckdbReadFn: null,
|
|
957
|
+
mimeType: "application/x-ipynb+json"
|
|
958
|
+
},
|
|
959
|
+
// ── Special ─────────────────────────────────────────────────────────
|
|
960
|
+
".zarr": {
|
|
961
|
+
icon: "Layers",
|
|
962
|
+
color: "text-purple-500 dark:text-purple-400",
|
|
963
|
+
label: "Zarr",
|
|
964
|
+
category: "data",
|
|
965
|
+
viewer: "zarr",
|
|
966
|
+
queryable: false,
|
|
967
|
+
duckdbReadFn: null,
|
|
968
|
+
mimeType: "application/octet-stream"
|
|
969
|
+
},
|
|
970
|
+
".zr3": {
|
|
971
|
+
icon: "Layers",
|
|
972
|
+
color: "text-purple-500 dark:text-purple-400",
|
|
973
|
+
label: "Zarr",
|
|
974
|
+
category: "data",
|
|
975
|
+
viewer: "zarr",
|
|
976
|
+
queryable: false,
|
|
977
|
+
duckdbReadFn: null,
|
|
978
|
+
mimeType: "application/octet-stream"
|
|
979
|
+
},
|
|
980
|
+
// ── Point Cloud ─────────────────────────────────────────────────────
|
|
981
|
+
".laz": {
|
|
982
|
+
icon: "Orbit",
|
|
983
|
+
color: "text-cyan-600 dark:text-cyan-400",
|
|
984
|
+
label: "COPC / LAZ",
|
|
985
|
+
category: "geo",
|
|
986
|
+
viewer: "copc",
|
|
987
|
+
queryable: false,
|
|
988
|
+
duckdbReadFn: null,
|
|
989
|
+
mimeType: "application/octet-stream"
|
|
990
|
+
},
|
|
991
|
+
".las": {
|
|
992
|
+
icon: "Orbit",
|
|
993
|
+
color: "text-cyan-600 dark:text-cyan-400",
|
|
994
|
+
label: "LAS Point Cloud",
|
|
995
|
+
category: "geo",
|
|
996
|
+
viewer: "copc",
|
|
997
|
+
queryable: false,
|
|
998
|
+
duckdbReadFn: null,
|
|
999
|
+
mimeType: "application/octet-stream"
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
function getFileTypeInfo(extension, isDir = false) {
|
|
1003
|
+
if (isDir) return FOLDER_INFO;
|
|
1004
|
+
const ext = extension.startsWith(".") ? extension.toLowerCase() : `.${extension.toLowerCase()}`;
|
|
1005
|
+
return EXTENSIONS[ext] ?? DEFAULT_INFO;
|
|
1006
|
+
}
|
|
1007
|
+
function getDuckDbReadFn(pathOrExt) {
|
|
1008
|
+
const ext = pathOrExt.includes(".") ? `.${pathOrExt.split(".").pop().toLowerCase()}` : "";
|
|
1009
|
+
return EXTENSIONS[ext]?.duckdbReadFn ?? "read_parquet";
|
|
1010
|
+
}
|
|
1011
|
+
function buildDuckDbSource(pathOrExt, url) {
|
|
1012
|
+
const ext = pathOrExt.includes(".") ? `.${pathOrExt.split(".").pop().toLowerCase()}` : "";
|
|
1013
|
+
if (ext === ".geojson") {
|
|
1014
|
+
return `(SELECT unnest(feature.properties), to_json(feature.geometry)::VARCHAR AS geometry FROM (SELECT unnest(features) AS feature FROM read_json_auto('${url}', maximum_object_size=1073741824, ignore_errors=true)))`;
|
|
1015
|
+
}
|
|
1016
|
+
const readFn = EXTENSIONS[ext]?.duckdbReadFn ?? "read_parquet";
|
|
1017
|
+
return `${readFn}('${url}')`;
|
|
1018
|
+
}
|
|
1019
|
+
var CLOUD_NATIVE_EXTS = /* @__PURE__ */ new Set([".parquet", ".geoparquet", ".gpq", ".gparquet"]);
|
|
1020
|
+
function isCloudNativeFormat(pathOrExt) {
|
|
1021
|
+
const ext = pathOrExt.includes(".") ? `.${pathOrExt.split(".").pop().toLowerCase()}` : "";
|
|
1022
|
+
return CLOUD_NATIVE_EXTS.has(ext);
|
|
1023
|
+
}
|
|
1024
|
+
function getViewerKind(extension) {
|
|
1025
|
+
return getFileTypeInfo(extension).viewer;
|
|
1026
|
+
}
|
|
1027
|
+
function isQueryable(extension) {
|
|
1028
|
+
return getFileTypeInfo(extension).queryable;
|
|
1029
|
+
}
|
|
1030
|
+
function getMimeType(extension) {
|
|
1031
|
+
return getFileTypeInfo(extension).mimeType;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// ../../src/lib/query/engine.ts
|
|
1035
|
+
var QueryCancelledError = class extends Error {
|
|
1036
|
+
constructor() {
|
|
1037
|
+
super("Query cancelled");
|
|
1038
|
+
this.name = "QueryCancelledError";
|
|
1039
|
+
}
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
// ../../src/lib/storage/url-adapter.ts
|
|
1043
|
+
var UrlAdapter = class {
|
|
1044
|
+
supportsWrite = false;
|
|
1045
|
+
async read(url, offset, length, signal) {
|
|
1046
|
+
const headers = {};
|
|
1047
|
+
if (offset !== void 0 && length !== void 0) {
|
|
1048
|
+
headers.Range = `bytes=${offset}-${offset + length - 1}`;
|
|
1049
|
+
} else if (offset !== void 0) {
|
|
1050
|
+
headers.Range = `bytes=${offset}-`;
|
|
1051
|
+
}
|
|
1052
|
+
const res = await fetch(url, { headers, signal });
|
|
1053
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
1054
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
1055
|
+
}
|
|
1056
|
+
async head(url, signal) {
|
|
1057
|
+
const res = await fetch(url, { method: "HEAD", signal });
|
|
1058
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
1059
|
+
const name = url.split("/").pop()?.split("?")[0] || "file";
|
|
1060
|
+
const ext = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
|
|
1061
|
+
return {
|
|
1062
|
+
name,
|
|
1063
|
+
path: url,
|
|
1064
|
+
is_dir: false,
|
|
1065
|
+
size: Number(res.headers.get("content-length") || 0),
|
|
1066
|
+
modified: new Date(res.headers.get("last-modified") || 0).getTime(),
|
|
1067
|
+
extension: ext
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
async list() {
|
|
1071
|
+
return [];
|
|
1072
|
+
}
|
|
1073
|
+
async put() {
|
|
1074
|
+
throw new Error("Write not supported for direct URL sources");
|
|
1075
|
+
}
|
|
1076
|
+
async delete() {
|
|
1077
|
+
throw new Error("Delete not supported for direct URL sources");
|
|
1078
|
+
}
|
|
1079
|
+
async deletePrefix() {
|
|
1080
|
+
throw new Error("Delete not supported for direct URL sources");
|
|
1081
|
+
}
|
|
1082
|
+
async copy() {
|
|
1083
|
+
throw new Error("Copy not supported for direct URL sources");
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
// ../../src/lib/utils/column-types.ts
|
|
1088
|
+
var NUMBER_TYPES = [
|
|
1089
|
+
"TINYINT",
|
|
1090
|
+
"SMALLINT",
|
|
1091
|
+
"INTEGER",
|
|
1092
|
+
"BIGINT",
|
|
1093
|
+
"HUGEINT",
|
|
1094
|
+
"UTINYINT",
|
|
1095
|
+
"USMALLINT",
|
|
1096
|
+
"UINTEGER",
|
|
1097
|
+
"UBIGINT",
|
|
1098
|
+
"FLOAT",
|
|
1099
|
+
"DOUBLE",
|
|
1100
|
+
"DECIMAL",
|
|
1101
|
+
"NUMERIC",
|
|
1102
|
+
"REAL",
|
|
1103
|
+
"INT",
|
|
1104
|
+
"INT1",
|
|
1105
|
+
"INT2",
|
|
1106
|
+
"INT4",
|
|
1107
|
+
"INT8",
|
|
1108
|
+
"SIGNED",
|
|
1109
|
+
"SHORT",
|
|
1110
|
+
"LONG"
|
|
1111
|
+
];
|
|
1112
|
+
var STRING_TYPES = ["VARCHAR", "TEXT", "STRING", "CHAR", "BPCHAR", "NAME", "UUID", "ENUM"];
|
|
1113
|
+
var DATE_TYPES = [
|
|
1114
|
+
"DATE",
|
|
1115
|
+
"TIME",
|
|
1116
|
+
"TIMESTAMP",
|
|
1117
|
+
"TIMESTAMP_S",
|
|
1118
|
+
"TIMESTAMP_MS",
|
|
1119
|
+
"TIMESTAMP_NS",
|
|
1120
|
+
"TIMESTAMP WITH TIME ZONE",
|
|
1121
|
+
"TIMESTAMPTZ",
|
|
1122
|
+
"INTERVAL",
|
|
1123
|
+
"TIMESTAMP_TZ"
|
|
1124
|
+
];
|
|
1125
|
+
var BOOLEAN_TYPES = ["BOOLEAN", "BOOL", "LOGICAL"];
|
|
1126
|
+
var GEO_TYPES = [
|
|
1127
|
+
"GEOMETRY",
|
|
1128
|
+
"POINT",
|
|
1129
|
+
"LINESTRING",
|
|
1130
|
+
"POLYGON",
|
|
1131
|
+
"MULTIPOINT",
|
|
1132
|
+
"MULTILINESTRING",
|
|
1133
|
+
"MULTIPOLYGON",
|
|
1134
|
+
"GEOMETRYCOLLECTION",
|
|
1135
|
+
"WKB_GEOMETRY"
|
|
1136
|
+
];
|
|
1137
|
+
var BINARY_TYPES = ["BLOB", "BYTEA", "BINARY", "VARBINARY"];
|
|
1138
|
+
var JSON_TYPES = ["JSON", "JSONB"];
|
|
1139
|
+
function classifyType(duckdbType) {
|
|
1140
|
+
const upper = duckdbType.toUpperCase().trim();
|
|
1141
|
+
const base = upper.replace(/\(.*\)/, "").trim();
|
|
1142
|
+
if (NUMBER_TYPES.includes(base)) return "number";
|
|
1143
|
+
if (STRING_TYPES.includes(base)) return "string";
|
|
1144
|
+
if (DATE_TYPES.includes(base)) return "date";
|
|
1145
|
+
if (BOOLEAN_TYPES.includes(base)) return "boolean";
|
|
1146
|
+
if (GEO_TYPES.includes(base)) return "geo";
|
|
1147
|
+
if (BINARY_TYPES.includes(base)) return "binary";
|
|
1148
|
+
if (JSON_TYPES.includes(base)) return "json";
|
|
1149
|
+
if (base.startsWith("STRUCT") || base.startsWith("MAP") || base.startsWith("UNION"))
|
|
1150
|
+
return "json";
|
|
1151
|
+
if (base.endsWith("[]") || base.startsWith("LIST")) return "json";
|
|
1152
|
+
if (upper.includes("INT") || upper.includes("FLOAT") || upper.includes("DOUBLE") || upper.includes("DECIMAL") || upper.includes("NUMERIC"))
|
|
1153
|
+
return "number";
|
|
1154
|
+
if (upper.includes("CHAR") || upper.includes("TEXT") || upper.includes("STRING")) return "string";
|
|
1155
|
+
if (upper.includes("TIME") || upper.includes("DATE")) return "date";
|
|
1156
|
+
if (upper.includes("BOOL")) return "boolean";
|
|
1157
|
+
if (upper.includes("GEOMETRY") || upper.includes("GEO") || upper.includes("WKB")) return "geo";
|
|
1158
|
+
if (upper.includes("BLOB") || upper.includes("BINARY")) return "binary";
|
|
1159
|
+
if (upper.includes("JSON") || upper.includes("STRUCT") || upper.includes("MAP") || upper.includes("LIST"))
|
|
1160
|
+
return "json";
|
|
1161
|
+
return "other";
|
|
1162
|
+
}
|
|
1163
|
+
var TYPE_COLORS = {
|
|
1164
|
+
number: "text-blue-500",
|
|
1165
|
+
string: "text-green-500",
|
|
1166
|
+
date: "text-amber-500",
|
|
1167
|
+
boolean: "text-purple-500",
|
|
1168
|
+
geo: "text-teal-500",
|
|
1169
|
+
binary: "text-zinc-500",
|
|
1170
|
+
json: "text-orange-500",
|
|
1171
|
+
other: "text-zinc-400"
|
|
1172
|
+
};
|
|
1173
|
+
var TYPE_BADGE_CLASSES = {
|
|
1174
|
+
number: "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20",
|
|
1175
|
+
string: "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20",
|
|
1176
|
+
date: "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20",
|
|
1177
|
+
boolean: "bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20",
|
|
1178
|
+
geo: "bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20",
|
|
1179
|
+
binary: "bg-zinc-500/10 text-zinc-600 dark:text-zinc-400 border-zinc-500/20",
|
|
1180
|
+
json: "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20",
|
|
1181
|
+
other: "bg-zinc-500/10 text-zinc-500 dark:text-zinc-400 border-zinc-500/20"
|
|
1182
|
+
};
|
|
1183
|
+
var TYPE_LABELS = {
|
|
1184
|
+
number: "#",
|
|
1185
|
+
string: "Aa",
|
|
1186
|
+
date: "dt",
|
|
1187
|
+
boolean: "T/F",
|
|
1188
|
+
geo: "geo",
|
|
1189
|
+
binary: "01",
|
|
1190
|
+
json: "{}",
|
|
1191
|
+
other: "?"
|
|
1192
|
+
};
|
|
1193
|
+
function typeColor(category) {
|
|
1194
|
+
return TYPE_COLORS[category];
|
|
1195
|
+
}
|
|
1196
|
+
function typeBadgeClass(category) {
|
|
1197
|
+
return TYPE_BADGE_CLASSES[category];
|
|
1198
|
+
}
|
|
1199
|
+
function typeLabel(category) {
|
|
1200
|
+
return TYPE_LABELS[category];
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// ../../src/lib/utils/format.ts
|
|
1204
|
+
function formatFileSize(bytes) {
|
|
1205
|
+
if (bytes < 0) return "0 B";
|
|
1206
|
+
if (bytes === 0) return "0 B";
|
|
1207
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
1208
|
+
const base = 1024;
|
|
1209
|
+
const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(base)), units.length - 1);
|
|
1210
|
+
const value = bytes / base ** exponent;
|
|
1211
|
+
if (exponent === 0) return `${bytes} B`;
|
|
1212
|
+
return `${value.toFixed(1)} ${units[exponent]}`;
|
|
1213
|
+
}
|
|
1214
|
+
function formatDate(timestamp) {
|
|
1215
|
+
if (!timestamp || timestamp <= 0 || !Number.isFinite(timestamp)) return "--";
|
|
1216
|
+
const date = new Date(timestamp);
|
|
1217
|
+
const now = Date.now();
|
|
1218
|
+
const diffMs = now - timestamp;
|
|
1219
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
1220
|
+
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
1221
|
+
const diffHours = Math.floor(diffMinutes / 60);
|
|
1222
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
1223
|
+
if (diffSeconds < 60) return "Just now";
|
|
1224
|
+
if (diffMinutes < 60) return `${diffMinutes}m ago`;
|
|
1225
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
1226
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
1227
|
+
return date.toLocaleDateString(void 0, {
|
|
1228
|
+
year: "numeric",
|
|
1229
|
+
month: "short",
|
|
1230
|
+
day: "numeric"
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
function getFileExtension(filename) {
|
|
1234
|
+
const lastDot = filename.lastIndexOf(".");
|
|
1235
|
+
if (lastDot <= 0) return "";
|
|
1236
|
+
return filename.slice(lastDot).toLowerCase();
|
|
1237
|
+
}
|
|
1238
|
+
function normalizeGeomType(raw) {
|
|
1239
|
+
const s = raw.toUpperCase().replace(/\s+/g, "");
|
|
1240
|
+
if (s === "POINT") return "point";
|
|
1241
|
+
if (s === "LINESTRING") return "linestring";
|
|
1242
|
+
if (s === "POLYGON") return "polygon";
|
|
1243
|
+
if (s === "MULTIPOINT") return "multipoint";
|
|
1244
|
+
if (s === "MULTILINESTRING") return "multilinestring";
|
|
1245
|
+
if (s === "MULTIPOLYGON") return "multipolygon";
|
|
1246
|
+
return "polygon";
|
|
1247
|
+
}
|
|
1248
|
+
var EXTENSION_NAMES = {
|
|
1249
|
+
point: "geoarrow.point",
|
|
1250
|
+
linestring: "geoarrow.linestring",
|
|
1251
|
+
polygon: "geoarrow.polygon",
|
|
1252
|
+
multipoint: "geoarrow.multipoint",
|
|
1253
|
+
multilinestring: "geoarrow.multilinestring",
|
|
1254
|
+
multipolygon: "geoarrow.multipolygon"
|
|
1255
|
+
};
|
|
1256
|
+
function readWkbHeader(wkb) {
|
|
1257
|
+
if (wkb.length < 5) return null;
|
|
1258
|
+
const le = wkb[0] === 1;
|
|
1259
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1260
|
+
const rawType = dv.getUint32(1, le);
|
|
1261
|
+
let headerSize = 5;
|
|
1262
|
+
if ((rawType & 536870912) !== 0) headerSize += 4;
|
|
1263
|
+
const ewkbZ = (rawType & 2147483648) !== 0;
|
|
1264
|
+
const ewkbM = (rawType & 1073741824) !== 0;
|
|
1265
|
+
let type = rawType & 268435455;
|
|
1266
|
+
let isoZ = false;
|
|
1267
|
+
let isoM = false;
|
|
1268
|
+
if (type > 3e3) {
|
|
1269
|
+
isoZ = true;
|
|
1270
|
+
isoM = true;
|
|
1271
|
+
type -= 3e3;
|
|
1272
|
+
} else if (type > 2e3) {
|
|
1273
|
+
isoM = true;
|
|
1274
|
+
type -= 2e3;
|
|
1275
|
+
} else if (type > 1e3) {
|
|
1276
|
+
isoZ = true;
|
|
1277
|
+
type -= 1e3;
|
|
1278
|
+
}
|
|
1279
|
+
const dims = (ewkbZ || isoZ ? 1 : 0) + (ewkbM || isoM ? 1 : 0);
|
|
1280
|
+
const coordStride = (2 + dims) * 8;
|
|
1281
|
+
return { type, le, coordStride, dataOffset: headerSize };
|
|
1282
|
+
}
|
|
1283
|
+
function classifyWkbType(wkb) {
|
|
1284
|
+
const h = readWkbHeader(wkb);
|
|
1285
|
+
if (!h) return null;
|
|
1286
|
+
switch (h.type) {
|
|
1287
|
+
case 1:
|
|
1288
|
+
return "point";
|
|
1289
|
+
case 2:
|
|
1290
|
+
return "linestring";
|
|
1291
|
+
case 3:
|
|
1292
|
+
return "polygon";
|
|
1293
|
+
case 4:
|
|
1294
|
+
return "multipoint";
|
|
1295
|
+
case 5:
|
|
1296
|
+
return "multilinestring";
|
|
1297
|
+
case 6:
|
|
1298
|
+
return "multipolygon";
|
|
1299
|
+
default:
|
|
1300
|
+
return null;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function newBounds() {
|
|
1304
|
+
return { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
|
|
1305
|
+
}
|
|
1306
|
+
function expandBounds(b, x, y) {
|
|
1307
|
+
if (Number.isNaN(x) || Number.isNaN(y)) return;
|
|
1308
|
+
if (x < b.minX) b.minX = x;
|
|
1309
|
+
if (y < b.minY) b.minY = y;
|
|
1310
|
+
if (x > b.maxX) b.maxX = x;
|
|
1311
|
+
if (y > b.maxY) b.maxY = y;
|
|
1312
|
+
}
|
|
1313
|
+
var coordField = new apacheArrow.Field("xy", new apacheArrow.Float64());
|
|
1314
|
+
var coordType = new apacheArrow.FixedSizeList(2, coordField);
|
|
1315
|
+
function makeCoordData(coords, numPoints) {
|
|
1316
|
+
const floatData = apacheArrow.makeData({ type: new apacheArrow.Float64(), length: coords.length, data: coords });
|
|
1317
|
+
return apacheArrow.makeData({ type: coordType, length: numPoints, nullCount: 0, child: floatData });
|
|
1318
|
+
}
|
|
1319
|
+
function buildPointData(wkbs, b) {
|
|
1320
|
+
const n = wkbs.length;
|
|
1321
|
+
const coords = new Float64Array(n * 2);
|
|
1322
|
+
for (let i = 0; i < n; i++) {
|
|
1323
|
+
const wkb = wkbs[i];
|
|
1324
|
+
const h = readWkbHeader(wkb);
|
|
1325
|
+
if (!h || h.type !== 1) {
|
|
1326
|
+
coords[i * 2] = 0;
|
|
1327
|
+
coords[i * 2 + 1] = 0;
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1331
|
+
const x = dv.getFloat64(h.dataOffset, h.le);
|
|
1332
|
+
const y = dv.getFloat64(h.dataOffset + 8, h.le);
|
|
1333
|
+
coords[i * 2] = x;
|
|
1334
|
+
coords[i * 2 + 1] = y;
|
|
1335
|
+
expandBounds(b, x, y);
|
|
1336
|
+
}
|
|
1337
|
+
return makeCoordData(coords, n);
|
|
1338
|
+
}
|
|
1339
|
+
function buildLineStringData(wkbs, b) {
|
|
1340
|
+
const n = wkbs.length;
|
|
1341
|
+
const geomOffsets = new Int32Array(n + 1);
|
|
1342
|
+
let totalCoords = 0;
|
|
1343
|
+
for (let i = 0; i < n; i++) {
|
|
1344
|
+
geomOffsets[i] = totalCoords;
|
|
1345
|
+
const h = readWkbHeader(wkbs[i]);
|
|
1346
|
+
if (!h || h.type !== 2) continue;
|
|
1347
|
+
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1348
|
+
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1349
|
+
totalCoords += numPts;
|
|
1350
|
+
}
|
|
1351
|
+
geomOffsets[n] = totalCoords;
|
|
1352
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1353
|
+
let ci = 0;
|
|
1354
|
+
for (const wkb of wkbs) {
|
|
1355
|
+
const h = readWkbHeader(wkb);
|
|
1356
|
+
if (!h || h.type !== 2) continue;
|
|
1357
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1358
|
+
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1359
|
+
let off = h.dataOffset + 4;
|
|
1360
|
+
for (let j = 0; j < numPts; j++) {
|
|
1361
|
+
const x = dv.getFloat64(off, h.le);
|
|
1362
|
+
const y = dv.getFloat64(off + 8, h.le);
|
|
1363
|
+
coords[ci++] = x;
|
|
1364
|
+
coords[ci++] = y;
|
|
1365
|
+
expandBounds(b, x, y);
|
|
1366
|
+
off += h.coordStride;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
const fslData = makeCoordData(coords, totalCoords);
|
|
1370
|
+
const listType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1371
|
+
return apacheArrow.makeData({
|
|
1372
|
+
type: listType,
|
|
1373
|
+
length: n,
|
|
1374
|
+
nullCount: 0,
|
|
1375
|
+
valueOffsets: geomOffsets,
|
|
1376
|
+
child: fslData
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
function buildPolygonData(wkbs, b) {
|
|
1380
|
+
const n = wkbs.length;
|
|
1381
|
+
const geomOffsets = new Int32Array(n + 1);
|
|
1382
|
+
let totalRings = 0;
|
|
1383
|
+
let totalCoords = 0;
|
|
1384
|
+
for (let i = 0; i < n; i++) {
|
|
1385
|
+
geomOffsets[i] = totalRings;
|
|
1386
|
+
const h = readWkbHeader(wkbs[i]);
|
|
1387
|
+
if (!h || h.type !== 3) continue;
|
|
1388
|
+
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1389
|
+
const numRings = dv.getUint32(h.dataOffset, h.le);
|
|
1390
|
+
let off = h.dataOffset + 4;
|
|
1391
|
+
for (let r = 0; r < numRings; r++) {
|
|
1392
|
+
const numPts = dv.getUint32(off, h.le);
|
|
1393
|
+
off += 4 + numPts * h.coordStride;
|
|
1394
|
+
totalCoords += numPts;
|
|
1395
|
+
totalRings++;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
geomOffsets[n] = totalRings;
|
|
1399
|
+
const ringOffsets = new Int32Array(totalRings + 1);
|
|
1400
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1401
|
+
let ri = 0;
|
|
1402
|
+
let ci = 0;
|
|
1403
|
+
for (const wkb of wkbs) {
|
|
1404
|
+
const h = readWkbHeader(wkb);
|
|
1405
|
+
if (!h || h.type !== 3) continue;
|
|
1406
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1407
|
+
const numRings = dv.getUint32(h.dataOffset, h.le);
|
|
1408
|
+
let off = h.dataOffset + 4;
|
|
1409
|
+
for (let r = 0; r < numRings; r++) {
|
|
1410
|
+
ringOffsets[ri++] = ci >> 1;
|
|
1411
|
+
const numPts = dv.getUint32(off, h.le);
|
|
1412
|
+
off += 4;
|
|
1413
|
+
for (let j = 0; j < numPts; j++) {
|
|
1414
|
+
const x = dv.getFloat64(off, h.le);
|
|
1415
|
+
const y = dv.getFloat64(off + 8, h.le);
|
|
1416
|
+
coords[ci++] = x;
|
|
1417
|
+
coords[ci++] = y;
|
|
1418
|
+
expandBounds(b, x, y);
|
|
1419
|
+
off += h.coordStride;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
ringOffsets[totalRings] = ci >> 1;
|
|
1424
|
+
const coordCount = ci >> 1;
|
|
1425
|
+
const fslData = makeCoordData(coords, coordCount);
|
|
1426
|
+
const ringListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1427
|
+
const ringListData = apacheArrow.makeData({
|
|
1428
|
+
type: ringListType,
|
|
1429
|
+
length: totalRings,
|
|
1430
|
+
nullCount: 0,
|
|
1431
|
+
valueOffsets: ringOffsets,
|
|
1432
|
+
child: fslData
|
|
1433
|
+
});
|
|
1434
|
+
const polyType = new apacheArrow.List(new apacheArrow.Field("rings", ringListType));
|
|
1435
|
+
return apacheArrow.makeData({
|
|
1436
|
+
type: polyType,
|
|
1437
|
+
length: n,
|
|
1438
|
+
nullCount: 0,
|
|
1439
|
+
valueOffsets: geomOffsets,
|
|
1440
|
+
child: ringListData
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
function buildMultiPointData(wkbs, b) {
|
|
1444
|
+
const n = wkbs.length;
|
|
1445
|
+
const geomOffsets = new Int32Array(n + 1);
|
|
1446
|
+
let totalCoords = 0;
|
|
1447
|
+
for (let i = 0; i < n; i++) {
|
|
1448
|
+
geomOffsets[i] = totalCoords;
|
|
1449
|
+
const h = readWkbHeader(wkbs[i]);
|
|
1450
|
+
if (!h || h.type !== 4) continue;
|
|
1451
|
+
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1452
|
+
totalCoords += dv.getUint32(h.dataOffset, h.le);
|
|
1453
|
+
}
|
|
1454
|
+
geomOffsets[n] = totalCoords;
|
|
1455
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1456
|
+
let ci = 0;
|
|
1457
|
+
for (const wkb of wkbs) {
|
|
1458
|
+
const h = readWkbHeader(wkb);
|
|
1459
|
+
if (!h || h.type !== 4) continue;
|
|
1460
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1461
|
+
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1462
|
+
let off = h.dataOffset + 4;
|
|
1463
|
+
for (let j = 0; j < numPts; j++) {
|
|
1464
|
+
const innerH = readWkbHeader(
|
|
1465
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1466
|
+
);
|
|
1467
|
+
if (innerH) {
|
|
1468
|
+
const x = dv.getFloat64(off + innerH.dataOffset, innerH.le);
|
|
1469
|
+
const y = dv.getFloat64(off + innerH.dataOffset + 8, innerH.le);
|
|
1470
|
+
coords[ci++] = x;
|
|
1471
|
+
coords[ci++] = y;
|
|
1472
|
+
expandBounds(b, x, y);
|
|
1473
|
+
off += innerH.dataOffset + innerH.coordStride;
|
|
1474
|
+
} else {
|
|
1475
|
+
coords[ci++] = 0;
|
|
1476
|
+
coords[ci++] = 0;
|
|
1477
|
+
off += 21;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
const fslData = makeCoordData(coords, totalCoords);
|
|
1482
|
+
const listType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1483
|
+
return apacheArrow.makeData({
|
|
1484
|
+
type: listType,
|
|
1485
|
+
length: n,
|
|
1486
|
+
nullCount: 0,
|
|
1487
|
+
valueOffsets: geomOffsets,
|
|
1488
|
+
child: fslData
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
function buildMultiLineStringData(wkbs, b) {
|
|
1492
|
+
const n = wkbs.length;
|
|
1493
|
+
const geomOffsetsArr = [0];
|
|
1494
|
+
let totalLines = 0;
|
|
1495
|
+
let totalCoords = 0;
|
|
1496
|
+
for (const wkb of wkbs) {
|
|
1497
|
+
const h = readWkbHeader(wkb);
|
|
1498
|
+
if (!h || h.type !== 5) {
|
|
1499
|
+
geomOffsetsArr.push(totalLines);
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1502
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1503
|
+
const numLines = dv.getUint32(h.dataOffset, h.le);
|
|
1504
|
+
let off = h.dataOffset + 4;
|
|
1505
|
+
for (let l = 0; l < numLines; l++) {
|
|
1506
|
+
const innerH = readWkbHeader(
|
|
1507
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1508
|
+
);
|
|
1509
|
+
if (!innerH) break;
|
|
1510
|
+
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1511
|
+
const numPts = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1512
|
+
totalCoords += numPts;
|
|
1513
|
+
off += innerH.dataOffset + 4 + numPts * innerH.coordStride;
|
|
1514
|
+
totalLines++;
|
|
1515
|
+
}
|
|
1516
|
+
geomOffsetsArr.push(totalLines);
|
|
1517
|
+
}
|
|
1518
|
+
const geomOffsets = new Int32Array(geomOffsetsArr);
|
|
1519
|
+
const lineOffsets = new Int32Array(totalLines + 1);
|
|
1520
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1521
|
+
let li = 0;
|
|
1522
|
+
let ci = 0;
|
|
1523
|
+
for (const wkb of wkbs) {
|
|
1524
|
+
const h = readWkbHeader(wkb);
|
|
1525
|
+
if (!h || h.type !== 5) continue;
|
|
1526
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1527
|
+
const numLines = dv.getUint32(h.dataOffset, h.le);
|
|
1528
|
+
let off = h.dataOffset + 4;
|
|
1529
|
+
for (let l = 0; l < numLines; l++) {
|
|
1530
|
+
lineOffsets[li++] = ci >> 1;
|
|
1531
|
+
const innerH = readWkbHeader(
|
|
1532
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1533
|
+
);
|
|
1534
|
+
if (!innerH) break;
|
|
1535
|
+
const numPts = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off).getUint32(
|
|
1536
|
+
innerH.dataOffset,
|
|
1537
|
+
innerH.le
|
|
1538
|
+
);
|
|
1539
|
+
let ptOff = off + innerH.dataOffset + 4;
|
|
1540
|
+
for (let j = 0; j < numPts; j++) {
|
|
1541
|
+
const x = dv.getFloat64(ptOff, innerH.le);
|
|
1542
|
+
const y = dv.getFloat64(ptOff + 8, innerH.le);
|
|
1543
|
+
coords[ci++] = x;
|
|
1544
|
+
coords[ci++] = y;
|
|
1545
|
+
expandBounds(b, x, y);
|
|
1546
|
+
ptOff += innerH.coordStride;
|
|
1547
|
+
}
|
|
1548
|
+
off = ptOff;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
lineOffsets[totalLines] = ci >> 1;
|
|
1552
|
+
const fslData = makeCoordData(coords, ci >> 1);
|
|
1553
|
+
const lineListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1554
|
+
const lineListData = apacheArrow.makeData({
|
|
1555
|
+
type: lineListType,
|
|
1556
|
+
length: totalLines,
|
|
1557
|
+
nullCount: 0,
|
|
1558
|
+
valueOffsets: lineOffsets,
|
|
1559
|
+
child: fslData
|
|
1560
|
+
});
|
|
1561
|
+
const multiLineType = new apacheArrow.List(new apacheArrow.Field("lines", lineListType));
|
|
1562
|
+
return apacheArrow.makeData({
|
|
1563
|
+
type: multiLineType,
|
|
1564
|
+
length: n,
|
|
1565
|
+
nullCount: 0,
|
|
1566
|
+
valueOffsets: geomOffsets,
|
|
1567
|
+
child: lineListData
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
function buildMultiPolygonData(wkbs, b) {
|
|
1571
|
+
const n = wkbs.length;
|
|
1572
|
+
const geomOffsetsArr = [0];
|
|
1573
|
+
let totalPolys = 0;
|
|
1574
|
+
let totalRings = 0;
|
|
1575
|
+
let totalCoords = 0;
|
|
1576
|
+
for (const wkb of wkbs) {
|
|
1577
|
+
const h = readWkbHeader(wkb);
|
|
1578
|
+
if (!h || h.type !== 6) {
|
|
1579
|
+
geomOffsetsArr.push(totalPolys);
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1583
|
+
const numPolys = dv.getUint32(h.dataOffset, h.le);
|
|
1584
|
+
let off = h.dataOffset + 4;
|
|
1585
|
+
for (let p = 0; p < numPolys; p++) {
|
|
1586
|
+
const innerH = readWkbHeader(
|
|
1587
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1588
|
+
);
|
|
1589
|
+
if (!innerH) break;
|
|
1590
|
+
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1591
|
+
const numRings = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1592
|
+
let ringOff = innerH.dataOffset + 4;
|
|
1593
|
+
for (let r = 0; r < numRings; r++) {
|
|
1594
|
+
const numPts = innerDv.getUint32(ringOff, innerH.le);
|
|
1595
|
+
ringOff += 4 + numPts * innerH.coordStride;
|
|
1596
|
+
totalCoords += numPts;
|
|
1597
|
+
totalRings++;
|
|
1598
|
+
}
|
|
1599
|
+
off += ringOff;
|
|
1600
|
+
totalPolys++;
|
|
1601
|
+
}
|
|
1602
|
+
geomOffsetsArr.push(totalPolys);
|
|
1603
|
+
}
|
|
1604
|
+
const geomOffsets = new Int32Array(geomOffsetsArr);
|
|
1605
|
+
const polyOffsets = new Int32Array(totalPolys + 1);
|
|
1606
|
+
const ringOffsets = new Int32Array(totalRings + 1);
|
|
1607
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1608
|
+
let pi = 0;
|
|
1609
|
+
let ri = 0;
|
|
1610
|
+
let ci = 0;
|
|
1611
|
+
for (const wkb of wkbs) {
|
|
1612
|
+
const h = readWkbHeader(wkb);
|
|
1613
|
+
if (!h || h.type !== 6) continue;
|
|
1614
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1615
|
+
const numPolys = dv.getUint32(h.dataOffset, h.le);
|
|
1616
|
+
let off = h.dataOffset + 4;
|
|
1617
|
+
for (let p = 0; p < numPolys; p++) {
|
|
1618
|
+
polyOffsets[pi++] = ri;
|
|
1619
|
+
const innerH = readWkbHeader(
|
|
1620
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1621
|
+
);
|
|
1622
|
+
if (!innerH) break;
|
|
1623
|
+
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1624
|
+
const numRings = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1625
|
+
let ringOff = off + innerH.dataOffset + 4;
|
|
1626
|
+
for (let r = 0; r < numRings; r++) {
|
|
1627
|
+
ringOffsets[ri++] = ci >> 1;
|
|
1628
|
+
const numPts = dv.getUint32(ringOff, innerH.le);
|
|
1629
|
+
ringOff += 4;
|
|
1630
|
+
for (let j = 0; j < numPts; j++) {
|
|
1631
|
+
const x = dv.getFloat64(ringOff, innerH.le);
|
|
1632
|
+
const y = dv.getFloat64(ringOff + 8, innerH.le);
|
|
1633
|
+
coords[ci++] = x;
|
|
1634
|
+
coords[ci++] = y;
|
|
1635
|
+
expandBounds(b, x, y);
|
|
1636
|
+
ringOff += innerH.coordStride;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
off = ringOff;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
polyOffsets[totalPolys] = ri;
|
|
1643
|
+
ringOffsets[totalRings] = ci >> 1;
|
|
1644
|
+
const fslData = makeCoordData(coords, ci >> 1);
|
|
1645
|
+
const ringListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1646
|
+
const ringListData = apacheArrow.makeData({
|
|
1647
|
+
type: ringListType,
|
|
1648
|
+
length: totalRings,
|
|
1649
|
+
nullCount: 0,
|
|
1650
|
+
valueOffsets: ringOffsets,
|
|
1651
|
+
child: fslData
|
|
1652
|
+
});
|
|
1653
|
+
const polyListType = new apacheArrow.List(new apacheArrow.Field("rings", ringListType));
|
|
1654
|
+
const polyListData = apacheArrow.makeData({
|
|
1655
|
+
type: polyListType,
|
|
1656
|
+
length: totalPolys,
|
|
1657
|
+
nullCount: 0,
|
|
1658
|
+
valueOffsets: polyOffsets,
|
|
1659
|
+
child: ringListData
|
|
1660
|
+
});
|
|
1661
|
+
const multiPolyType = new apacheArrow.List(new apacheArrow.Field("polygons", polyListType));
|
|
1662
|
+
return apacheArrow.makeData({
|
|
1663
|
+
type: multiPolyType,
|
|
1664
|
+
length: n,
|
|
1665
|
+
nullCount: 0,
|
|
1666
|
+
valueOffsets: geomOffsets,
|
|
1667
|
+
child: polyListData
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1670
|
+
function buildAttributeColumns(indices, attributes) {
|
|
1671
|
+
const n = indices.length;
|
|
1672
|
+
const fields = [];
|
|
1673
|
+
const dataArr = [];
|
|
1674
|
+
for (const [name, col] of attributes) {
|
|
1675
|
+
const { values } = col;
|
|
1676
|
+
let isNumeric = true;
|
|
1677
|
+
const sampleEnd = Math.min(n, 100);
|
|
1678
|
+
for (let i = 0; i < sampleEnd; i++) {
|
|
1679
|
+
if (values[indices[i]] != null && typeof values[indices[i]] !== "number") {
|
|
1680
|
+
isNumeric = false;
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
if (isNumeric) {
|
|
1685
|
+
const arr = new Float64Array(n);
|
|
1686
|
+
for (let i = 0; i < n; i++) arr[i] = values[indices[i]] ?? NaN;
|
|
1687
|
+
const data = apacheArrow.makeData({ type: new apacheArrow.Float64(), length: n, data: arr });
|
|
1688
|
+
fields.push(new apacheArrow.Field(name, new apacheArrow.Float64(), true));
|
|
1689
|
+
dataArr.push(data);
|
|
1690
|
+
} else {
|
|
1691
|
+
const encoder = new TextEncoder();
|
|
1692
|
+
const offsets = new Int32Array(n + 1);
|
|
1693
|
+
let totalBytes = 0;
|
|
1694
|
+
const strParts = [];
|
|
1695
|
+
for (let i = 0; i < n; i++) {
|
|
1696
|
+
offsets[i] = totalBytes;
|
|
1697
|
+
const s = values[indices[i]] != null ? String(values[indices[i]]) : "";
|
|
1698
|
+
const encoded = encoder.encode(s);
|
|
1699
|
+
strParts.push(encoded);
|
|
1700
|
+
totalBytes += encoded.length;
|
|
1701
|
+
}
|
|
1702
|
+
offsets[n] = totalBytes;
|
|
1703
|
+
const valueBuffer = new Uint8Array(totalBytes);
|
|
1704
|
+
let pos = 0;
|
|
1705
|
+
for (const sv of strParts) {
|
|
1706
|
+
valueBuffer.set(sv, pos);
|
|
1707
|
+
pos += sv.length;
|
|
1708
|
+
}
|
|
1709
|
+
const data = apacheArrow.makeData({
|
|
1710
|
+
type: new apacheArrow.Utf8(),
|
|
1711
|
+
length: n,
|
|
1712
|
+
valueOffsets: offsets,
|
|
1713
|
+
data: valueBuffer
|
|
1714
|
+
});
|
|
1715
|
+
fields.push(new apacheArrow.Field(name, new apacheArrow.Utf8(), true));
|
|
1716
|
+
dataArr.push(data);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
return { fields, data: dataArr };
|
|
1720
|
+
}
|
|
1721
|
+
function buildSingleTable(geomType, wkbs, indices, attributes, b) {
|
|
1722
|
+
const n = wkbs.length;
|
|
1723
|
+
let geomData;
|
|
1724
|
+
switch (geomType) {
|
|
1725
|
+
case "point":
|
|
1726
|
+
geomData = buildPointData(wkbs, b);
|
|
1727
|
+
break;
|
|
1728
|
+
case "linestring":
|
|
1729
|
+
geomData = buildLineStringData(wkbs, b);
|
|
1730
|
+
break;
|
|
1731
|
+
case "polygon":
|
|
1732
|
+
geomData = buildPolygonData(wkbs, b);
|
|
1733
|
+
break;
|
|
1734
|
+
case "multipoint":
|
|
1735
|
+
geomData = buildMultiPointData(wkbs, b);
|
|
1736
|
+
break;
|
|
1737
|
+
case "multilinestring":
|
|
1738
|
+
geomData = buildMultiLineStringData(wkbs, b);
|
|
1739
|
+
break;
|
|
1740
|
+
case "multipolygon":
|
|
1741
|
+
geomData = buildMultiPolygonData(wkbs, b);
|
|
1742
|
+
break;
|
|
1743
|
+
}
|
|
1744
|
+
const extensionName = EXTENSION_NAMES[geomType];
|
|
1745
|
+
const geomMetadata = /* @__PURE__ */ new Map([
|
|
1746
|
+
["ARROW:extension:name", extensionName],
|
|
1747
|
+
[
|
|
1748
|
+
"ARROW:extension:metadata",
|
|
1749
|
+
JSON.stringify({
|
|
1750
|
+
crs: {
|
|
1751
|
+
type: "name",
|
|
1752
|
+
properties: { name: "urn:ogc:def:crs:OGC:1.3:CRS84" }
|
|
1753
|
+
}
|
|
1754
|
+
})
|
|
1755
|
+
]
|
|
1756
|
+
]);
|
|
1757
|
+
const geomField = new apacheArrow.Field("geometry", geomData.type, false, geomMetadata);
|
|
1758
|
+
const attrCols = buildAttributeColumns(indices, attributes);
|
|
1759
|
+
const fields = [geomField, ...attrCols.fields];
|
|
1760
|
+
const childrenData = [geomData, ...attrCols.data];
|
|
1761
|
+
const arrowSchema = new apacheArrow.Schema(fields);
|
|
1762
|
+
const structType = new apacheArrow.Struct(fields);
|
|
1763
|
+
const structData = apacheArrow.makeData({
|
|
1764
|
+
type: structType,
|
|
1765
|
+
length: n,
|
|
1766
|
+
nullCount: 0,
|
|
1767
|
+
children: childrenData
|
|
1768
|
+
});
|
|
1769
|
+
const batch = new apacheArrow.RecordBatch(arrowSchema, structData);
|
|
1770
|
+
const table = new apacheArrow.Table(arrowSchema, batch);
|
|
1771
|
+
return {
|
|
1772
|
+
table,
|
|
1773
|
+
geometryType: geomType,
|
|
1774
|
+
bounds: [b.minX, b.minY, b.maxX, b.maxY],
|
|
1775
|
+
sourceIndices: indices
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
function buildGeoArrowTables(wkbArrays, attributes, knownGeomType) {
|
|
1779
|
+
if (wkbArrays.length === 0) return [];
|
|
1780
|
+
if (knownGeomType) {
|
|
1781
|
+
const globalBounds2 = newBounds();
|
|
1782
|
+
const indices = Array.from({ length: wkbArrays.length }, (_, i) => i);
|
|
1783
|
+
const result = buildSingleTable(knownGeomType, wkbArrays, indices, attributes, globalBounds2);
|
|
1784
|
+
return [result];
|
|
1785
|
+
}
|
|
1786
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1787
|
+
for (let i = 0; i < wkbArrays.length; i++) {
|
|
1788
|
+
const geomType = classifyWkbType(wkbArrays[i]);
|
|
1789
|
+
if (!geomType) continue;
|
|
1790
|
+
let group = groups.get(geomType);
|
|
1791
|
+
if (!group) {
|
|
1792
|
+
group = { wkbs: [], indices: [] };
|
|
1793
|
+
groups.set(geomType, group);
|
|
1794
|
+
}
|
|
1795
|
+
group.wkbs.push(wkbArrays[i]);
|
|
1796
|
+
group.indices.push(i);
|
|
1797
|
+
}
|
|
1798
|
+
if (groups.size === 0) return [];
|
|
1799
|
+
const globalBounds = newBounds();
|
|
1800
|
+
const results = [];
|
|
1801
|
+
for (const [geomType, { wkbs, indices }] of groups) {
|
|
1802
|
+
const result = buildSingleTable(geomType, wkbs, indices, attributes, globalBounds);
|
|
1803
|
+
results.push(result);
|
|
1804
|
+
}
|
|
1805
|
+
const mergedBounds = [
|
|
1806
|
+
globalBounds.minX,
|
|
1807
|
+
globalBounds.minY,
|
|
1808
|
+
globalBounds.maxX,
|
|
1809
|
+
globalBounds.maxY
|
|
1810
|
+
];
|
|
1811
|
+
for (const r of results) r.bounds = mergedBounds;
|
|
1812
|
+
return results;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// ../../src/lib/utils/hex.ts
|
|
1816
|
+
function generateHexDump(data, bytesPerRow = 16) {
|
|
1817
|
+
const rows = [];
|
|
1818
|
+
for (let i = 0; i < data.length; i += bytesPerRow) {
|
|
1819
|
+
const slice = data.slice(i, i + bytesPerRow);
|
|
1820
|
+
const offset = i.toString(16).padStart(8, "0");
|
|
1821
|
+
const hex = [];
|
|
1822
|
+
for (let j = 0; j < bytesPerRow; j++) {
|
|
1823
|
+
if (j < slice.length) {
|
|
1824
|
+
hex.push(slice[j].toString(16).padStart(2, "0"));
|
|
1825
|
+
} else {
|
|
1826
|
+
hex.push(" ");
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
let ascii = "";
|
|
1830
|
+
for (let j = 0; j < slice.length; j++) {
|
|
1831
|
+
const byte = slice[j];
|
|
1832
|
+
ascii += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : ".";
|
|
1833
|
+
}
|
|
1834
|
+
rows.push({ offset, hex, ascii });
|
|
1835
|
+
}
|
|
1836
|
+
return rows;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// ../../src/lib/utils/parquet-metadata.ts
|
|
1840
|
+
var WGS84_CODES = /* @__PURE__ */ new Set([4326, 4979]);
|
|
1841
|
+
function mapParquetType(col) {
|
|
1842
|
+
const lt = col.logical_type;
|
|
1843
|
+
if (lt) {
|
|
1844
|
+
if (lt.type === "GEOMETRY" || lt.type === "GEOGRAPHY") return "GEOMETRY";
|
|
1845
|
+
if (lt.type === "STRING" || lt.type === "UTF8") return "VARCHAR";
|
|
1846
|
+
if (lt.type === "JSON") return "JSON";
|
|
1847
|
+
if (lt.type === "UUID") return "UUID";
|
|
1848
|
+
if (lt.type === "ENUM") return "VARCHAR";
|
|
1849
|
+
if (lt.type === "INT" || lt.type === "INTEGER") {
|
|
1850
|
+
const bits = lt.bitWidth ?? 32;
|
|
1851
|
+
const signed = lt.isSigned !== false;
|
|
1852
|
+
if (bits <= 8) return signed ? "TINYINT" : "UTINYINT";
|
|
1853
|
+
if (bits <= 16) return signed ? "SMALLINT" : "USMALLINT";
|
|
1854
|
+
if (bits <= 32) return signed ? "INTEGER" : "UINTEGER";
|
|
1855
|
+
return signed ? "BIGINT" : "UBIGINT";
|
|
1856
|
+
}
|
|
1857
|
+
if (lt.type === "DECIMAL") return `DECIMAL(${lt.precision ?? 18},${lt.scale ?? 0})`;
|
|
1858
|
+
if (lt.type === "DATE") return "DATE";
|
|
1859
|
+
if (lt.type === "TIME") return "TIME";
|
|
1860
|
+
if (lt.type === "TIMESTAMP") return "TIMESTAMP";
|
|
1861
|
+
if (lt.type === "BSON") return "BLOB";
|
|
1862
|
+
}
|
|
1863
|
+
const ct = col.converted_type;
|
|
1864
|
+
if (ct === "UTF8") return "VARCHAR";
|
|
1865
|
+
if (ct === "JSON") return "JSON";
|
|
1866
|
+
if (ct === "DATE") return "DATE";
|
|
1867
|
+
if (ct === "TIMESTAMP_MILLIS" || ct === "TIMESTAMP_MICROS") return "TIMESTAMP";
|
|
1868
|
+
if (ct === "DECIMAL") return `DECIMAL(${col.precision ?? 18},${col.scale ?? 0})`;
|
|
1869
|
+
if (ct === "INT_8") return "TINYINT";
|
|
1870
|
+
if (ct === "INT_16") return "SMALLINT";
|
|
1871
|
+
if (ct === "INT_32") return "INTEGER";
|
|
1872
|
+
if (ct === "INT_64") return "BIGINT";
|
|
1873
|
+
if (ct === "UINT_8") return "UTINYINT";
|
|
1874
|
+
if (ct === "UINT_16") return "USMALLINT";
|
|
1875
|
+
if (ct === "UINT_32") return "UINTEGER";
|
|
1876
|
+
if (ct === "UINT_64") return "UBIGINT";
|
|
1877
|
+
const pt = col.type;
|
|
1878
|
+
if (pt === "BOOLEAN") return "BOOLEAN";
|
|
1879
|
+
if (pt === "INT32") return "INTEGER";
|
|
1880
|
+
if (pt === "INT64") return "BIGINT";
|
|
1881
|
+
if (pt === "INT96") return "TIMESTAMP";
|
|
1882
|
+
if (pt === "FLOAT") return "FLOAT";
|
|
1883
|
+
if (pt === "DOUBLE") return "DOUBLE";
|
|
1884
|
+
if (pt === "BYTE_ARRAY") return "BLOB";
|
|
1885
|
+
if (pt === "FIXED_LEN_BYTE_ARRAY") return "BLOB";
|
|
1886
|
+
return "VARCHAR";
|
|
1887
|
+
}
|
|
1888
|
+
async function readParquetMetadata(url) {
|
|
1889
|
+
const { parquetMetadataAsync, asyncBufferFromUrl } = await import('hyparquet');
|
|
1890
|
+
const file = await asyncBufferFromUrl({ url });
|
|
1891
|
+
const metadata = await parquetMetadataAsync(file);
|
|
1892
|
+
const rowCount = metadata.row_groups.reduce(
|
|
1893
|
+
(sum, rg) => sum + Number(rg.num_rows),
|
|
1894
|
+
0
|
|
1895
|
+
);
|
|
1896
|
+
const schema = metadata.schema.slice(1).filter((col) => col.num_children === void 0).map((col) => ({
|
|
1897
|
+
name: col.name,
|
|
1898
|
+
type: mapParquetType(col)
|
|
1899
|
+
}));
|
|
1900
|
+
let geo = null;
|
|
1901
|
+
let legacyGeoParquet = false;
|
|
1902
|
+
const geoKv = metadata.key_value_metadata?.find((kv) => kv.key === "geo");
|
|
1903
|
+
if (geoKv) {
|
|
1904
|
+
try {
|
|
1905
|
+
const geoJson = JSON.parse(geoKv.value ?? "");
|
|
1906
|
+
if (geoJson.schema_version && !geoJson.version) {
|
|
1907
|
+
legacyGeoParquet = true;
|
|
1908
|
+
}
|
|
1909
|
+
geo = {
|
|
1910
|
+
primaryColumn: geoJson.primary_column ?? "geometry",
|
|
1911
|
+
columns: {}
|
|
1912
|
+
};
|
|
1913
|
+
if (geoJson.columns) {
|
|
1914
|
+
for (const [colName, colMeta] of Object.entries(geoJson.columns)) {
|
|
1915
|
+
geo.columns[colName] = {
|
|
1916
|
+
encoding: colMeta.encoding ?? "WKB",
|
|
1917
|
+
geometryTypes: colMeta.geometry_types ?? [],
|
|
1918
|
+
crs: colMeta.crs ?? null,
|
|
1919
|
+
bbox: colMeta.bbox
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
} catch {
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
const createdBy = metadata.created_by ?? null;
|
|
1927
|
+
const numRowGroups = metadata.row_groups.length;
|
|
1928
|
+
let compression = null;
|
|
1929
|
+
if (numRowGroups > 0 && metadata.row_groups[0].columns) {
|
|
1930
|
+
const codecs = /* @__PURE__ */ new Set();
|
|
1931
|
+
for (const col of metadata.row_groups[0].columns) {
|
|
1932
|
+
const codec = col.meta_data?.codec;
|
|
1933
|
+
if (codec) codecs.add(codec);
|
|
1934
|
+
}
|
|
1935
|
+
if (codecs.size === 1) {
|
|
1936
|
+
compression = [...codecs][0];
|
|
1937
|
+
} else if (codecs.size > 1) {
|
|
1938
|
+
compression = [...codecs].join(", ");
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
return { rowCount, schema, geo, legacyGeoParquet, createdBy, numRowGroups, compression };
|
|
1942
|
+
}
|
|
1943
|
+
function extractEpsgFromGeoMeta(geo) {
|
|
1944
|
+
const primaryCol = geo.columns[geo.primaryColumn];
|
|
1945
|
+
if (!primaryCol?.crs) return null;
|
|
1946
|
+
const crs = primaryCol.crs;
|
|
1947
|
+
if (crs.type === "name" && crs.properties?.name?.includes("CRS84")) return null;
|
|
1948
|
+
if (crs.id?.authority === "EPSG") {
|
|
1949
|
+
const code = crs.id.code;
|
|
1950
|
+
if (WGS84_CODES.has(code)) return null;
|
|
1951
|
+
return `EPSG:${code}`;
|
|
1952
|
+
}
|
|
1953
|
+
return null;
|
|
1954
|
+
}
|
|
1955
|
+
function extractGeometryTypes(geo) {
|
|
1956
|
+
const primaryCol = geo.columns[geo.primaryColumn];
|
|
1957
|
+
if (!primaryCol?.geometryTypes?.length) return [];
|
|
1958
|
+
const typeMap = {
|
|
1959
|
+
Point: "point",
|
|
1960
|
+
LineString: "linestring",
|
|
1961
|
+
Polygon: "polygon",
|
|
1962
|
+
MultiPoint: "multipoint",
|
|
1963
|
+
MultiLineString: "multilinestring",
|
|
1964
|
+
MultiPolygon: "multipolygon"
|
|
1965
|
+
};
|
|
1966
|
+
const types = [];
|
|
1967
|
+
for (const raw of primaryCol.geometryTypes) {
|
|
1968
|
+
const base = raw.split(" ")[0];
|
|
1969
|
+
const mapped = typeMap[base];
|
|
1970
|
+
if (mapped && !types.includes(mapped)) types.push(mapped);
|
|
1971
|
+
}
|
|
1972
|
+
return types;
|
|
1973
|
+
}
|
|
1974
|
+
function extractBounds(geo) {
|
|
1975
|
+
const primaryCol = geo.columns[geo.primaryColumn];
|
|
1976
|
+
if (!primaryCol?.bbox || primaryCol.bbox.length < 4) return null;
|
|
1977
|
+
return [primaryCol.bbox[0], primaryCol.bbox[1], primaryCol.bbox[2], primaryCol.bbox[3]];
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
// ../../src/lib/utils/storage-url.ts
|
|
1981
|
+
var SCHEME_MAP = {
|
|
1982
|
+
"s3://": { provider: "s3", strip: 5 },
|
|
1983
|
+
"s3a://": { provider: "s3", strip: 6 },
|
|
1984
|
+
"s3n://": { provider: "s3", strip: 6 },
|
|
1985
|
+
"aws://": { provider: "s3", strip: 6 },
|
|
1986
|
+
"r2://": { provider: "r2", strip: 5 },
|
|
1987
|
+
"gs://": { provider: "gcs", strip: 5 },
|
|
1988
|
+
"gcs://": { provider: "gcs", strip: 6 },
|
|
1989
|
+
"azure://": { provider: "azure", strip: 8 },
|
|
1990
|
+
"az://": { provider: "azure", strip: 5 },
|
|
1991
|
+
"abfs://": { provider: "azure", strip: 7 },
|
|
1992
|
+
"abfss://": { provider: "azure", strip: 8 },
|
|
1993
|
+
"wasbs://": { provider: "azure", strip: 8 },
|
|
1994
|
+
"adl://": { provider: "azure", strip: 6 },
|
|
1995
|
+
"storj://": { provider: "storj", strip: 8 },
|
|
1996
|
+
"sj://": { provider: "storj", strip: 5 },
|
|
1997
|
+
"swift://": { provider: "unknown", strip: 8 }
|
|
1998
|
+
};
|
|
1999
|
+
function defaultResult(defaults) {
|
|
2000
|
+
return {
|
|
2001
|
+
bucket: "",
|
|
2002
|
+
region: defaults.region || "us-east-1",
|
|
2003
|
+
endpoint: defaults.endpoint || "",
|
|
2004
|
+
provider: defaults.provider || "s3",
|
|
2005
|
+
prefix: ""
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
function splitBucketPrefix(rest) {
|
|
2009
|
+
const slashIdx = rest.indexOf("/");
|
|
2010
|
+
if (slashIdx >= 0) {
|
|
2011
|
+
return {
|
|
2012
|
+
bucket: rest.slice(0, slashIdx),
|
|
2013
|
+
prefix: rest.slice(slashIdx + 1).replace(/\/+$/, "")
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
return { bucket: rest, prefix: "" };
|
|
2017
|
+
}
|
|
2018
|
+
function parseStorageUrl(input, defaults = {}) {
|
|
2019
|
+
const trimmed = input.trim();
|
|
2020
|
+
const lower = trimmed.toLowerCase();
|
|
2021
|
+
for (const [scheme, { provider, strip }] of Object.entries(SCHEME_MAP)) {
|
|
2022
|
+
if (lower.startsWith(scheme)) {
|
|
2023
|
+
const rest = trimmed.slice(strip);
|
|
2024
|
+
const { bucket, prefix } = splitBucketPrefix(rest);
|
|
2025
|
+
return {
|
|
2026
|
+
bucket,
|
|
2027
|
+
region: defaults.region || "us-east-1",
|
|
2028
|
+
endpoint: defaults.endpoint || "",
|
|
2029
|
+
provider,
|
|
2030
|
+
prefix
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
if (lower.startsWith("http://") || lower.startsWith("https://")) {
|
|
2035
|
+
try {
|
|
2036
|
+
const url = new URL(trimmed);
|
|
2037
|
+
const host = url.hostname;
|
|
2038
|
+
const pathParts = url.pathname.replace(/^\//, "").split("/").filter(Boolean);
|
|
2039
|
+
const awsVhost = host.match(/^(.+)\.s3[.-]([a-z0-9-]+)\.amazonaws\.com$/);
|
|
2040
|
+
if (awsVhost) {
|
|
2041
|
+
return {
|
|
2042
|
+
bucket: awsVhost[1],
|
|
2043
|
+
region: awsVhost[2],
|
|
2044
|
+
endpoint: "",
|
|
2045
|
+
provider: "s3",
|
|
2046
|
+
prefix: pathParts.join("/")
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
const awsPath = host.match(/^s3[.-]([a-z0-9-]+)\.amazonaws\.com$/);
|
|
2050
|
+
if (awsPath && pathParts.length > 0) {
|
|
2051
|
+
return {
|
|
2052
|
+
bucket: pathParts[0],
|
|
2053
|
+
region: awsPath[1],
|
|
2054
|
+
endpoint: "",
|
|
2055
|
+
provider: "s3",
|
|
2056
|
+
prefix: pathParts.slice(1).join("/")
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
if (host === "s3.amazonaws.com" && pathParts.length > 0) {
|
|
2060
|
+
return {
|
|
2061
|
+
bucket: pathParts[0],
|
|
2062
|
+
region: defaults.region || "us-east-1",
|
|
2063
|
+
endpoint: "",
|
|
2064
|
+
provider: "s3",
|
|
2065
|
+
prefix: pathParts.slice(1).join("/")
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
const r2Match = host.match(/^([a-z0-9]+)\.r2\.cloudflarestorage\.com$/);
|
|
2069
|
+
if (r2Match && pathParts.length > 0) {
|
|
2070
|
+
return {
|
|
2071
|
+
bucket: pathParts[0],
|
|
2072
|
+
region: "auto",
|
|
2073
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2074
|
+
provider: "r2",
|
|
2075
|
+
prefix: pathParts.slice(1).join("/")
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
2078
|
+
if (host === "storage.googleapis.com" && pathParts.length > 0) {
|
|
2079
|
+
return {
|
|
2080
|
+
bucket: pathParts[0],
|
|
2081
|
+
region: defaults.region || "us",
|
|
2082
|
+
endpoint: "",
|
|
2083
|
+
provider: "gcs",
|
|
2084
|
+
prefix: pathParts.slice(1).join("/")
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
const gcsVhost = host.match(/^(.+)\.storage\.googleapis\.com$/);
|
|
2088
|
+
if (gcsVhost) {
|
|
2089
|
+
return {
|
|
2090
|
+
bucket: gcsVhost[1],
|
|
2091
|
+
region: defaults.region || "us",
|
|
2092
|
+
endpoint: "",
|
|
2093
|
+
provider: "gcs",
|
|
2094
|
+
prefix: pathParts.join("/")
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
const doVhost = host.match(/^(.+)\.([a-z0-9-]+)\.digitaloceanspaces\.com$/);
|
|
2098
|
+
if (doVhost) {
|
|
2099
|
+
return {
|
|
2100
|
+
bucket: doVhost[1],
|
|
2101
|
+
region: doVhost[2],
|
|
2102
|
+
endpoint: `${url.protocol}//${doVhost[2]}.digitaloceanspaces.com`,
|
|
2103
|
+
provider: "s3",
|
|
2104
|
+
prefix: pathParts.join("/")
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
const doPath = host.match(/^([a-z0-9-]+)\.digitaloceanspaces\.com$/);
|
|
2108
|
+
if (doPath && pathParts.length > 0) {
|
|
2109
|
+
return {
|
|
2110
|
+
bucket: pathParts[0],
|
|
2111
|
+
region: doPath[1],
|
|
2112
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2113
|
+
provider: "s3",
|
|
2114
|
+
prefix: pathParts.slice(1).join("/")
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
const wasabiMatch = host.match(/^s3\.([a-z0-9-]+)\.wasabisys\.com$/);
|
|
2118
|
+
if (wasabiMatch && pathParts.length > 0) {
|
|
2119
|
+
return {
|
|
2120
|
+
bucket: pathParts[0],
|
|
2121
|
+
region: wasabiMatch[1],
|
|
2122
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2123
|
+
provider: "s3",
|
|
2124
|
+
prefix: pathParts.slice(1).join("/")
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
const b2S3 = host.match(/^(.+)\.s3\.([a-z0-9-]+)\.backblazeb2\.com$/);
|
|
2128
|
+
if (b2S3) {
|
|
2129
|
+
return {
|
|
2130
|
+
bucket: b2S3[1],
|
|
2131
|
+
region: b2S3[2],
|
|
2132
|
+
endpoint: `${url.protocol}//s3.${b2S3[2]}.backblazeb2.com`,
|
|
2133
|
+
provider: "s3",
|
|
2134
|
+
prefix: pathParts.join("/")
|
|
2135
|
+
};
|
|
2136
|
+
}
|
|
2137
|
+
const b2Native = host.match(/^f[a-z0-9]+\.backblazeb2\.com$/);
|
|
2138
|
+
if (b2Native && pathParts[0] === "file" && pathParts.length > 1) {
|
|
2139
|
+
return {
|
|
2140
|
+
bucket: pathParts[1],
|
|
2141
|
+
region: defaults.region || "us-west-000",
|
|
2142
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2143
|
+
provider: "s3",
|
|
2144
|
+
prefix: pathParts.slice(2).join("/")
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
const ossMatch = host.match(/^(.+)\.(oss-[a-z0-9-]+)\.aliyuncs\.com$/);
|
|
2148
|
+
if (ossMatch) {
|
|
2149
|
+
return {
|
|
2150
|
+
bucket: ossMatch[1],
|
|
2151
|
+
region: ossMatch[2],
|
|
2152
|
+
endpoint: `${url.protocol}//${ossMatch[2]}.aliyuncs.com`,
|
|
2153
|
+
provider: "s3",
|
|
2154
|
+
prefix: pathParts.join("/")
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
const cosMatch = host.match(/^(.+)\.cos\.([a-z0-9-]+)\.myqcloud\.com$/);
|
|
2158
|
+
if (cosMatch) {
|
|
2159
|
+
return {
|
|
2160
|
+
bucket: cosMatch[1],
|
|
2161
|
+
region: cosMatch[2],
|
|
2162
|
+
endpoint: `${url.protocol}//cos.${cosMatch[2]}.myqcloud.com`,
|
|
2163
|
+
provider: "s3",
|
|
2164
|
+
prefix: pathParts.join("/")
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
if (host === "storage.yandexcloud.net" && pathParts.length > 0) {
|
|
2168
|
+
return {
|
|
2169
|
+
bucket: pathParts[0],
|
|
2170
|
+
region: defaults.region || "ru-central1",
|
|
2171
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2172
|
+
provider: "s3",
|
|
2173
|
+
prefix: pathParts.slice(1).join("/")
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
const isMinioLike = host.includes("minio") || host === "localhost" || host === "127.0.0.1" || host.startsWith("192.168.") || host.startsWith("10.");
|
|
2177
|
+
if (isMinioLike && pathParts.length > 0) {
|
|
2178
|
+
return {
|
|
2179
|
+
bucket: pathParts[0],
|
|
2180
|
+
region: defaults.region || "us-east-1",
|
|
2181
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2182
|
+
provider: "minio",
|
|
2183
|
+
prefix: pathParts.slice(1).join("/")
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
const azureBlob = host.match(/^([a-z0-9]+)\.blob\.core\.windows\.net$/);
|
|
2187
|
+
if (azureBlob && pathParts.length > 0) {
|
|
2188
|
+
return {
|
|
2189
|
+
bucket: pathParts[0],
|
|
2190
|
+
region: defaults.region || "",
|
|
2191
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2192
|
+
provider: "azure",
|
|
2193
|
+
prefix: pathParts.slice(1).join("/")
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
const storjGateway = host.match(/^gateway\.(?:([a-z0-9]+)\.)?storjshare\.io$/);
|
|
2197
|
+
if (storjGateway && pathParts.length > 0) {
|
|
2198
|
+
return {
|
|
2199
|
+
bucket: pathParts[0],
|
|
2200
|
+
region: storjGateway[1] || defaults.region || "us1",
|
|
2201
|
+
endpoint: `${url.protocol}//${url.host}`,
|
|
2202
|
+
provider: "storj",
|
|
2203
|
+
prefix: pathParts.slice(1).join("/")
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
const storjLink = host.match(/^link\.(?:([a-z0-9]+)\.)?storjshare\.io$/);
|
|
2207
|
+
if (storjLink && pathParts.length >= 3 && (pathParts[0] === "raw" || pathParts[0] === "s")) {
|
|
2208
|
+
return {
|
|
2209
|
+
bucket: pathParts[2],
|
|
2210
|
+
region: storjLink[1] || defaults.region || "us1",
|
|
2211
|
+
endpoint: `${url.protocol}//${url.host}/${pathParts[0]}/${pathParts[1]}`,
|
|
2212
|
+
provider: "storj",
|
|
2213
|
+
prefix: pathParts.slice(3).join("/")
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
if (pathParts.length > 0) {
|
|
2217
|
+
const endpoint = `${url.protocol}//${url.host}`;
|
|
2218
|
+
return {
|
|
2219
|
+
bucket: pathParts[0],
|
|
2220
|
+
region: defaults.region || "us-east-1",
|
|
2221
|
+
endpoint,
|
|
2222
|
+
provider: defaults.provider || "s3",
|
|
2223
|
+
prefix: pathParts.slice(1).join("/")
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
return {
|
|
2227
|
+
...defaultResult(defaults),
|
|
2228
|
+
endpoint: `${url.protocol}//${url.host}`
|
|
2229
|
+
};
|
|
2230
|
+
} catch {
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
const cleaned = trimmed.replace(/^\/+|\/+$/g, "");
|
|
2234
|
+
return {
|
|
2235
|
+
bucket: cleaned,
|
|
2236
|
+
region: defaults.region || "us-east-1",
|
|
2237
|
+
endpoint: defaults.endpoint || "",
|
|
2238
|
+
provider: defaults.provider || "s3",
|
|
2239
|
+
prefix: ""
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
function looksLikeUrl(input) {
|
|
2243
|
+
const lower = input.trim().toLowerCase();
|
|
2244
|
+
if (lower.startsWith("http://") || lower.startsWith("https://")) return true;
|
|
2245
|
+
for (const scheme of Object.keys(SCHEME_MAP)) {
|
|
2246
|
+
if (lower.startsWith(scheme)) return true;
|
|
2247
|
+
}
|
|
2248
|
+
return false;
|
|
2249
|
+
}
|
|
2250
|
+
function describeParseResult(parsed) {
|
|
2251
|
+
const parts = [];
|
|
2252
|
+
if (parsed.bucket) parts.push(`bucket="${parsed.bucket}"`);
|
|
2253
|
+
if (parsed.endpoint) parts.push(`endpoint="${parsed.endpoint}"`);
|
|
2254
|
+
if (parsed.region && parsed.region !== "us-east-1") parts.push(`region="${parsed.region}"`);
|
|
2255
|
+
if (parsed.provider !== "s3") parts.push(`provider=${parsed.provider}`);
|
|
2256
|
+
if (parsed.prefix) parts.push(`prefix="${parsed.prefix}"`);
|
|
2257
|
+
return parts.length > 0 ? `Detected: ${parts.join(", ")}` : "";
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
// ../../src/lib/utils/wkb.ts
|
|
2261
|
+
var WKB_POINT = 1;
|
|
2262
|
+
var WKB_LINESTRING = 2;
|
|
2263
|
+
var WKB_POLYGON = 3;
|
|
2264
|
+
var WKB_MULTIPOINT = 4;
|
|
2265
|
+
var WKB_MULTILINESTRING = 5;
|
|
2266
|
+
var WKB_MULTIPOLYGON = 6;
|
|
2267
|
+
var EWKB_Z_FLAG = 2147483648;
|
|
2268
|
+
var EWKB_M_FLAG = 1073741824;
|
|
2269
|
+
var EWKB_SRID_FLAG = 536870912;
|
|
2270
|
+
function toBinary(value) {
|
|
2271
|
+
if (value === null || value === void 0) return null;
|
|
2272
|
+
if (value instanceof Uint8Array) return value;
|
|
2273
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
2274
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "number") {
|
|
2275
|
+
return new Uint8Array(value);
|
|
2276
|
+
}
|
|
2277
|
+
if (typeof value === "string" && /^[0-9a-fA-F]+$/.test(value) && value.length % 2 === 0) {
|
|
2278
|
+
const bytes = new Uint8Array(value.length / 2);
|
|
2279
|
+
for (let i = 0; i < value.length; i += 2) {
|
|
2280
|
+
bytes[i / 2] = parseInt(value.substring(i, i + 2), 16);
|
|
2281
|
+
}
|
|
2282
|
+
return bytes;
|
|
2283
|
+
}
|
|
2284
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
2285
|
+
const obj = value;
|
|
2286
|
+
const keys = Object.keys(obj);
|
|
2287
|
+
if (keys.length > 4 && typeof obj["0"] === "number") {
|
|
2288
|
+
const arr = new Uint8Array(keys.length);
|
|
2289
|
+
for (let i = 0; i < keys.length; i++) arr[i] = obj[i];
|
|
2290
|
+
return arr;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
return null;
|
|
2294
|
+
}
|
|
2295
|
+
function parseWKB(data) {
|
|
2296
|
+
if (data.length < 5) return null;
|
|
2297
|
+
try {
|
|
2298
|
+
return readGeometry(new DataView(data.buffer, data.byteOffset, data.byteLength), 0).geometry;
|
|
2299
|
+
} catch {
|
|
2300
|
+
return null;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
function readGeometry(view, offset) {
|
|
2304
|
+
const le = view.getUint8(offset) === 1;
|
|
2305
|
+
offset += 1;
|
|
2306
|
+
let typeInt = view.getUint32(offset, le);
|
|
2307
|
+
offset += 4;
|
|
2308
|
+
const hasZ = (typeInt & EWKB_Z_FLAG) !== 0 || typeInt % 1e4 >= 1e3 && typeInt % 1e4 < 2e3 || typeInt % 1e4 >= 3e3 && typeInt % 1e4 < 4e3;
|
|
2309
|
+
const hasM = (typeInt & EWKB_M_FLAG) !== 0 || typeInt % 1e4 >= 2e3 && typeInt % 1e4 < 3e3 || typeInt % 1e4 >= 3e3 && typeInt % 1e4 < 4e3;
|
|
2310
|
+
if (typeInt & EWKB_SRID_FLAG) offset += 4;
|
|
2311
|
+
typeInt = (typeInt & 65535) % 1e3;
|
|
2312
|
+
const extraDims = (hasZ ? 1 : 0) + (hasM ? 1 : 0);
|
|
2313
|
+
const rd = (o) => view.getFloat64(o, le);
|
|
2314
|
+
const ru = (o) => view.getUint32(o, le);
|
|
2315
|
+
function readPoint(off) {
|
|
2316
|
+
const x = rd(off);
|
|
2317
|
+
const y = rd(off + 8);
|
|
2318
|
+
return { coords: [x, y], offset: off + 16 + extraDims * 8 };
|
|
2319
|
+
}
|
|
2320
|
+
function readLineString(off) {
|
|
2321
|
+
const n = ru(off);
|
|
2322
|
+
off += 4;
|
|
2323
|
+
const coords = [];
|
|
2324
|
+
for (let i = 0; i < n; i++) {
|
|
2325
|
+
const pt = readPoint(off);
|
|
2326
|
+
coords.push(pt.coords);
|
|
2327
|
+
off = pt.offset;
|
|
2328
|
+
}
|
|
2329
|
+
return { coords, offset: off };
|
|
2330
|
+
}
|
|
2331
|
+
function readPolygon(off) {
|
|
2332
|
+
const n = ru(off);
|
|
2333
|
+
off += 4;
|
|
2334
|
+
const coords = [];
|
|
2335
|
+
for (let i = 0; i < n; i++) {
|
|
2336
|
+
const ring = readLineString(off);
|
|
2337
|
+
coords.push(ring.coords);
|
|
2338
|
+
off = ring.offset;
|
|
2339
|
+
}
|
|
2340
|
+
return { coords, offset: off };
|
|
2341
|
+
}
|
|
2342
|
+
switch (typeInt) {
|
|
2343
|
+
case WKB_POINT: {
|
|
2344
|
+
const pt = readPoint(offset);
|
|
2345
|
+
return { geometry: { type: "Point", coordinates: pt.coords }, offset: pt.offset };
|
|
2346
|
+
}
|
|
2347
|
+
case WKB_LINESTRING: {
|
|
2348
|
+
const ls = readLineString(offset);
|
|
2349
|
+
return { geometry: { type: "LineString", coordinates: ls.coords }, offset: ls.offset };
|
|
2350
|
+
}
|
|
2351
|
+
case WKB_POLYGON: {
|
|
2352
|
+
const pg = readPolygon(offset);
|
|
2353
|
+
return { geometry: { type: "Polygon", coordinates: pg.coords }, offset: pg.offset };
|
|
2354
|
+
}
|
|
2355
|
+
case WKB_MULTIPOINT: {
|
|
2356
|
+
const n = ru(offset);
|
|
2357
|
+
offset += 4;
|
|
2358
|
+
const coords = [];
|
|
2359
|
+
for (let i = 0; i < n; i++) {
|
|
2360
|
+
const r = readGeometry(view, offset);
|
|
2361
|
+
coords.push(r.geometry.coordinates);
|
|
2362
|
+
offset = r.offset;
|
|
2363
|
+
}
|
|
2364
|
+
return { geometry: { type: "MultiPoint", coordinates: coords }, offset };
|
|
2365
|
+
}
|
|
2366
|
+
case WKB_MULTILINESTRING: {
|
|
2367
|
+
const n = ru(offset);
|
|
2368
|
+
offset += 4;
|
|
2369
|
+
const coords = [];
|
|
2370
|
+
for (let i = 0; i < n; i++) {
|
|
2371
|
+
const r = readGeometry(view, offset);
|
|
2372
|
+
coords.push(r.geometry.coordinates);
|
|
2373
|
+
offset = r.offset;
|
|
2374
|
+
}
|
|
2375
|
+
return { geometry: { type: "MultiLineString", coordinates: coords }, offset };
|
|
2376
|
+
}
|
|
2377
|
+
case WKB_MULTIPOLYGON: {
|
|
2378
|
+
const n = ru(offset);
|
|
2379
|
+
offset += 4;
|
|
2380
|
+
const coords = [];
|
|
2381
|
+
for (let i = 0; i < n; i++) {
|
|
2382
|
+
const r = readGeometry(view, offset);
|
|
2383
|
+
coords.push(r.geometry.coordinates);
|
|
2384
|
+
offset = r.offset;
|
|
2385
|
+
}
|
|
2386
|
+
return { geometry: { type: "MultiPolygon", coordinates: coords }, offset };
|
|
2387
|
+
}
|
|
2388
|
+
default:
|
|
2389
|
+
return { geometry: { type: "Unknown", coordinates: [] }, offset };
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
var GEO_NAMES = [
|
|
2393
|
+
"geometry",
|
|
2394
|
+
"geom",
|
|
2395
|
+
"wkb_geometry",
|
|
2396
|
+
"the_geom",
|
|
2397
|
+
"shape",
|
|
2398
|
+
"geo",
|
|
2399
|
+
"wkt_geometry",
|
|
2400
|
+
"the_geog",
|
|
2401
|
+
"geog",
|
|
2402
|
+
"way",
|
|
2403
|
+
"ora_geometry"
|
|
2404
|
+
];
|
|
2405
|
+
var GEO_TYPE_KEYWORDS = [
|
|
2406
|
+
"geometry",
|
|
2407
|
+
"geography",
|
|
2408
|
+
"wkb",
|
|
2409
|
+
"point",
|
|
2410
|
+
"linestring",
|
|
2411
|
+
"polygon",
|
|
2412
|
+
"multipoint",
|
|
2413
|
+
"multilinestring",
|
|
2414
|
+
"multipolygon",
|
|
2415
|
+
"geometrycollection",
|
|
2416
|
+
"sdo_geometry"
|
|
2417
|
+
];
|
|
2418
|
+
var GEO_NAME_HINTS = ["geom", "geometry", "geo_", "_geo", "wkb", "wkt", "shape", "spatial"];
|
|
2419
|
+
var GEOJSON_TYPES = [
|
|
2420
|
+
"Point",
|
|
2421
|
+
"LineString",
|
|
2422
|
+
"Polygon",
|
|
2423
|
+
"MultiPoint",
|
|
2424
|
+
"MultiLineString",
|
|
2425
|
+
"MultiPolygon"
|
|
2426
|
+
];
|
|
2427
|
+
function isGeoJSONGeometry(value) {
|
|
2428
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
2429
|
+
const obj = value;
|
|
2430
|
+
return typeof obj.type === "string" && GEOJSON_TYPES.includes(obj.type) && obj.coordinates != null;
|
|
2431
|
+
}
|
|
2432
|
+
function findGeoColumn(schema) {
|
|
2433
|
+
for (const f of schema) {
|
|
2434
|
+
const t = f.type.toLowerCase();
|
|
2435
|
+
if (t.startsWith("struct") || t.startsWith("map") || t.startsWith("list")) continue;
|
|
2436
|
+
if (GEO_TYPE_KEYWORDS.some((kw) => t.includes(kw))) return f.name;
|
|
2437
|
+
}
|
|
2438
|
+
for (const f of schema) {
|
|
2439
|
+
const n = f.name.toLowerCase();
|
|
2440
|
+
const t = f.type.toLowerCase();
|
|
2441
|
+
const isBinary = t.includes("blob") || t.includes("binary") || t.includes("bytea");
|
|
2442
|
+
if (GEO_NAMES.includes(n) && isBinary) return f.name;
|
|
2443
|
+
}
|
|
2444
|
+
for (const f of schema) {
|
|
2445
|
+
if (GEO_NAMES.includes(f.name.toLowerCase())) return f.name;
|
|
2446
|
+
}
|
|
2447
|
+
for (const f of schema) {
|
|
2448
|
+
const n = f.name.toLowerCase();
|
|
2449
|
+
const t = f.type.toLowerCase();
|
|
2450
|
+
const isBinary = t.includes("blob") || t.includes("binary") || t.includes("bytea");
|
|
2451
|
+
if (isBinary && GEO_NAME_HINTS.some((hint) => n.includes(hint))) return f.name;
|
|
2452
|
+
}
|
|
2453
|
+
for (const f of schema) {
|
|
2454
|
+
const n = f.name.toLowerCase();
|
|
2455
|
+
if (GEO_NAME_HINTS.some((hint) => n.includes(hint))) return f.name;
|
|
2456
|
+
}
|
|
2457
|
+
return null;
|
|
2458
|
+
}
|
|
2459
|
+
function looksLikeWKB(value) {
|
|
2460
|
+
const bytes = toBinary(value);
|
|
2461
|
+
if (!bytes || bytes.length < 5) return false;
|
|
2462
|
+
const bom = bytes[0];
|
|
2463
|
+
if (bom !== 0 && bom !== 1) return false;
|
|
2464
|
+
const le = bom === 1;
|
|
2465
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2466
|
+
let typeInt = view.getUint32(1, le);
|
|
2467
|
+
typeInt = (typeInt & 65535) % 1e3;
|
|
2468
|
+
return typeInt >= 1 && typeInt <= 7;
|
|
2469
|
+
}
|
|
2470
|
+
function findGeoColumnFromRows(rows, schema) {
|
|
2471
|
+
if (rows.length === 0) return null;
|
|
2472
|
+
const sample = rows[0];
|
|
2473
|
+
for (const f of schema) {
|
|
2474
|
+
const t = f.type.toLowerCase();
|
|
2475
|
+
const isBinary = t.includes("blob") || t.includes("binary") || t.includes("bytea");
|
|
2476
|
+
if (isBinary && looksLikeWKB(sample[f.name])) return f.name;
|
|
2477
|
+
}
|
|
2478
|
+
for (const [key, value] of Object.entries(sample)) {
|
|
2479
|
+
if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
|
|
2480
|
+
if (looksLikeWKB(value)) return key;
|
|
2481
|
+
}
|
|
2482
|
+
if (typeof value === "string") {
|
|
2483
|
+
if (/^[0-9a-fA-F]+$/.test(value) && value.length >= 10 && looksLikeWKB(value)) {
|
|
2484
|
+
return key;
|
|
2485
|
+
}
|
|
2486
|
+
if (isWKT(value)) return key;
|
|
2487
|
+
}
|
|
2488
|
+
if (isGeoJSONGeometry(value)) return key;
|
|
2489
|
+
if (typeof value === "string" && value.startsWith("{")) {
|
|
2490
|
+
try {
|
|
2491
|
+
if (isGeoJSONGeometry(JSON.parse(value))) return key;
|
|
2492
|
+
} catch {
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
return null;
|
|
2497
|
+
}
|
|
2498
|
+
var WKT_TYPES = [
|
|
2499
|
+
"POINT",
|
|
2500
|
+
"LINESTRING",
|
|
2501
|
+
"POLYGON",
|
|
2502
|
+
"MULTIPOINT",
|
|
2503
|
+
"MULTILINESTRING",
|
|
2504
|
+
"MULTIPOLYGON"
|
|
2505
|
+
];
|
|
2506
|
+
function isWKT(value) {
|
|
2507
|
+
if (typeof value !== "string") return false;
|
|
2508
|
+
const s = value.trimStart().toUpperCase();
|
|
2509
|
+
return WKT_TYPES.some((t) => s.startsWith(t) || s.startsWith(`MULTI${t}`));
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
exports.QueryCancelledError = QueryCancelledError;
|
|
2513
|
+
exports.UrlAdapter = UrlAdapter;
|
|
2514
|
+
exports.buildDuckDbSource = buildDuckDbSource;
|
|
2515
|
+
exports.buildGeoArrowTables = buildGeoArrowTables;
|
|
2516
|
+
exports.classifyType = classifyType;
|
|
2517
|
+
exports.describeParseResult = describeParseResult;
|
|
2518
|
+
exports.extractBounds = extractBounds;
|
|
2519
|
+
exports.extractEpsgFromGeoMeta = extractEpsgFromGeoMeta;
|
|
2520
|
+
exports.extractGeometryTypes = extractGeometryTypes;
|
|
2521
|
+
exports.findGeoColumn = findGeoColumn;
|
|
2522
|
+
exports.findGeoColumnFromRows = findGeoColumnFromRows;
|
|
2523
|
+
exports.formatDate = formatDate;
|
|
2524
|
+
exports.formatFileSize = formatFileSize;
|
|
2525
|
+
exports.generateHexDump = generateHexDump;
|
|
2526
|
+
exports.getDuckDbReadFn = getDuckDbReadFn;
|
|
2527
|
+
exports.getFileExtension = getFileExtension;
|
|
2528
|
+
exports.getFileTypeInfo = getFileTypeInfo;
|
|
2529
|
+
exports.getMimeType = getMimeType;
|
|
2530
|
+
exports.getViewerKind = getViewerKind;
|
|
2531
|
+
exports.isCloudNativeFormat = isCloudNativeFormat;
|
|
2532
|
+
exports.isQueryable = isQueryable;
|
|
2533
|
+
exports.looksLikeUrl = looksLikeUrl;
|
|
2534
|
+
exports.normalizeGeomType = normalizeGeomType;
|
|
2535
|
+
exports.parseStorageUrl = parseStorageUrl;
|
|
2536
|
+
exports.parseWKB = parseWKB;
|
|
2537
|
+
exports.readParquetMetadata = readParquetMetadata;
|
|
2538
|
+
exports.toBinary = toBinary;
|
|
2539
|
+
exports.typeBadgeClass = typeBadgeClass;
|
|
2540
|
+
exports.typeColor = typeColor;
|
|
2541
|
+
exports.typeLabel = typeLabel;
|
|
2542
|
+
//# sourceMappingURL=index.cjs.map
|
|
2543
|
+
//# sourceMappingURL=index.cjs.map
|