@walkthru-earth/objex 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/components/browser/FileBrowser.svelte +25 -14
- package/dist/components/browser/FileTreeSidebar.svelte +42 -6
- package/dist/components/layout/ConnectionDialog.svelte +100 -1
- package/dist/components/layout/Sidebar.svelte +43 -25
- package/dist/components/viewers/CodeViewer.svelte +23 -0
- package/dist/components/viewers/CogControls.svelte +208 -0
- package/dist/components/viewers/CogControls.svelte.d.ts +12 -0
- package/dist/components/viewers/CogViewer.svelte +353 -1160
- package/dist/components/viewers/CogViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/DatabaseViewer.svelte +345 -37
- package/dist/components/viewers/MarkdownViewer.svelte +1 -1
- package/dist/components/viewers/TableViewer.svelte +123 -41
- package/dist/components/viewers/ZarrMapViewer.svelte +29 -0
- package/dist/components/viewers/ZarrViewer.svelte +1 -4
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +6 -2
- package/dist/file-icons/index.d.ts +1 -1
- package/dist/file-icons/index.js +12 -2
- package/dist/i18n/ar.js +24 -0
- package/dist/i18n/en.js +24 -0
- package/dist/i18n/index.svelte.d.ts +0 -1
- package/dist/i18n/index.svelte.js +0 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/query/engine.d.ts +20 -4
- package/dist/query/index.d.ts +2 -1
- package/dist/query/index.js +1 -0
- package/dist/query/source.d.ts +30 -0
- package/dist/query/source.js +37 -0
- package/dist/query/wasm.d.ts +7 -5
- package/dist/query/wasm.js +138 -85
- package/dist/storage/providers.d.ts +47 -0
- package/dist/storage/providers.js +160 -0
- package/dist/stores/files.svelte.d.ts +1 -2
- package/dist/stores/files.svelte.js +1 -2
- package/dist/stores/tabs.svelte.d.ts +9 -2
- package/dist/stores/tabs.svelte.js +11 -2
- package/dist/types.d.ts +11 -0
- package/dist/utils/cog.d.ts +244 -0
- package/dist/utils/cog.js +1039 -0
- package/dist/utils/deck.d.ts +0 -18
- package/dist/utils/deck.js +0 -36
- package/dist/utils/geometry-type.d.ts +52 -0
- package/dist/utils/geometry-type.js +76 -0
- package/dist/utils/markdown-sql.d.ts +1 -1
- package/dist/utils/markdown-sql.js +3 -4
- package/dist/utils/pmtiles-tile.d.ts +0 -2
- package/dist/utils/pmtiles-tile.js +0 -8
- package/dist/utils/url-state.d.ts +6 -0
- package/dist/utils/url-state.js +34 -26
- package/dist/utils/url.d.ts +13 -9
- package/dist/utils/url.js +16 -25
- package/dist/utils/zarr-tab.d.ts +22 -0
- package/dist/utils/zarr-tab.js +30 -0
- package/dist/utils/zarr.d.ts +0 -2
- package/dist/utils/zarr.js +73 -44
- package/package.json +47 -43
- package/dist/components/ui/tabs/index.d.ts +0 -5
- package/dist/components/ui/tabs/index.js +0 -7
- package/dist/components/ui/tabs/tabs-content.svelte +0 -17
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs-list.svelte +0 -16
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs-trigger.svelte +0 -20
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs.svelte +0 -19
- package/dist/components/ui/tabs/tabs.svelte.d.ts +0 -4
- package/dist/components/viewers/MapViewer.svelte +0 -234
- package/dist/components/viewers/MapViewer.svelte.d.ts +0 -7
- package/dist/components/viewers/StyleEditorOverlay.svelte +0 -27
- package/dist/components/viewers/StyleEditorOverlay.svelte.d.ts +0 -7
|
@@ -266,6 +266,148 @@ export const PROVIDERS = {
|
|
|
266
266
|
schemes: []
|
|
267
267
|
}
|
|
268
268
|
};
|
|
269
|
+
export const CORS_HELP = {
|
|
270
|
+
s3: {
|
|
271
|
+
defaultEnabled: false,
|
|
272
|
+
docsUrl: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/enabling-cors-examples.html',
|
|
273
|
+
note: 'Enable via S3 Console: Bucket > Permissions > CORS, or use the AWS CLI.'
|
|
274
|
+
},
|
|
275
|
+
gcs: {
|
|
276
|
+
defaultEnabled: false,
|
|
277
|
+
docsUrl: 'https://cloud.google.com/storage/docs/using-cors',
|
|
278
|
+
note: 'CORS cannot be configured via the Cloud Console. Use the gcloud CLI.',
|
|
279
|
+
cliSteps: [
|
|
280
|
+
'Create a cors.json file:\n[\n {\n "origin": ["*"],\n "method": ["GET", "HEAD"],\n "responseHeader": [\n "Content-Type",\n "Content-Length",\n "Content-Range",\n "Accept-Ranges",\n "ETag"\n ],\n "maxAgeSeconds": 3600\n }\n]',
|
|
281
|
+
'gcloud storage buckets update gs://BUCKET --cors-file=cors.json'
|
|
282
|
+
]
|
|
283
|
+
},
|
|
284
|
+
r2: {
|
|
285
|
+
defaultEnabled: false,
|
|
286
|
+
docsUrl: 'https://developers.cloudflare.com/r2/buckets/cors/',
|
|
287
|
+
note: 'Enable via R2 Dashboard: Bucket > Settings > CORS Policy.'
|
|
288
|
+
},
|
|
289
|
+
azure: {
|
|
290
|
+
defaultEnabled: false,
|
|
291
|
+
docsUrl: 'https://learn.microsoft.com/en-us/rest/api/storageservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services',
|
|
292
|
+
note: 'Enable via Azure Portal: Storage Account > Blob Service > CORS, or use the Azure CLI.',
|
|
293
|
+
cliSteps: [
|
|
294
|
+
'az storage cors add --services b --methods GET HEAD \\\n --origins "*" --allowed-headers "*" \\\n --exposed-headers "*" --max-age 3600 \\\n --account-name ACCOUNT'
|
|
295
|
+
]
|
|
296
|
+
},
|
|
297
|
+
minio: {
|
|
298
|
+
defaultEnabled: true,
|
|
299
|
+
docsUrl: 'https://docs.min.io/enterprise/aistor-object-store/reference/cli/mc-cors/',
|
|
300
|
+
note: 'MinIO allows all origins by default. For custom rules, use mc cors set.'
|
|
301
|
+
},
|
|
302
|
+
storj: {
|
|
303
|
+
defaultEnabled: true,
|
|
304
|
+
note: 'Storj S3 gateway returns CORS headers by default.'
|
|
305
|
+
},
|
|
306
|
+
b2: {
|
|
307
|
+
defaultEnabled: false,
|
|
308
|
+
docsUrl: 'https://www.backblaze.com/docs/cloud-storage-cross-origin-resource-sharing-rules',
|
|
309
|
+
note: 'Enable via B2 Console: Bucket Settings > CORS Rules, or use the B2 CLI.',
|
|
310
|
+
cliSteps: [
|
|
311
|
+
'b2 bucket update --cors-rules \'[{\n "corsRuleName": "allow-all",\n "allowedOrigins": ["*"],\n "allowedOperations": ["s3_head", "s3_get"],\n "allowedHeaders": ["*"],\n "maxAgeSeconds": 3600\n}]\' BUCKET allPublic'
|
|
312
|
+
]
|
|
313
|
+
},
|
|
314
|
+
digitalocean: {
|
|
315
|
+
defaultEnabled: false,
|
|
316
|
+
docsUrl: 'https://docs.digitalocean.com/products/spaces/how-to/configure-cors/',
|
|
317
|
+
note: 'Enable via Control Panel: Space > Settings > CORS Configurations.'
|
|
318
|
+
},
|
|
319
|
+
wasabi: {
|
|
320
|
+
defaultEnabled: true,
|
|
321
|
+
docsUrl: 'https://docs.wasabi.com/docs/bucket-policy',
|
|
322
|
+
note: 'Wasabi returns CORS headers by default for all buckets.'
|
|
323
|
+
},
|
|
324
|
+
contabo: {
|
|
325
|
+
defaultEnabled: false,
|
|
326
|
+
note: 'S3-compatible CORS via the AWS CLI.',
|
|
327
|
+
cliSteps: [
|
|
328
|
+
'Create a cors.json file:\n{\n "CORSRules": [{\n "AllowedOrigins": ["*"],\n "AllowedMethods": ["GET", "HEAD"],\n "AllowedHeaders": ["*"],\n "ExposeHeaders": ["ETag", "Content-Length", "Content-Type", "Content-Range", "Accept-Ranges"],\n "MaxAgeSeconds": 3600\n }]\n}',
|
|
329
|
+
'aws s3api put-bucket-cors --bucket BUCKET \\\n --cors-configuration file://cors.json \\\n --endpoint-url https://REGION.contaboobj.com'
|
|
330
|
+
]
|
|
331
|
+
},
|
|
332
|
+
hetzner: {
|
|
333
|
+
defaultEnabled: false,
|
|
334
|
+
docsUrl: 'https://docs.hetzner.com/storage/object-storage/howto-protect-objects/cors/',
|
|
335
|
+
note: 'S3-compatible CORS via the AWS CLI.',
|
|
336
|
+
cliSteps: [
|
|
337
|
+
'Create a cors.json file:\n{\n "CORSRules": [{\n "AllowedOrigins": ["*"],\n "AllowedMethods": ["GET", "HEAD"],\n "AllowedHeaders": ["*"],\n "ExposeHeaders": ["ETag", "Content-Length", "Content-Type", "Content-Range", "Accept-Ranges"],\n "MaxAgeSeconds": 3600\n }]\n}',
|
|
338
|
+
'aws s3api put-bucket-cors --bucket BUCKET \\\n --cors-configuration file://cors.json \\\n --endpoint-url https://REGION.your-objectstorage.com \\\n --region REGION'
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
linode: {
|
|
342
|
+
defaultEnabled: false,
|
|
343
|
+
docsUrl: 'https://www.linode.com/docs/guides/working-with-cors-linode-object-storage/',
|
|
344
|
+
note: 'S3-compatible CORS via the AWS CLI.',
|
|
345
|
+
cliSteps: [
|
|
346
|
+
'Create a cors.json file:\n{\n "CORSRules": [{\n "AllowedOrigins": ["*"],\n "AllowedMethods": ["GET", "HEAD"],\n "AllowedHeaders": ["*"],\n "ExposeHeaders": ["ETag", "Content-Length", "Content-Type", "Content-Range", "Accept-Ranges"],\n "MaxAgeSeconds": 3600\n }]\n}',
|
|
347
|
+
'aws s3api put-bucket-cors --bucket BUCKET \\\n --cors-configuration file://cors.json \\\n --endpoint-url https://REGION.linodeobjects.com'
|
|
348
|
+
]
|
|
349
|
+
},
|
|
350
|
+
ovhcloud: {
|
|
351
|
+
defaultEnabled: false,
|
|
352
|
+
docsUrl: 'https://help.ovhcloud.com/csm/en-public-cloud-storage-s3-cors?id=kb_article_view&sysparm_article=KB0058291',
|
|
353
|
+
note: 'S3-compatible CORS via the AWS CLI.',
|
|
354
|
+
cliSteps: [
|
|
355
|
+
'Create a cors.json file:\n{\n "CORSRules": [{\n "AllowedOrigins": ["*"],\n "AllowedMethods": ["GET", "HEAD"],\n "AllowedHeaders": ["*"],\n "ExposeHeaders": ["ETag", "Content-Length", "Content-Type", "Content-Range", "Accept-Ranges"],\n "MaxAgeSeconds": 3600\n }]\n}',
|
|
356
|
+
'aws s3api put-bucket-cors --bucket BUCKET \\\n --cors-configuration file://cors.json \\\n --endpoint-url https://s3.REGION.io.cloud.ovh.net'
|
|
357
|
+
]
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
export const READ_ONLY_HELP = {
|
|
361
|
+
s3: {
|
|
362
|
+
note: 'Use IAM policies to create a read-only user, or apply a bucket policy that allows only s3:GetObject and s3:ListBucket.',
|
|
363
|
+
docsUrl: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-policies-s3.html'
|
|
364
|
+
},
|
|
365
|
+
gcs: {
|
|
366
|
+
note: 'Assign the Storage Object Viewer role (roles/storage.objectViewer) to the service account.',
|
|
367
|
+
docsUrl: 'https://cloud.google.com/storage/docs/access-control/iam-roles'
|
|
368
|
+
},
|
|
369
|
+
r2: {
|
|
370
|
+
note: 'Create an API token with Object Read permissions in the R2 dashboard.',
|
|
371
|
+
docsUrl: 'https://developers.cloudflare.com/r2/api/tokens/'
|
|
372
|
+
},
|
|
373
|
+
azure: {
|
|
374
|
+
note: 'Generate a SAS token with Read and List permissions only. Avoid granting Write or Delete.',
|
|
375
|
+
docsUrl: 'https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview'
|
|
376
|
+
},
|
|
377
|
+
b2: {
|
|
378
|
+
note: 'Create an application key with readFiles and listBuckets capabilities only.',
|
|
379
|
+
docsUrl: 'https://www.backblaze.com/docs/cloud-storage-application-keys'
|
|
380
|
+
},
|
|
381
|
+
hetzner: {
|
|
382
|
+
note: 'Keys have full read/write by default. Use a bucket policy with the correct ARN format to deny write and policy actions. To undo, generate a new admin key from the Hetzner Console.',
|
|
383
|
+
docsUrl: 'https://docs.hetzner.com/storage/object-storage/faq/s3-credentials/#how-do-i-restrict-access-per-key',
|
|
384
|
+
cliSteps: [
|
|
385
|
+
'Find your project ID from the Hetzner Console URL:\nhttps://console.hetzner.com/projects/<PROJECT_ID>/servers',
|
|
386
|
+
'Create a policy.json file:\n{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "DenyWrites",\n "Effect": "Deny",\n "Principal": {\n "AWS": "arn:aws:iam:::user/p<PROJECT_ID>:<ACCESS_KEY>"\n },\n "Action": [\n "s3:PutObject",\n "s3:DeleteObject",\n "s3:AbortMultipartUpload",\n "s3:PutBucketPolicy",\n "s3:DeleteBucketPolicy"\n ],\n "Resource": [\n "arn:aws:s3:::BUCKET",\n "arn:aws:s3:::BUCKET/*"\n ]\n }\n ]\n}',
|
|
387
|
+
'aws s3api put-bucket-policy --bucket BUCKET \\\n --policy file://policy.json \\\n --endpoint-url https://REGION.your-objectstorage.com \\\n --region REGION',
|
|
388
|
+
'Note: This key can no longer modify the policy.\nTo restore write access, generate a new key in the\nHetzner Console and use it to delete the policy.'
|
|
389
|
+
]
|
|
390
|
+
},
|
|
391
|
+
minio: {
|
|
392
|
+
note: 'Create a read-only policy with mc admin policy, or use the built-in readonly canned policy.',
|
|
393
|
+
docsUrl: 'https://docs.min.io/enterprise/aistor-object-store/administration/iam/access/'
|
|
394
|
+
},
|
|
395
|
+
digitalocean: {
|
|
396
|
+
note: 'Spaces keys are project-wide. Use a bucket policy to restrict write actions for a specific key.',
|
|
397
|
+
docsUrl: 'https://docs.digitalocean.com/products/spaces/how-to/manage-access/'
|
|
398
|
+
},
|
|
399
|
+
wasabi: {
|
|
400
|
+
note: 'Create a sub-user with a read-only policy in the Wasabi Console.',
|
|
401
|
+
docsUrl: 'https://docs.wasabi.com/docs/creating-a-user-account-and-access-key'
|
|
402
|
+
},
|
|
403
|
+
contabo: {
|
|
404
|
+
note: 'S3-compatible bucket policies. Use a Deny policy for write actions with the key ARN.',
|
|
405
|
+
cliSteps: [
|
|
406
|
+
'Create a policy.json with a Deny statement for s3:PutObject and s3:DeleteObject.',
|
|
407
|
+
'aws s3api put-bucket-policy --bucket BUCKET \\\n --policy file://policy.json \\\n --endpoint-url https://REGION.contaboobj.com'
|
|
408
|
+
]
|
|
409
|
+
}
|
|
410
|
+
};
|
|
269
411
|
// ---------------------------------------------------------------------------
|
|
270
412
|
// Helpers
|
|
271
413
|
// ---------------------------------------------------------------------------
|
|
@@ -316,3 +458,21 @@ export function buildProviderBaseUrl(provider, endpoint, bucket, region) {
|
|
|
316
458
|
export function isGcsProvider(provider, endpoint) {
|
|
317
459
|
return provider === 'gcs' || (!!endpoint && /storage\.googleapis\.com/i.test(endpoint));
|
|
318
460
|
}
|
|
461
|
+
export function getAccessMode(conn) {
|
|
462
|
+
if (conn.provider === 'azure')
|
|
463
|
+
return 'sas-https';
|
|
464
|
+
// Anonymous buckets: every provider serves files over plain HTTPS without
|
|
465
|
+
// signing (AWS path/vhost, GCS, R2 public, Storj, Wasabi, DO, etc.).
|
|
466
|
+
if (conn.anonymous)
|
|
467
|
+
return 'public-https';
|
|
468
|
+
// Authenticated: needs SigV4 signing.
|
|
469
|
+
return 'signed-s3';
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* True when the connection's files can be fetched by any HTTP client
|
|
473
|
+
* (fetch/img/video/DuckDB httpfs/COG/Zarr/etc.) without the storage adapter.
|
|
474
|
+
*/
|
|
475
|
+
export function isPubliclyStreamable(conn) {
|
|
476
|
+
const mode = getAccessMode(conn);
|
|
477
|
+
return mode === 'public-https' || mode === 'sas-https';
|
|
478
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FileEntry } from '../types.js';
|
|
2
2
|
import { type SortConfig, type SortField } from '../utils/file-sort.js';
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const files: {
|
|
4
4
|
readonly entries: FileEntry[];
|
|
5
5
|
readonly currentPath: string;
|
|
6
6
|
readonly loading: boolean;
|
|
@@ -12,4 +12,3 @@ export declare const fileStore: {
|
|
|
12
12
|
setError(message: string | null): void;
|
|
13
13
|
sort(field: SortField): void;
|
|
14
14
|
};
|
|
15
|
-
export { fileStore as files };
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { Tab } from '../types.js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Tab-id for eagerly-opened direct-URL tabs (`source: 'url'`).
|
|
4
|
+
* The Sidebar's host-detection auto-migration closes an eager tab by its id
|
|
5
|
+
* and re-opens as a remote tab once a connection is available; the eager id
|
|
6
|
+
* is built in `+page.svelte::openUrlTab` and matched in `Sidebar.svelte::
|
|
7
|
+
* handleAutoDetection`, so both sides must agree on the format.
|
|
8
|
+
*/
|
|
9
|
+
export declare function eagerUrlTabId(url: string): string;
|
|
10
|
+
export declare const tabs: {
|
|
3
11
|
readonly items: Tab[];
|
|
4
12
|
readonly activeTabId: string | null;
|
|
5
13
|
readonly active: Tab | undefined;
|
|
@@ -14,4 +22,3 @@ export declare const tabStore: {
|
|
|
14
22
|
setActive(id: string): void;
|
|
15
23
|
update(id: string, partial: Partial<Omit<Tab, "id">>): void;
|
|
16
24
|
};
|
|
17
|
-
export { tabStore as tabs };
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { tabResources } from './tab-resources.svelte.js';
|
|
2
2
|
/** Maximum number of viewer instances kept alive (mounted but hidden). */
|
|
3
3
|
const MAX_ALIVE = 5;
|
|
4
|
+
/**
|
|
5
|
+
* Tab-id for eagerly-opened direct-URL tabs (`source: 'url'`).
|
|
6
|
+
* The Sidebar's host-detection auto-migration closes an eager tab by its id
|
|
7
|
+
* and re-opens as a remote tab once a connection is available; the eager id
|
|
8
|
+
* is built in `+page.svelte::openUrlTab` and matched in `Sidebar.svelte::
|
|
9
|
+
* handleAutoDetection`, so both sides must agree on the format.
|
|
10
|
+
*/
|
|
11
|
+
export function eagerUrlTabId(url) {
|
|
12
|
+
return `url:${url}`;
|
|
13
|
+
}
|
|
4
14
|
function releaseDuckDbMemory() {
|
|
5
15
|
import('../query/index.js')
|
|
6
16
|
.then(({ getQueryEngine }) => getQueryEngine().then((engine) => engine.releaseMemory()))
|
|
@@ -106,5 +116,4 @@ function createTabsStore() {
|
|
|
106
116
|
}
|
|
107
117
|
};
|
|
108
118
|
}
|
|
109
|
-
export const
|
|
110
|
-
export { tabStore as tabs };
|
|
119
|
+
export const tabs = createTabsStore();
|
package/dist/types.d.ts
CHANGED
|
@@ -38,6 +38,17 @@ export interface Tab {
|
|
|
38
38
|
connectionId?: string;
|
|
39
39
|
extension: string;
|
|
40
40
|
size?: number;
|
|
41
|
+
/**
|
|
42
|
+
* When set, the tab reads data from a SQL FROM-clause target (e.g. an
|
|
43
|
+
* attached DuckLake/DuckDB/SQLite table) rather than a file URL. The ref
|
|
44
|
+
* is inserted directly into generated SQL, so it must be fully-qualified
|
|
45
|
+
* and pre-quoted, e.g. `__objex_db__."main"."air_quality"`.
|
|
46
|
+
*
|
|
47
|
+
* When `sourceRef` is set, file-specific loading paths (hyparquet
|
|
48
|
+
* metadata, `parquet_kv_metadata`, etc.) are skipped, and schema / CRS /
|
|
49
|
+
* row count are derived from the SQL source directly via DuckDB.
|
|
50
|
+
*/
|
|
51
|
+
sourceRef?: string;
|
|
41
52
|
}
|
|
42
53
|
export interface WriteResult {
|
|
43
54
|
key: string;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import type { GetTileDataOptions, MinimalDataT } from '@developmentseed/deck.gl-geotiff';
|
|
2
|
+
import type { RenderTileResult } from '@developmentseed/deck.gl-raster';
|
|
3
|
+
import type { GeoTIFF as GeoTIFFType, Overview } from '@developmentseed/geotiff';
|
|
4
|
+
import { GeoTIFF } from '@developmentseed/geotiff';
|
|
5
|
+
import type { EpsgResolver } from '@developmentseed/proj';
|
|
6
|
+
import type maplibregl from 'maplibre-gl';
|
|
7
|
+
/** SampleFormat tag value → human label. */
|
|
8
|
+
export declare const SF_LABELS: Record<number, string>;
|
|
9
|
+
export type ColorRampId = 'grayscale' | 'terrain' | 'viridis' | 'magma' | 'turbo' | 'spectral';
|
|
10
|
+
export declare const COLOR_RAMP_STOPS: Record<ColorRampId, [number, number, number][]>;
|
|
11
|
+
/** Interpolate a normalized value (0..1) into an RGB color from a ramp. */
|
|
12
|
+
export declare function interpolateRamp(stops: [number, number, number][], t: number): [number, number, number];
|
|
13
|
+
/** Generate a CSS linear-gradient string for a color ramp. */
|
|
14
|
+
export declare function rampToGradientCss(id: ColorRampId): string;
|
|
15
|
+
export interface BandConfig {
|
|
16
|
+
mode: 'rgb' | 'single';
|
|
17
|
+
/** 0-indexed band indices for RGB channels */
|
|
18
|
+
rBand: number;
|
|
19
|
+
gBand: number;
|
|
20
|
+
bBand: number;
|
|
21
|
+
/** 0-indexed band index for single-band mode */
|
|
22
|
+
band: number;
|
|
23
|
+
colorRamp: ColorRampId;
|
|
24
|
+
}
|
|
25
|
+
/** Create a sensible default band config based on COG metadata. */
|
|
26
|
+
export declare function defaultBandConfig(bandCount: number, sampleFormat: number): BandConfig;
|
|
27
|
+
/** Check if the config matches the default for this COG (no user changes). */
|
|
28
|
+
export declare function isDefaultBandConfig(config: BandConfig, bandCount: number, sampleFormat: number): boolean;
|
|
29
|
+
export interface CogTagInfo {
|
|
30
|
+
/** TIFF SampleFormat[0] value. 1=uint, 2=int, 3=float. Defaults to 1 when absent. */
|
|
31
|
+
sampleFormat: number;
|
|
32
|
+
/** True when SampleFormat[0] === 1 (unsigned integer). */
|
|
33
|
+
isUint: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* True when Photometric === 3 (Palette) and the ColorMap tag is present.
|
|
36
|
+
* These COGs should defer to the library's default Colormap GPU module,
|
|
37
|
+
* not our custom JS pipeline, so the embedded palette renders correctly.
|
|
38
|
+
*/
|
|
39
|
+
isPaletteIndexed: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Inspect the TIFF tags that drive pipeline selection. Centralizes the
|
|
43
|
+
* Photometric.Palette === 3 magic number and the SampleFormat fallback in one
|
|
44
|
+
* place so viewers don't reimplement raw tag reads. Photometric values come
|
|
45
|
+
* from the @cogeotiff/core Photometric enum.
|
|
46
|
+
*/
|
|
47
|
+
export declare function inspectCogTags(geotiff: GeoTIFFType): CogTagInfo;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a given band config requires a custom pipeline (vs library default).
|
|
50
|
+
* Library default only works for uint with standard RGB band order, or for
|
|
51
|
+
* palette-indexed uint COGs where the embedded ColorMap tag auto-renders.
|
|
52
|
+
*/
|
|
53
|
+
export declare function needsCustomPipelineForConfig(geotiff: GeoTIFFType, config: BandConfig): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Min/max rescale values applied via the `LinearRescale` shader module. Values
|
|
56
|
+
* are in normalized shader space [0, 1]. Default `{ min: 0, max: 1 }` is a
|
|
57
|
+
* no-op and the library-default pipeline is used as-is.
|
|
58
|
+
*/
|
|
59
|
+
export interface RescaleConfig {
|
|
60
|
+
min: number;
|
|
61
|
+
max: number;
|
|
62
|
+
}
|
|
63
|
+
export declare const DEFAULT_RESCALE: RescaleConfig;
|
|
64
|
+
/** True when the rescale values would produce a visible change on the GPU. */
|
|
65
|
+
export declare function isRescaleActive(cfg: RescaleConfig): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Build a `getTileData` + `renderTile` pair that reuses the library-default
|
|
68
|
+
* uint pipeline (via `inferRenderPipeline`) and appends `LinearRescale` to the
|
|
69
|
+
* returned render pipeline. Only safe to use when the default pipeline would
|
|
70
|
+
* have been chosen anyway, i.e. `needsCustomPipelineForConfig(geotiff, cfg)`
|
|
71
|
+
* is false. For non-uint or custom band configs the custom JS pipeline already
|
|
72
|
+
* bakes RGBA in CPU and a GPU rescale would be cosmetic.
|
|
73
|
+
*
|
|
74
|
+
* `inferRenderPipeline` needs the GPU `Device` which arrives in the first
|
|
75
|
+
* tile's `GetTileDataOptions`, so the pipeline is built lazily on first call.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createRescaledPipeline(geotiff: GeoTIFFType, rescale: RescaleConfig): {
|
|
78
|
+
getTileData: (image: GeoTIFFType | Overview, options: GetTileDataOptions) => Promise<MinimalDataT>;
|
|
79
|
+
renderTile: (data: MinimalDataT) => RenderTileResult;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Apply the two upstream-bug workarounds a GeoTIFF needs before being handed
|
|
83
|
+
* to `COGLayer`:
|
|
84
|
+
* 1. Strip oversized overviews (image smaller than tile size). These produce
|
|
85
|
+
* out-of-domain proj4 NaN during pre-flight reprojection.
|
|
86
|
+
* 2. Clamp EPSG:4326 bbox to Web Mercator's safe range. Global 4326 COGs with
|
|
87
|
+
* ±90° extents crash the tile matrix generator.
|
|
88
|
+
*
|
|
89
|
+
* Mutates the GeoTIFF in place. Safe to call repeatedly. Kept out of the
|
|
90
|
+
* Svelte component so MultiCOG/Mosaic can apply the same fix per sub-COG.
|
|
91
|
+
*/
|
|
92
|
+
export declare function normalizeCogGeotiff(geotiff: GeoTIFFType): void;
|
|
93
|
+
/**
|
|
94
|
+
* Resolved COGLayer data props. Empty object means "library default pipeline".
|
|
95
|
+
* Spread into `new COGLayer({ ..., ...resolved })` to activate.
|
|
96
|
+
*
|
|
97
|
+
* COGLayer's data-prop types are a discriminated XOR and the four pipelines we
|
|
98
|
+
* dispatch to return different DataT shapes (`CustomTileData`, `MinimalDataT`).
|
|
99
|
+
* Typing this as `Record<string, any>` matches the `customProps` pattern
|
|
100
|
+
* already used at the COGLayer boundary and keeps the dispatch site simple.
|
|
101
|
+
*/
|
|
102
|
+
export type ResolvedCogPipeline = Record<string, any>;
|
|
103
|
+
export interface SelectCogPipelineOptions {
|
|
104
|
+
/** Active band/color config, or null/undefined when not yet resolved. */
|
|
105
|
+
bandConfig?: BandConfig | null;
|
|
106
|
+
/** Linear rescale GPU module values. No-op when omitted or at defaults. */
|
|
107
|
+
rescale?: RescaleConfig;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Decide which getTileData/renderTile pair COGLayer should use for a GeoTIFF.
|
|
111
|
+
* Four outcomes, in priority order:
|
|
112
|
+
*
|
|
113
|
+
* 1. Custom configurable (band swap, color ramp) — when bandConfig is active
|
|
114
|
+
* and needsCustomPipelineForConfig is true (non-uint, mode=single, or
|
|
115
|
+
* non-standard RGB band order).
|
|
116
|
+
* 2. Custom non-uint (Int/Float source) — when no bandConfig yet but the
|
|
117
|
+
* GeoTIFF itself forces custom handling.
|
|
118
|
+
* 3. Library default + LinearRescale — uint path is fine AND the user moved
|
|
119
|
+
* the rescale slider away from defaults.
|
|
120
|
+
* 4. Library default — returns `{}`, caller spreads into COGLayer props.
|
|
121
|
+
*
|
|
122
|
+
* Pure dispatch. Kept separate from the Svelte component so MultiCOG/Mosaic
|
|
123
|
+
* viewers can call it per sub-COG without re-implementing the decision tree.
|
|
124
|
+
*/
|
|
125
|
+
export declare function selectCogPipeline(geotiff: GeoTIFFType, opts?: SelectCogPipelineOptions): ResolvedCogPipeline;
|
|
126
|
+
export interface GeoBounds {
|
|
127
|
+
west: number;
|
|
128
|
+
south: number;
|
|
129
|
+
east: number;
|
|
130
|
+
north: number;
|
|
131
|
+
}
|
|
132
|
+
export interface CogInfo {
|
|
133
|
+
width: number;
|
|
134
|
+
height: number;
|
|
135
|
+
bandCount: number;
|
|
136
|
+
dataType: string;
|
|
137
|
+
bounds: GeoBounds;
|
|
138
|
+
downsampled?: boolean;
|
|
139
|
+
}
|
|
140
|
+
/** Safely clamp a number to a range, treating NaN/Infinity as the fallback. */
|
|
141
|
+
export declare function safeClamp(v: number, lo: number, hi: number, fallback: number): number;
|
|
142
|
+
/** Clamp geographic bounds to valid MapLibre web-Mercator range. */
|
|
143
|
+
export declare function clampBounds(b: GeoBounds): GeoBounds;
|
|
144
|
+
/**
|
|
145
|
+
* Build a data-type label from GeoTIFF sample format and bits per sample.
|
|
146
|
+
* e.g. "uint8", "float32", "int16"
|
|
147
|
+
*/
|
|
148
|
+
export declare function buildDataTypeLabel(sampleFormat: number, bitsPerSample: number): string;
|
|
149
|
+
/**
|
|
150
|
+
* Query the GPU's MAX_TEXTURE_SIZE from MapLibre's WebGL context.
|
|
151
|
+
* Falls back to 4096 (lowest common denominator for mobile GPUs).
|
|
152
|
+
*/
|
|
153
|
+
export declare function getMaxTextureSize(map: maplibregl.Map): number;
|
|
154
|
+
/**
|
|
155
|
+
* Fit the map to COG bounds with responsive padding.
|
|
156
|
+
* Uses smaller padding on mobile to zoom in closer, ensuring overviews load
|
|
157
|
+
* properly instead of appearing black at very low zoom levels.
|
|
158
|
+
* After fitting, bumps zoom +2 when the viewport settles at a very low level.
|
|
159
|
+
*/
|
|
160
|
+
export declare function fitCogBounds(map: maplibregl.Map, b: GeoBounds): void;
|
|
161
|
+
/** Remove the native bitmap source/layer from the map (idempotent). */
|
|
162
|
+
export declare function cleanupNativeBitmap(map: maplibregl.Map): void;
|
|
163
|
+
/**
|
|
164
|
+
* Render a non-tiled GeoTIFF as a MapLibre native image source (bitmap).
|
|
165
|
+
* Opens the file with @developmentseed/geotiff, reads band 0, normalizes
|
|
166
|
+
* to grayscale RGBA, and adds to the map as a raster layer.
|
|
167
|
+
*
|
|
168
|
+
* Returns CogInfo for the metadata panel.
|
|
169
|
+
*/
|
|
170
|
+
export declare function renderNonTiledBitmap(options: {
|
|
171
|
+
url: string;
|
|
172
|
+
map: maplibregl.Map;
|
|
173
|
+
signal: AbortSignal;
|
|
174
|
+
geotiff?: GeoTIFF;
|
|
175
|
+
}): Promise<CogInfo>;
|
|
176
|
+
/** Result type returned by our custom getTileData. */
|
|
177
|
+
export interface CustomTileData {
|
|
178
|
+
imageData: ImageData;
|
|
179
|
+
width: number;
|
|
180
|
+
height: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Check whether a GeoTIFF needs a custom render pipeline.
|
|
184
|
+
* v0.3's inferRenderPipeline only supports unsigned integers (SampleFormat 1).
|
|
185
|
+
* Signed int (2) and float (3) need custom getTileData/renderTile.
|
|
186
|
+
*/
|
|
187
|
+
export declare function needsCustomPipeline(geotiff: GeoTIFFType): boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Create custom getTileData for non-uint COGs.
|
|
190
|
+
* Reads band 0, normalizes using GDAL statistics / per-tile adaptive stretch,
|
|
191
|
+
* applies terrain color ramp for single-band data.
|
|
192
|
+
*/
|
|
193
|
+
export declare function createCustomGetTileData(geotiff: GeoTIFFType): (image: GeoTIFFType | Overview, options: {
|
|
194
|
+
x: number;
|
|
195
|
+
y: number;
|
|
196
|
+
pool: unknown;
|
|
197
|
+
signal?: AbortSignal;
|
|
198
|
+
}) => Promise<CustomTileData>;
|
|
199
|
+
/**
|
|
200
|
+
* Custom renderTile for non-uint COGs.
|
|
201
|
+
* v0.5 RasterLayer requires a RenderTileResult with `image` or `renderPipeline`.
|
|
202
|
+
* We produce an ImageData and pass it through the `image` slot. deck.gl manages
|
|
203
|
+
* the texture lifecycle and prepends a CreateTexture module automatically.
|
|
204
|
+
*/
|
|
205
|
+
export declare function customRenderTile(data: CustomTileData): {
|
|
206
|
+
image: ImageData;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Create a configurable getTileData that respects BandConfig.
|
|
210
|
+
* Supports both RGB mode (multi-band → R,G,B) and single-band mode (color ramp).
|
|
211
|
+
*/
|
|
212
|
+
export declare function createConfigurableGetTileData(geotiff: GeoTIFFType, config: BandConfig): (image: GeoTIFFType | Overview, options: {
|
|
213
|
+
x: number;
|
|
214
|
+
y: number;
|
|
215
|
+
pool: unknown;
|
|
216
|
+
signal?: AbortSignal;
|
|
217
|
+
}) => Promise<CustomTileData>;
|
|
218
|
+
export interface PixelValue {
|
|
219
|
+
lng: number;
|
|
220
|
+
lat: number;
|
|
221
|
+
values: number[];
|
|
222
|
+
row: number;
|
|
223
|
+
col: number;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Create an async EPSG resolver for `@developmentseed/deck.gl-geotiff`.
|
|
227
|
+
* Looks up the numeric EPSG code in the bundled WKT database and returns the
|
|
228
|
+
* `ProjectionDefinition` produced by `parseWkt`. Throws a clear error when the
|
|
229
|
+
* code is not present in the database.
|
|
230
|
+
*/
|
|
231
|
+
export declare function createEpsgResolver(): EpsgResolver;
|
|
232
|
+
/**
|
|
233
|
+
* Resolve a proj4-compatible definition for a CRS read from a GeoTIFF.
|
|
234
|
+
* For numeric EPSG codes this returns the WKT string from the bundled EPSG
|
|
235
|
+
* database, which `proj4()` accepts directly. For ProjJSON it falls back to a
|
|
236
|
+
* JSON string. Returns null for EPSG:4326 (no conversion needed) or when the
|
|
237
|
+
* code is not present in the database.
|
|
238
|
+
*/
|
|
239
|
+
export declare function resolveProj4Def(crs: number | unknown, _signal: AbortSignal): Promise<string | null>;
|
|
240
|
+
/**
|
|
241
|
+
* Read pixel values at a given lng/lat from a GeoTIFF.
|
|
242
|
+
* Converts WGS84 → source CRS → pixel coords, fetches the tile, reads all bands.
|
|
243
|
+
*/
|
|
244
|
+
export declare function readPixelAtLngLat(geotiff: GeoTIFFType, lng: number, lat: number, proj4Def: string | null, pool: any, signal?: AbortSignal): Promise<PixelValue | null>;
|