@walkthru-earth/objex 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +5 -0
- package/README.md +20 -12
- package/dist/components/browser/FileTreeSidebar.svelte +32 -17
- package/dist/components/layout/AboutSheet.svelte +5 -2
- package/dist/components/layout/ConnectionDialog.svelte +1 -1
- package/dist/components/layout/SettingsSheet.svelte +237 -0
- package/dist/components/layout/SettingsSheet.svelte.d.ts +6 -0
- package/dist/components/layout/Sidebar.svelte +73 -6
- package/dist/components/layout/Sidebar.svelte.d.ts +4 -1
- package/dist/components/layout/StatusBar.svelte +1 -1
- package/dist/components/layout/TabBar.svelte +2 -2
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/resizable/index.d.ts +1 -1
- package/dist/components/ui/resizable/index.js +2 -2
- package/dist/components/ui/slider/index.d.ts +3 -0
- package/dist/components/ui/slider/index.js +5 -0
- package/dist/components/ui/slider/range-slider.svelte +94 -0
- package/dist/components/ui/slider/range-slider.svelte.d.ts +21 -0
- package/dist/components/ui/slider/slider.svelte +83 -0
- package/dist/components/ui/slider/slider.svelte.d.ts +7 -0
- package/dist/components/viewers/ArchiveViewer.svelte +2 -2
- package/dist/components/viewers/CodeViewer.svelte +31 -22
- package/dist/components/viewers/CogControls.svelte +338 -184
- package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
- package/dist/components/viewers/CogViewer.svelte +263 -112
- package/dist/components/viewers/CopcViewer.svelte +1 -1
- package/dist/components/viewers/FlatGeobufViewer.svelte +1 -1
- package/dist/components/viewers/GeoParquetMapViewer.svelte +6 -6
- package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/ImageViewer.svelte +2 -2
- package/dist/components/viewers/MarkdownViewer.svelte +12 -9
- package/dist/components/viewers/MediaViewer.svelte +2 -2
- package/dist/components/viewers/ModelViewer.svelte +1 -1
- package/dist/components/viewers/MultiCogViewer.svelte +467 -102
- package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/NotebookViewer.svelte +6 -3
- package/dist/components/viewers/PdfViewer.svelte +2 -2
- package/dist/components/viewers/PmtilesViewer.svelte +3 -6
- package/dist/components/viewers/RawViewer.svelte +6 -3
- package/dist/components/viewers/StacMapViewer.svelte +1 -1
- package/dist/components/viewers/StacMosaicViewer.svelte +1760 -408
- package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/StacTabViewer.svelte +24 -13
- package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/TableGrid.svelte +4 -4
- package/dist/components/viewers/TableStatusBar.svelte +1 -1
- package/dist/components/viewers/TableToolbar.svelte +1 -1
- package/dist/components/viewers/TableViewer.svelte +25 -17
- package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
- package/dist/components/viewers/ViewerRouter.svelte +16 -8
- package/dist/components/viewers/ZarrMapViewer.svelte +11 -9
- package/dist/components/viewers/ZarrViewer.svelte +4 -4
- package/dist/components/viewers/cog/ChannelPicker.svelte +83 -0
- package/dist/components/viewers/cog/ChannelPicker.svelte.d.ts +13 -0
- package/dist/components/viewers/cog/PixelInspectorPanel.svelte +87 -0
- package/dist/components/viewers/cog/PixelInspectorPanel.svelte.d.ts +17 -0
- package/dist/components/viewers/cog/buildRgbLayer.d.ts +78 -0
- package/dist/components/viewers/cog/buildRgbLayer.js +176 -0
- package/dist/components/viewers/map/AttributeTable.svelte +1 -1
- package/dist/components/viewers/map/MapContainer.svelte +37 -11
- package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +1 -1
- package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +1 -1
- package/dist/components/viewers/stac/StacDatetimeBar.svelte +175 -0
- package/dist/components/viewers/stac/StacDatetimeBar.svelte.d.ts +10 -0
- package/dist/components/viewers/stac/StacFilterPanel.svelte +243 -0
- package/dist/components/viewers/stac/StacFilterPanel.svelte.d.ts +14 -0
- package/dist/components/viewers/stac/StacItemInspector.svelte +223 -0
- package/dist/components/viewers/stac/StacItemInspector.svelte.d.ts +10 -0
- package/dist/components/viewers/stac/StacItemStrip.svelte +228 -0
- package/dist/components/viewers/stac/StacItemStrip.svelte.d.ts +12 -0
- package/dist/file-icons/index.d.ts +1 -1
- package/dist/file-icons/index.js +1 -1
- package/dist/i18n/ar.js +110 -2
- package/dist/i18n/en.js +110 -2
- package/dist/index.d.ts +2 -28
- package/dist/index.js +7 -23
- package/dist/query/engine.d.ts +10 -0
- package/dist/query/source.js +1 -1
- package/dist/query/stac-source-factory.d.ts +65 -0
- package/dist/query/stac-source-factory.js +77 -0
- package/dist/query/stac-source-parquet.d.ts +135 -0
- package/dist/query/stac-source-parquet.js +465 -0
- package/dist/query/wasm.d.ts +8 -0
- package/dist/query/wasm.js +304 -2
- package/dist/storage/presign.js +1 -1
- package/dist/storage/providers.js +5 -5
- package/dist/stores/config.svelte.d.ts +15 -0
- package/dist/stores/config.svelte.js +46 -0
- package/dist/stores/connections.svelte.d.ts +2 -2
- package/dist/stores/connections.svelte.js +1 -2
- package/dist/stores/files.svelte.d.ts +1 -1
- package/dist/stores/files.svelte.js +1 -1
- package/dist/stores/query-history.svelte.js +1 -1
- package/dist/stores/settings.svelte.d.ts +16 -1
- package/dist/stores/settings.svelte.js +104 -48
- package/dist/stores/tabs.svelte.d.ts +3 -0
- package/dist/stores/tabs.svelte.js +17 -0
- package/dist/utils/cog-histogram.d.ts +121 -0
- package/dist/utils/cog-histogram.js +424 -0
- package/dist/utils/cog.d.ts +177 -20
- package/dist/utils/cog.js +361 -76
- package/dist/utils/colormap-sprite.d.ts +0 -9
- package/dist/utils/colormap-sprite.js +0 -21
- package/dist/utils/deck.d.ts +16 -12
- package/dist/utils/deck.js +10 -4
- package/dist/utils/pmtiles-tile.js +2 -2
- package/dist/utils/{url.d.ts → signed-url.d.ts} +15 -1
- package/dist/utils/{url.js → signed-url.js} +32 -10
- package/dist/utils/url-state.d.ts +36 -0
- package/dist/utils/url-state.js +72 -2
- package/dist/utils/zarr-tab.d.ts +1 -2
- package/dist/utils/zarr-tab.js +1 -2
- package/dist/utils/zarr.d.ts +0 -17
- package/dist/utils/zarr.js +1 -45
- package/package.json +55 -84
- package/dist/components/browser/Breadcrumb.svelte +0 -50
- package/dist/components/browser/Breadcrumb.svelte.d.ts +0 -7
- package/dist/components/browser/CreateFolderDialog.svelte +0 -98
- package/dist/components/browser/CreateFolderDialog.svelte.d.ts +0 -6
- package/dist/components/browser/DeleteConfirmDialog.svelte +0 -90
- package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +0 -8
- package/dist/components/browser/DropZone.svelte +0 -83
- package/dist/components/browser/DropZone.svelte.d.ts +0 -7
- package/dist/components/browser/FileBrowser.svelte +0 -252
- package/dist/components/browser/FileBrowser.svelte.d.ts +0 -3
- package/dist/components/browser/FileRow.svelte +0 -117
- package/dist/components/browser/FileRow.svelte.d.ts +0 -9
- package/dist/components/browser/RenameDialog.svelte +0 -101
- package/dist/components/browser/RenameDialog.svelte.d.ts +0 -8
- package/dist/components/browser/SearchBar.svelte +0 -40
- package/dist/components/browser/SearchBar.svelte.d.ts +0 -6
- package/dist/components/browser/UploadButton.svelte +0 -65
- package/dist/components/browser/UploadButton.svelte.d.ts +0 -3
- package/dist/query/stac-geoparquet.d.ts +0 -31
- package/dist/query/stac-geoparquet.js +0 -136
- package/dist/utils/clipboard.d.ts +0 -13
- package/dist/utils/clipboard.js +0 -38
- package/dist/utils/cloud-url.d.ts +0 -27
- package/dist/utils/cloud-url.js +0 -61
- package/dist/utils/cog-pure.d.ts +0 -25
- package/dist/utils/cog-pure.js +0 -35
- package/dist/utils/column-types.d.ts +0 -5
- package/dist/utils/column-types.js +0 -137
- package/dist/utils/connection-identity.d.ts +0 -51
- package/dist/utils/connection-identity.js +0 -97
- package/dist/utils/error.d.ts +0 -8
- package/dist/utils/error.js +0 -12
- package/dist/utils/evidence-context.d.ts +0 -22
- package/dist/utils/evidence-context.js +0 -56
- package/dist/utils/export.d.ts +0 -22
- package/dist/utils/export.js +0 -76
- package/dist/utils/file-sort.d.ts +0 -20
- package/dist/utils/file-sort.js +0 -41
- package/dist/utils/format.d.ts +0 -24
- package/dist/utils/format.js +0 -78
- package/dist/utils/geoarrow.d.ts +0 -32
- package/dist/utils/geoarrow.js +0 -672
- package/dist/utils/geometry-type.d.ts +0 -52
- package/dist/utils/geometry-type.js +0 -76
- package/dist/utils/hex.d.ts +0 -10
- package/dist/utils/hex.js +0 -27
- package/dist/utils/host-detection.d.ts +0 -23
- package/dist/utils/host-detection.js +0 -95
- package/dist/utils/local-storage.d.ts +0 -16
- package/dist/utils/local-storage.js +0 -37
- package/dist/utils/markdown-sql.d.ts +0 -30
- package/dist/utils/markdown-sql.js +0 -72
- package/dist/utils/notebook.d.ts +0 -59
- package/dist/utils/notebook.js +0 -211
- package/dist/utils/parquet-metadata.d.ts +0 -64
- package/dist/utils/parquet-metadata.js +0 -262
- package/dist/utils/stac-geoparquet.d.ts +0 -90
- package/dist/utils/stac-geoparquet.js +0 -223
- package/dist/utils/stac-hydrate.d.ts +0 -38
- package/dist/utils/stac-hydrate.js +0 -243
- package/dist/utils/stac.d.ts +0 -136
- package/dist/utils/stac.js +0 -176
- package/dist/utils/storage-url.d.ts +0 -90
- package/dist/utils/storage-url.js +0 -568
- package/dist/utils/wkb.d.ts +0 -43
- package/dist/utils/wkb.js +0 -359
package/dist/utils/cog-pure.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/** SampleFormat tag value → human label. */
|
|
2
|
-
export declare const SF_LABELS: Record<number, string>;
|
|
3
|
-
export interface GeoBounds {
|
|
4
|
-
west: number;
|
|
5
|
-
south: number;
|
|
6
|
-
east: number;
|
|
7
|
-
north: number;
|
|
8
|
-
}
|
|
9
|
-
export interface CogInfo {
|
|
10
|
-
width: number;
|
|
11
|
-
height: number;
|
|
12
|
-
bandCount: number;
|
|
13
|
-
dataType: string;
|
|
14
|
-
bounds: GeoBounds;
|
|
15
|
-
downsampled?: boolean;
|
|
16
|
-
}
|
|
17
|
-
/** Safely clamp a number to a range, treating NaN/Infinity as the fallback. */
|
|
18
|
-
export declare function safeClamp(v: number, lo: number, hi: number, fallback: number): number;
|
|
19
|
-
/** Clamp geographic bounds to valid MapLibre web-Mercator range. */
|
|
20
|
-
export declare function clampBounds(b: GeoBounds): GeoBounds;
|
|
21
|
-
/**
|
|
22
|
-
* Build a data-type label from GeoTIFF sample format and bits per sample.
|
|
23
|
-
* e.g. "uint8", "float32", "int16"
|
|
24
|
-
*/
|
|
25
|
-
export declare function buildDataTypeLabel(sampleFormat: number, bitsPerSample: number): string;
|
package/dist/utils/cog-pure.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// Dependency-free subset of `cog.ts` so that `@walkthru-earth/objex-utils`
|
|
2
|
-
// can re-export these helpers without dragging in `@developmentseed/epsg`,
|
|
3
|
-
// `@developmentseed/geotiff`, `@developmentseed/proj`, `proj4`, or
|
|
4
|
-
// `maplibre-gl`. tsup preserves bare side-effect imports from externalized
|
|
5
|
-
// modules even when all named bindings are tree-shaken, so the pure surface
|
|
6
|
-
// MUST live in a module that has zero heavy imports.
|
|
7
|
-
/** SampleFormat tag value → human label. */
|
|
8
|
-
export const SF_LABELS = {
|
|
9
|
-
1: 'uint',
|
|
10
|
-
2: 'int',
|
|
11
|
-
3: 'float',
|
|
12
|
-
4: 'void',
|
|
13
|
-
5: 'complex int',
|
|
14
|
-
6: 'complex float'
|
|
15
|
-
};
|
|
16
|
-
/** Safely clamp a number to a range, treating NaN/Infinity as the fallback. */
|
|
17
|
-
export function safeClamp(v, lo, hi, fallback) {
|
|
18
|
-
return Number.isFinite(v) ? Math.max(lo, Math.min(hi, v)) : fallback;
|
|
19
|
-
}
|
|
20
|
-
/** Clamp geographic bounds to valid MapLibre web-Mercator range. */
|
|
21
|
-
export function clampBounds(b) {
|
|
22
|
-
return {
|
|
23
|
-
west: safeClamp(b.west, -180, 180, -180),
|
|
24
|
-
south: safeClamp(b.south, -85.051129, 85.051129, -85.051129),
|
|
25
|
-
east: safeClamp(b.east, -180, 180, 180),
|
|
26
|
-
north: safeClamp(b.north, -85.051129, 85.051129, 85.051129)
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Build a data-type label from GeoTIFF sample format and bits per sample.
|
|
31
|
-
* e.g. "uint8", "float32", "int16"
|
|
32
|
-
*/
|
|
33
|
-
export function buildDataTypeLabel(sampleFormat, bitsPerSample) {
|
|
34
|
-
return `${SF_LABELS[sampleFormat] ?? `sf${sampleFormat}`}${bitsPerSample ?? ''}`;
|
|
35
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export type TypeCategory = 'number' | 'string' | 'date' | 'boolean' | 'geo' | 'binary' | 'json' | 'other';
|
|
2
|
-
export declare function classifyType(duckdbType: string): TypeCategory;
|
|
3
|
-
export declare function typeColor(category: TypeCategory): string;
|
|
4
|
-
export declare function typeBadgeClass(category: TypeCategory): string;
|
|
5
|
-
export declare function typeLabel(category: TypeCategory): string;
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
const NUMBER_TYPES = [
|
|
2
|
-
'TINYINT',
|
|
3
|
-
'SMALLINT',
|
|
4
|
-
'INTEGER',
|
|
5
|
-
'BIGINT',
|
|
6
|
-
'HUGEINT',
|
|
7
|
-
'UTINYINT',
|
|
8
|
-
'USMALLINT',
|
|
9
|
-
'UINTEGER',
|
|
10
|
-
'UBIGINT',
|
|
11
|
-
'FLOAT',
|
|
12
|
-
'DOUBLE',
|
|
13
|
-
'DECIMAL',
|
|
14
|
-
'NUMERIC',
|
|
15
|
-
'REAL',
|
|
16
|
-
'INT',
|
|
17
|
-
'INT1',
|
|
18
|
-
'INT2',
|
|
19
|
-
'INT4',
|
|
20
|
-
'INT8',
|
|
21
|
-
'SIGNED',
|
|
22
|
-
'SHORT',
|
|
23
|
-
'LONG'
|
|
24
|
-
];
|
|
25
|
-
const STRING_TYPES = ['VARCHAR', 'TEXT', 'STRING', 'CHAR', 'BPCHAR', 'NAME', 'UUID', 'ENUM'];
|
|
26
|
-
const DATE_TYPES = [
|
|
27
|
-
'DATE',
|
|
28
|
-
'TIME',
|
|
29
|
-
'TIMESTAMP',
|
|
30
|
-
'TIMESTAMP_S',
|
|
31
|
-
'TIMESTAMP_MS',
|
|
32
|
-
'TIMESTAMP_NS',
|
|
33
|
-
'TIMESTAMP WITH TIME ZONE',
|
|
34
|
-
'TIMESTAMPTZ',
|
|
35
|
-
'INTERVAL',
|
|
36
|
-
'TIMESTAMP_TZ'
|
|
37
|
-
];
|
|
38
|
-
const BOOLEAN_TYPES = ['BOOLEAN', 'BOOL', 'LOGICAL'];
|
|
39
|
-
const GEO_TYPES = [
|
|
40
|
-
'GEOMETRY',
|
|
41
|
-
'POINT',
|
|
42
|
-
'LINESTRING',
|
|
43
|
-
'POLYGON',
|
|
44
|
-
'MULTIPOINT',
|
|
45
|
-
'MULTILINESTRING',
|
|
46
|
-
'MULTIPOLYGON',
|
|
47
|
-
'GEOMETRYCOLLECTION',
|
|
48
|
-
'WKB_GEOMETRY'
|
|
49
|
-
];
|
|
50
|
-
const BINARY_TYPES = ['BLOB', 'BYTEA', 'BINARY', 'VARBINARY'];
|
|
51
|
-
const JSON_TYPES = ['JSON', 'JSONB'];
|
|
52
|
-
export function classifyType(duckdbType) {
|
|
53
|
-
const upper = duckdbType.toUpperCase().trim();
|
|
54
|
-
// Handle parameterized types like DECIMAL(18,3), VARCHAR(100)
|
|
55
|
-
const base = upper.replace(/\(.*\)/, '').trim();
|
|
56
|
-
if (NUMBER_TYPES.includes(base))
|
|
57
|
-
return 'number';
|
|
58
|
-
if (STRING_TYPES.includes(base))
|
|
59
|
-
return 'string';
|
|
60
|
-
if (DATE_TYPES.includes(base))
|
|
61
|
-
return 'date';
|
|
62
|
-
if (BOOLEAN_TYPES.includes(base))
|
|
63
|
-
return 'boolean';
|
|
64
|
-
if (GEO_TYPES.includes(base))
|
|
65
|
-
return 'geo';
|
|
66
|
-
if (BINARY_TYPES.includes(base))
|
|
67
|
-
return 'binary';
|
|
68
|
-
if (JSON_TYPES.includes(base))
|
|
69
|
-
return 'json';
|
|
70
|
-
// Compound types
|
|
71
|
-
if (base.startsWith('STRUCT') || base.startsWith('MAP') || base.startsWith('UNION'))
|
|
72
|
-
return 'json';
|
|
73
|
-
if (base.endsWith('[]') || base.startsWith('LIST'))
|
|
74
|
-
return 'json';
|
|
75
|
-
// Fallback checks
|
|
76
|
-
if (upper.includes('INT') ||
|
|
77
|
-
upper.includes('FLOAT') ||
|
|
78
|
-
upper.includes('DOUBLE') ||
|
|
79
|
-
upper.includes('DECIMAL') ||
|
|
80
|
-
upper.includes('NUMERIC'))
|
|
81
|
-
return 'number';
|
|
82
|
-
if (upper.includes('CHAR') || upper.includes('TEXT') || upper.includes('STRING'))
|
|
83
|
-
return 'string';
|
|
84
|
-
if (upper.includes('TIME') || upper.includes('DATE'))
|
|
85
|
-
return 'date';
|
|
86
|
-
if (upper.includes('BOOL'))
|
|
87
|
-
return 'boolean';
|
|
88
|
-
if (upper.includes('GEOMETRY') || upper.includes('GEO') || upper.includes('WKB'))
|
|
89
|
-
return 'geo';
|
|
90
|
-
if (upper.includes('BLOB') || upper.includes('BINARY'))
|
|
91
|
-
return 'binary';
|
|
92
|
-
if (upper.includes('JSON') ||
|
|
93
|
-
upper.includes('STRUCT') ||
|
|
94
|
-
upper.includes('MAP') ||
|
|
95
|
-
upper.includes('LIST'))
|
|
96
|
-
return 'json';
|
|
97
|
-
return 'other';
|
|
98
|
-
}
|
|
99
|
-
const TYPE_COLORS = {
|
|
100
|
-
number: 'text-blue-500',
|
|
101
|
-
string: 'text-green-500',
|
|
102
|
-
date: 'text-amber-500',
|
|
103
|
-
boolean: 'text-purple-500',
|
|
104
|
-
geo: 'text-teal-500',
|
|
105
|
-
binary: 'text-zinc-500',
|
|
106
|
-
json: 'text-orange-500',
|
|
107
|
-
other: 'text-zinc-400'
|
|
108
|
-
};
|
|
109
|
-
const TYPE_BADGE_CLASSES = {
|
|
110
|
-
number: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20',
|
|
111
|
-
string: 'bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20',
|
|
112
|
-
date: 'bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20',
|
|
113
|
-
boolean: 'bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20',
|
|
114
|
-
geo: 'bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20',
|
|
115
|
-
binary: 'bg-zinc-500/10 text-zinc-600 dark:text-zinc-400 border-zinc-500/20',
|
|
116
|
-
json: 'bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20',
|
|
117
|
-
other: 'bg-zinc-500/10 text-zinc-500 dark:text-zinc-400 border-zinc-500/20'
|
|
118
|
-
};
|
|
119
|
-
const TYPE_LABELS = {
|
|
120
|
-
number: '#',
|
|
121
|
-
string: 'Aa',
|
|
122
|
-
date: 'dt',
|
|
123
|
-
boolean: 'T/F',
|
|
124
|
-
geo: 'geo',
|
|
125
|
-
binary: '01',
|
|
126
|
-
json: '{}',
|
|
127
|
-
other: '?'
|
|
128
|
-
};
|
|
129
|
-
export function typeColor(category) {
|
|
130
|
-
return TYPE_COLORS[category];
|
|
131
|
-
}
|
|
132
|
-
export function typeBadgeClass(category) {
|
|
133
|
-
return TYPE_BADGE_CLASSES[category];
|
|
134
|
-
}
|
|
135
|
-
export function typeLabel(category) {
|
|
136
|
-
return TYPE_LABELS[category];
|
|
137
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical connection identity.
|
|
3
|
-
*
|
|
4
|
-
* Single source of truth for deciding when two connection configs point at
|
|
5
|
-
* the same bucket. Used by the connections store to deduplicate auto-detect,
|
|
6
|
-
* manual add, and edit flows, so one physical bucket never ends up with
|
|
7
|
-
* multiple competing local records.
|
|
8
|
-
*
|
|
9
|
-
* Identity rules, per provider:
|
|
10
|
-
*
|
|
11
|
-
* azure → (provider, endpoint, bucket) endpoint carries the account
|
|
12
|
-
* gcs → (provider, bucket) GCS bucket names are global
|
|
13
|
-
* s3 → (provider, bucket, region) AWS native: same bucket name
|
|
14
|
-
* can exist in exactly one region,
|
|
15
|
-
* but the region is load-bearing
|
|
16
|
-
* for signing, so a paste with a
|
|
17
|
-
* different region is a distinct
|
|
18
|
-
* connection until the user merges
|
|
19
|
-
* other → (provider, endpoint, bucket) r2, b2, minio, wasabi, storj,
|
|
20
|
-
* digitalocean, contabo, hetzner,
|
|
21
|
-
* linode, ovhcloud, custom
|
|
22
|
-
*
|
|
23
|
-
* Endpoint normalization is aggressive: scheme + host + non-default port +
|
|
24
|
-
* pathname, with trailing slashes and default ports stripped, host lowercased.
|
|
25
|
-
* That collapses the common trip hazards — http vs https, :443 vs empty,
|
|
26
|
-
* trailing slash drift, mixed case host.
|
|
27
|
-
*/
|
|
28
|
-
import type { ProviderId } from '../storage/providers.js';
|
|
29
|
-
export interface ConnectionIdentityInput {
|
|
30
|
-
provider: string;
|
|
31
|
-
endpoint: string;
|
|
32
|
-
bucket: string;
|
|
33
|
-
region: string;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Normalize an endpoint URL to a canonical form suitable for equality checks.
|
|
37
|
-
* Empty / whitespace-only input returns `''` (the "no endpoint" sentinel).
|
|
38
|
-
* Non-URL strings are lowercased and stripped of trailing slashes as a best
|
|
39
|
-
* effort so the comparison is still deterministic.
|
|
40
|
-
*/
|
|
41
|
-
export declare function normalizeEndpoint(raw: string | undefined | null): string;
|
|
42
|
-
/** Collapse unknown / empty providers to `'s3'`; otherwise lowercase. */
|
|
43
|
-
export declare function normalizeProvider(provider: string | undefined | null): ProviderId;
|
|
44
|
-
/**
|
|
45
|
-
* Produce a canonical key for a connection's identity. Two connection
|
|
46
|
-
* configs with the same identity key point at the same physical bucket.
|
|
47
|
-
* Returns `''` when the config is too incomplete to identify a bucket.
|
|
48
|
-
*/
|
|
49
|
-
export declare function connectionIdentityKey(input: ConnectionIdentityInput): string;
|
|
50
|
-
/** Convenience: true when both inputs share the same non-empty identity. */
|
|
51
|
-
export declare function isSameConnectionIdentity(a: ConnectionIdentityInput, b: ConnectionIdentityInput): boolean;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical connection identity.
|
|
3
|
-
*
|
|
4
|
-
* Single source of truth for deciding when two connection configs point at
|
|
5
|
-
* the same bucket. Used by the connections store to deduplicate auto-detect,
|
|
6
|
-
* manual add, and edit flows, so one physical bucket never ends up with
|
|
7
|
-
* multiple competing local records.
|
|
8
|
-
*
|
|
9
|
-
* Identity rules, per provider:
|
|
10
|
-
*
|
|
11
|
-
* azure → (provider, endpoint, bucket) endpoint carries the account
|
|
12
|
-
* gcs → (provider, bucket) GCS bucket names are global
|
|
13
|
-
* s3 → (provider, bucket, region) AWS native: same bucket name
|
|
14
|
-
* can exist in exactly one region,
|
|
15
|
-
* but the region is load-bearing
|
|
16
|
-
* for signing, so a paste with a
|
|
17
|
-
* different region is a distinct
|
|
18
|
-
* connection until the user merges
|
|
19
|
-
* other → (provider, endpoint, bucket) r2, b2, minio, wasabi, storj,
|
|
20
|
-
* digitalocean, contabo, hetzner,
|
|
21
|
-
* linode, ovhcloud, custom
|
|
22
|
-
*
|
|
23
|
-
* Endpoint normalization is aggressive: scheme + host + non-default port +
|
|
24
|
-
* pathname, with trailing slashes and default ports stripped, host lowercased.
|
|
25
|
-
* That collapses the common trip hazards — http vs https, :443 vs empty,
|
|
26
|
-
* trailing slash drift, mixed case host.
|
|
27
|
-
*/
|
|
28
|
-
const DEFAULT_PORTS = {
|
|
29
|
-
'https:': '443',
|
|
30
|
-
'http:': '80'
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* Normalize an endpoint URL to a canonical form suitable for equality checks.
|
|
34
|
-
* Empty / whitespace-only input returns `''` (the "no endpoint" sentinel).
|
|
35
|
-
* Non-URL strings are lowercased and stripped of trailing slashes as a best
|
|
36
|
-
* effort so the comparison is still deterministic.
|
|
37
|
-
*/
|
|
38
|
-
export function normalizeEndpoint(raw) {
|
|
39
|
-
if (!raw)
|
|
40
|
-
return '';
|
|
41
|
-
const trimmed = raw.trim();
|
|
42
|
-
if (!trimmed)
|
|
43
|
-
return '';
|
|
44
|
-
try {
|
|
45
|
-
const url = new URL(trimmed);
|
|
46
|
-
const scheme = url.protocol.toLowerCase();
|
|
47
|
-
const host = url.hostname.toLowerCase();
|
|
48
|
-
const defaultPort = DEFAULT_PORTS[scheme] ?? '';
|
|
49
|
-
const port = url.port && url.port !== defaultPort ? `:${url.port}` : '';
|
|
50
|
-
const path = url.pathname.replace(/\/+$/, '');
|
|
51
|
-
return `${scheme}//${host}${port}${path}`;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return trimmed.toLowerCase().replace(/\/+$/, '');
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/** Collapse unknown / empty providers to `'s3'`; otherwise lowercase. */
|
|
58
|
-
export function normalizeProvider(provider) {
|
|
59
|
-
if (!provider)
|
|
60
|
-
return 's3';
|
|
61
|
-
const p = provider.trim().toLowerCase();
|
|
62
|
-
if (!p || p === 'unknown')
|
|
63
|
-
return 's3';
|
|
64
|
-
return p;
|
|
65
|
-
}
|
|
66
|
-
/** Bucket names are case-sensitive on some backends, so preserve case. */
|
|
67
|
-
function normalizeBucket(bucket) {
|
|
68
|
-
return (bucket ?? '').trim().replace(/^\/+|\/+$/g, '');
|
|
69
|
-
}
|
|
70
|
-
function normalizeRegion(region) {
|
|
71
|
-
return (region ?? '').trim().toLowerCase();
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Produce a canonical key for a connection's identity. Two connection
|
|
75
|
-
* configs with the same identity key point at the same physical bucket.
|
|
76
|
-
* Returns `''` when the config is too incomplete to identify a bucket.
|
|
77
|
-
*/
|
|
78
|
-
export function connectionIdentityKey(input) {
|
|
79
|
-
const provider = normalizeProvider(input.provider);
|
|
80
|
-
const bucket = normalizeBucket(input.bucket);
|
|
81
|
-
if (!bucket)
|
|
82
|
-
return '';
|
|
83
|
-
const endpoint = normalizeEndpoint(input.endpoint);
|
|
84
|
-
const region = normalizeRegion(input.region);
|
|
85
|
-
if (provider === 'azure')
|
|
86
|
-
return `azure|${endpoint}|${bucket}`;
|
|
87
|
-
if (provider === 'gcs')
|
|
88
|
-
return `gcs|${bucket}`;
|
|
89
|
-
if (provider === 's3' && !endpoint)
|
|
90
|
-
return `s3|${bucket}|${region}`;
|
|
91
|
-
return `${provider}|${endpoint}|${bucket}`;
|
|
92
|
-
}
|
|
93
|
-
/** Convenience: true when both inputs share the same non-empty identity. */
|
|
94
|
-
export function isSameConnectionIdentity(a, b) {
|
|
95
|
-
const key = connectionIdentityKey(a);
|
|
96
|
-
return key !== '' && key === connectionIdentityKey(b);
|
|
97
|
-
}
|
package/dist/utils/error.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared error handling for async viewer load operations.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Extract an error message from an unknown caught value.
|
|
6
|
-
* Returns null for AbortError (caller should silently return).
|
|
7
|
-
*/
|
|
8
|
-
export declare function handleLoadError(err: unknown): string | null;
|
package/dist/utils/error.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared error handling for async viewer load operations.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Extract an error message from an unknown caught value.
|
|
6
|
-
* Returns null for AbortError (caller should silently return).
|
|
7
|
-
*/
|
|
8
|
-
export function handleLoadError(err) {
|
|
9
|
-
if (err instanceof DOMException && err.name === 'AbortError')
|
|
10
|
-
return null;
|
|
11
|
-
return err instanceof Error ? err.message : String(err);
|
|
12
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { QueryResult } from '../query/engine';
|
|
2
|
-
export declare class EvidenceContext {
|
|
3
|
-
private connId;
|
|
4
|
-
private prefix;
|
|
5
|
-
private results;
|
|
6
|
-
constructor(connId: string, prefix?: string);
|
|
7
|
-
/**
|
|
8
|
-
* Execute a SQL query and store the result under the given name.
|
|
9
|
-
*/
|
|
10
|
-
executeSql(sql: string, queryName: string): Promise<Record<string, any>[]>;
|
|
11
|
-
/**
|
|
12
|
-
* Transform relative file paths in SQL to full S3 URLs.
|
|
13
|
-
* e.g., read_parquet('data.parquet') → read_parquet('s3://bucket/prefix/data.parquet')
|
|
14
|
-
*/
|
|
15
|
-
private transformPaths;
|
|
16
|
-
getResult(queryName: string): {
|
|
17
|
-
result: QueryResult;
|
|
18
|
-
rows: Record<string, any>[];
|
|
19
|
-
} | undefined;
|
|
20
|
-
getAllResults(): Map<string, Record<string, any>[]>;
|
|
21
|
-
getColumns(queryName: string): string[];
|
|
22
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { getQueryEngine } from '../query/index.js';
|
|
2
|
-
export class EvidenceContext {
|
|
3
|
-
connId;
|
|
4
|
-
prefix;
|
|
5
|
-
results = new Map();
|
|
6
|
-
constructor(connId, prefix = '') {
|
|
7
|
-
this.connId = connId;
|
|
8
|
-
this.prefix = prefix;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Execute a SQL query and store the result under the given name.
|
|
12
|
-
*/
|
|
13
|
-
async executeSql(sql, queryName) {
|
|
14
|
-
const engine = await getQueryEngine();
|
|
15
|
-
// Transform relative file paths to full paths
|
|
16
|
-
const transformedSql = this.transformPaths(sql);
|
|
17
|
-
const result = await engine.query(this.connId, transformedSql);
|
|
18
|
-
const rows = result.rows ?? [];
|
|
19
|
-
this.results.set(queryName, { result, rows });
|
|
20
|
-
return rows;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Transform relative file paths in SQL to full S3 URLs.
|
|
24
|
-
* e.g., read_parquet('data.parquet') → read_parquet('s3://bucket/prefix/data.parquet')
|
|
25
|
-
*/
|
|
26
|
-
transformPaths(sql) {
|
|
27
|
-
if (!this.connId || !this.prefix)
|
|
28
|
-
return sql;
|
|
29
|
-
// Match read_parquet('path'), read_csv('path'), read_json('path')
|
|
30
|
-
return sql.replace(/(read_(?:parquet|csv|json|csv_auto))\('([^']+)'\)/g, (match, fn, path) => {
|
|
31
|
-
// Skip absolute paths and URLs
|
|
32
|
-
if (path.startsWith('s3://') || path.startsWith('http') || path.startsWith('/')) {
|
|
33
|
-
return match;
|
|
34
|
-
}
|
|
35
|
-
// Resolve relative path
|
|
36
|
-
const fullPath = `s3://${this.prefix}/${path}`;
|
|
37
|
-
return `${fn}('${fullPath}')`;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
getResult(queryName) {
|
|
41
|
-
return this.results.get(queryName);
|
|
42
|
-
}
|
|
43
|
-
getAllResults() {
|
|
44
|
-
const map = new Map();
|
|
45
|
-
for (const [name, { rows }] of this.results) {
|
|
46
|
-
map.set(name, rows);
|
|
47
|
-
}
|
|
48
|
-
return map;
|
|
49
|
-
}
|
|
50
|
-
getColumns(queryName) {
|
|
51
|
-
const entry = this.results.get(queryName);
|
|
52
|
-
if (!entry)
|
|
53
|
-
return [];
|
|
54
|
-
return entry.result.columns;
|
|
55
|
-
}
|
|
56
|
-
}
|
package/dist/utils/export.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Escape a CSV field value per RFC 4180.
|
|
3
|
-
*/
|
|
4
|
-
export declare function escapeCsvField(value: string): string;
|
|
5
|
-
/**
|
|
6
|
-
* Serialize column/row data to a CSV string.
|
|
7
|
-
* Pure function — no browser APIs, works in Node.js.
|
|
8
|
-
*/
|
|
9
|
-
export declare function serializeToCsv(columns: string[], rows: Record<string, unknown>[]): string;
|
|
10
|
-
/**
|
|
11
|
-
* Serialize column/row data to a formatted JSON string.
|
|
12
|
-
* Pure function — no browser APIs, works in Node.js.
|
|
13
|
-
*/
|
|
14
|
-
export declare function serializeToJson(columns: string[], rows: Record<string, unknown>[]): string;
|
|
15
|
-
/**
|
|
16
|
-
* Export data as CSV file (triggers browser download).
|
|
17
|
-
*/
|
|
18
|
-
export declare function exportToCsv(columns: string[], rows: Record<string, unknown>[], filename: string): void;
|
|
19
|
-
/**
|
|
20
|
-
* Export data as JSON file (triggers browser download).
|
|
21
|
-
*/
|
|
22
|
-
export declare function exportToJson(columns: string[], rows: Record<string, unknown>[], filename: string): void;
|
package/dist/utils/export.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { jsonReplacerBigInt } from './format.js';
|
|
2
|
-
function triggerDownload(content, filename, mimeType) {
|
|
3
|
-
const blob = new Blob([content], { type: mimeType });
|
|
4
|
-
const url = URL.createObjectURL(blob);
|
|
5
|
-
const a = document.createElement('a');
|
|
6
|
-
a.href = url;
|
|
7
|
-
a.download = filename;
|
|
8
|
-
document.body.appendChild(a);
|
|
9
|
-
a.click();
|
|
10
|
-
document.body.removeChild(a);
|
|
11
|
-
URL.revokeObjectURL(url);
|
|
12
|
-
}
|
|
13
|
-
/** Format a cell value for export (empty string for null/undefined). */
|
|
14
|
-
function formatCellValue(value) {
|
|
15
|
-
if (value === null || value === undefined)
|
|
16
|
-
return '';
|
|
17
|
-
if (value instanceof Date)
|
|
18
|
-
return value.toISOString();
|
|
19
|
-
if (typeof value === 'bigint')
|
|
20
|
-
return value.toString();
|
|
21
|
-
if (typeof value === 'object')
|
|
22
|
-
return JSON.stringify(value, jsonReplacerBigInt);
|
|
23
|
-
return String(value);
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Escape a CSV field value per RFC 4180.
|
|
27
|
-
*/
|
|
28
|
-
export function escapeCsvField(value) {
|
|
29
|
-
if (value.includes(',') || value.includes('"') || value.includes('\n') || value.includes('\r')) {
|
|
30
|
-
return `"${value.replace(/"/g, '""')}"`;
|
|
31
|
-
}
|
|
32
|
-
return value;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Serialize column/row data to a CSV string.
|
|
36
|
-
* Pure function — no browser APIs, works in Node.js.
|
|
37
|
-
*/
|
|
38
|
-
export function serializeToCsv(columns, rows) {
|
|
39
|
-
const header = columns.map(escapeCsvField).join(',');
|
|
40
|
-
const body = rows
|
|
41
|
-
.map((row) => columns.map((col) => escapeCsvField(formatCellValue(row[col]))).join(','))
|
|
42
|
-
.join('\n');
|
|
43
|
-
return `${header}\n${body}`;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Serialize column/row data to a formatted JSON string.
|
|
47
|
-
* Pure function — no browser APIs, works in Node.js.
|
|
48
|
-
*/
|
|
49
|
-
export function serializeToJson(columns, rows) {
|
|
50
|
-
const data = rows.map((row) => {
|
|
51
|
-
const obj = {};
|
|
52
|
-
for (const col of columns) {
|
|
53
|
-
const val = row[col];
|
|
54
|
-
if (val instanceof Date) {
|
|
55
|
-
obj[col] = val.toISOString();
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
obj[col] = val ?? null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return obj;
|
|
62
|
-
});
|
|
63
|
-
return JSON.stringify(data, jsonReplacerBigInt, 2);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Export data as CSV file (triggers browser download).
|
|
67
|
-
*/
|
|
68
|
-
export function exportToCsv(columns, rows, filename) {
|
|
69
|
-
triggerDownload(serializeToCsv(columns, rows), filename.endsWith('.csv') ? filename : `${filename}.csv`, 'text/csv;charset=utf-8;');
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Export data as JSON file (triggers browser download).
|
|
73
|
-
*/
|
|
74
|
-
export function exportToJson(columns, rows, filename) {
|
|
75
|
-
triggerDownload(serializeToJson(columns, rows), filename.endsWith('.json') ? filename : `${filename}.json`, 'application/json');
|
|
76
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure file entry sorting — framework-agnostic, works in Node.js.
|
|
3
|
-
*/
|
|
4
|
-
import type { FileEntry } from '../types.js';
|
|
5
|
-
export type SortField = 'name' | 'size' | 'modified' | 'extension';
|
|
6
|
-
export type SortDirection = 'asc' | 'desc';
|
|
7
|
-
export interface SortConfig {
|
|
8
|
-
field: SortField;
|
|
9
|
-
direction: SortDirection;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Sort file entries by the given config.
|
|
13
|
-
* Directories always sort before files regardless of sort field.
|
|
14
|
-
* Returns a new array (does not mutate the input).
|
|
15
|
-
*/
|
|
16
|
-
export declare function sortFileEntries(entries: FileEntry[], config: SortConfig): FileEntry[];
|
|
17
|
-
/**
|
|
18
|
-
* Toggle sort config: same field flips direction, new field starts ascending.
|
|
19
|
-
*/
|
|
20
|
-
export declare function toggleSortField(current: SortConfig, field: SortField): SortConfig;
|
package/dist/utils/file-sort.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure file entry sorting — framework-agnostic, works in Node.js.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Sort file entries by the given config.
|
|
6
|
-
* Directories always sort before files regardless of sort field.
|
|
7
|
-
* Returns a new array (does not mutate the input).
|
|
8
|
-
*/
|
|
9
|
-
export function sortFileEntries(entries, config) {
|
|
10
|
-
const sorted = [...entries];
|
|
11
|
-
const dir = config.direction === 'asc' ? 1 : -1;
|
|
12
|
-
sorted.sort((a, b) => {
|
|
13
|
-
// Directories always come first
|
|
14
|
-
if (a.is_dir && !b.is_dir)
|
|
15
|
-
return -1;
|
|
16
|
-
if (!a.is_dir && b.is_dir)
|
|
17
|
-
return 1;
|
|
18
|
-
switch (config.field) {
|
|
19
|
-
case 'name':
|
|
20
|
-
return dir * a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
|
|
21
|
-
case 'size':
|
|
22
|
-
return dir * (a.size - b.size);
|
|
23
|
-
case 'modified':
|
|
24
|
-
return dir * (a.modified - b.modified);
|
|
25
|
-
case 'extension':
|
|
26
|
-
return dir * a.extension.localeCompare(b.extension, undefined, { sensitivity: 'base' });
|
|
27
|
-
default:
|
|
28
|
-
return 0;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return sorted;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Toggle sort config: same field flips direction, new field starts ascending.
|
|
35
|
-
*/
|
|
36
|
-
export function toggleSortField(current, field) {
|
|
37
|
-
if (current.field === field) {
|
|
38
|
-
return { field, direction: current.direction === 'asc' ? 'desc' : 'asc' };
|
|
39
|
-
}
|
|
40
|
-
return { field, direction: 'asc' };
|
|
41
|
-
}
|
package/dist/utils/format.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Formats a byte count into a human-readable string.
|
|
3
|
-
*/
|
|
4
|
-
export declare function formatFileSize(bytes: number): string;
|
|
5
|
-
/**
|
|
6
|
-
* Formats a unix timestamp (milliseconds) to a human-readable date string.
|
|
7
|
-
* Shows relative time for recent dates, absolute for older ones.
|
|
8
|
-
*/
|
|
9
|
-
export declare function formatDate(timestamp: number): string;
|
|
10
|
-
/**
|
|
11
|
-
* Extracts the file extension from a filename, including the leading dot.
|
|
12
|
-
* Returns an empty string if no extension is found.
|
|
13
|
-
*/
|
|
14
|
-
export declare function getFileExtension(filename: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* JSON replacer that converts BigInt values to strings.
|
|
17
|
-
* Use with `JSON.stringify(value, jsonReplacerBigInt)`.
|
|
18
|
-
*/
|
|
19
|
-
export declare function jsonReplacerBigInt(_key: string, value: unknown): unknown;
|
|
20
|
-
/**
|
|
21
|
-
* Format a value for display in tables, attribute panels, and exports.
|
|
22
|
-
* Handles null, undefined, Date, BigInt, and objects uniformly.
|
|
23
|
-
*/
|
|
24
|
-
export declare function formatValue(value: unknown): string;
|