@walkthru-earth/objex-utils 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 +36 -19
- package/dist/index.cjs +3019 -520
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1462 -82
- package/dist/index.d.ts +1462 -82
- package/dist/index.js +2937 -521
- package/dist/index.js.map +1 -1
- package/docs/README.md +17 -6
- package/docs/app-config.md +237 -0
- package/docs/channel-composite.md +127 -0
- package/docs/cog-asset.md +164 -0
- package/docs/cog.md +1 -1
- package/docs/errors.md +1 -1
- package/docs/file-sort.md +1 -1
- package/docs/formatting.md +4 -4
- package/docs/geometry.md +3 -3
- package/docs/local-storage.md +1 -1
- package/docs/lru.md +76 -0
- package/docs/map-pixel-inspect.md +132 -0
- package/docs/markdown-sql.md +1 -1
- package/docs/parquet-metadata.md +1 -1
- package/docs/stac-facets.md +198 -0
- package/docs/stac-hydrate.md +181 -0
- package/docs/stac-pushdown.md +145 -0
- package/docs/stac-source.md +224 -0
- package/docs/stac-storage-extension.md +146 -0
- package/docs/stac.md +425 -0
- package/docs/storage.md +2 -2
- package/package.json +10 -3
package/docs/stac.md
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# stac
|
|
2
|
+
|
|
3
|
+
Core STAC (SpatioTemporal Asset Catalog) types, shape-checks, classifiers, and asset extractors. Pure TypeScript, zero Svelte / DuckDB / deck.gl dependency, framework-agnostic. Shared by `ViewerRouter`, `StacMosaicViewer`, and `MultiCogViewer` in the main package.
|
|
4
|
+
|
|
5
|
+
Source: `packages/objex-utils/src/stac.ts`.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import {
|
|
9
|
+
type StacItem,
|
|
10
|
+
type StacFeatureCollection,
|
|
11
|
+
type StacCollection,
|
|
12
|
+
type StacCatalog,
|
|
13
|
+
type StacAsset,
|
|
14
|
+
type StacLink,
|
|
15
|
+
type StacRoutableKind,
|
|
16
|
+
type MosaicSourceMeta,
|
|
17
|
+
type BandSlot,
|
|
18
|
+
type BandMap,
|
|
19
|
+
type RasterBandAsset,
|
|
20
|
+
STAC_COG_ASSET_KEYS,
|
|
21
|
+
classifyStac,
|
|
22
|
+
isStacItem,
|
|
23
|
+
isStacFeatureCollection,
|
|
24
|
+
isStacCollection,
|
|
25
|
+
isStacCatalog,
|
|
26
|
+
detectMosaicCapable,
|
|
27
|
+
detectMultiCogCapable,
|
|
28
|
+
pickCogAssetHref,
|
|
29
|
+
stacItemBbox,
|
|
30
|
+
buildMosaicSourceMeta,
|
|
31
|
+
spatialCellKey,
|
|
32
|
+
extractSentinelBandAssets,
|
|
33
|
+
hasRgbBands,
|
|
34
|
+
extractRasterBandAssets,
|
|
35
|
+
extractMosaicAssets,
|
|
36
|
+
resolveBandSlotAssetKey,
|
|
37
|
+
resolvePresetComposite,
|
|
38
|
+
hasCompositableBands,
|
|
39
|
+
} from '@walkthru-earth/objex-utils';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Types
|
|
43
|
+
|
|
44
|
+
### `StacLink`
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
interface StacLink {
|
|
48
|
+
rel: string;
|
|
49
|
+
href: string;
|
|
50
|
+
type?: string;
|
|
51
|
+
title?: string;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
A link entry shared by Catalog / Collection / Item. The link-walker in [`stac-hydrate`](./stac-hydrate.md) keys on `rel` (`item`, `child`, `items`, `next`).
|
|
56
|
+
|
|
57
|
+
### `StacItem`
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
interface StacItem {
|
|
61
|
+
type: 'Feature';
|
|
62
|
+
stac_version: string;
|
|
63
|
+
id: string;
|
|
64
|
+
bbox?: [number, number, number, number];
|
|
65
|
+
geometry?: unknown;
|
|
66
|
+
properties?: Record<string, unknown>;
|
|
67
|
+
assets?: Record<string, StacAsset>;
|
|
68
|
+
collection?: string;
|
|
69
|
+
links?: StacLink[];
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A STAC Item is a GeoJSON Feature with a `stac_version`. `geometry` is left `unknown` because this module never parses footprints, the bbox is the only spatial field it reads.
|
|
74
|
+
|
|
75
|
+
### `StacFeatureCollection`
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
interface StacFeatureCollection {
|
|
79
|
+
type: 'FeatureCollection';
|
|
80
|
+
stac_version?: string;
|
|
81
|
+
features: StacItem[];
|
|
82
|
+
links?: StacLink[];
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
A page of Items, also the shape STAC API `/search` and `/items` endpoints return. `stac_version` is optional here because some API responses omit it at the collection level, in which case the first feature is checked instead.
|
|
87
|
+
|
|
88
|
+
### `StacCollection`
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
interface StacCollection {
|
|
92
|
+
type: 'Collection';
|
|
93
|
+
stac_version: string;
|
|
94
|
+
id: string;
|
|
95
|
+
description?: string;
|
|
96
|
+
extent?: { spatial?: { bbox?: number[][] }; temporal?: unknown };
|
|
97
|
+
links: StacLink[];
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
A grouping of Items with its own metadata and a required `links` array.
|
|
102
|
+
|
|
103
|
+
### `StacCatalog`
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
interface StacCatalog {
|
|
107
|
+
type: 'Catalog';
|
|
108
|
+
stac_version: string;
|
|
109
|
+
id: string;
|
|
110
|
+
description?: string;
|
|
111
|
+
links: StacLink[];
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
A directory-like grouping of Catalogs / Collections / Items via `links`.
|
|
116
|
+
|
|
117
|
+
### `StacAsset`
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
interface StacAsset {
|
|
121
|
+
href: string;
|
|
122
|
+
type?: string;
|
|
123
|
+
title?: string;
|
|
124
|
+
roles?: string[];
|
|
125
|
+
'eo:bands'?: { name?: string; common_name?: string }[];
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
A single asset entry within an Item. `'eo:bands'` is populated when the asset carries the EO extension band metadata, the extractors read `eo:bands[0].common_name` to map an asset to a band slot.
|
|
130
|
+
|
|
131
|
+
### `BandSlot`
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
type BandSlot = 'red' | 'green' | 'blue' | 'nir' | 'swir1' | 'swir2' | 'rededge';
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
A Sentinel-2-style band slot identifier, shared with the composite helpers in the app-side `utils/cog.ts`.
|
|
138
|
+
|
|
139
|
+
### `BandMap`
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
type BandMap = Partial<Record<BandSlot, string>>;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Parsed band map, each slot maps to an absolute HTTPS asset URL. Returned by `extractSentinelBandAssets`.
|
|
146
|
+
|
|
147
|
+
### `StacRoutableKind`
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
type StacRoutableKind =
|
|
151
|
+
| { kind: 'item'; item: StacItem }
|
|
152
|
+
| { kind: 'item-collection'; fc: StacFeatureCollection }
|
|
153
|
+
| { kind: 'collection'; payload: StacCollection }
|
|
154
|
+
| { kind: 'catalog'; payload: StacCatalog }
|
|
155
|
+
| { kind: 'none' };
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The routing verdict returned by `classifyStac`. The `kind: 'none'` variant carries no payload and signals the JSON is not STAC-shaped.
|
|
159
|
+
|
|
160
|
+
### `MosaicSourceMeta`
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
interface MosaicSourceMeta {
|
|
164
|
+
id: string;
|
|
165
|
+
bbox: [number, number, number, number];
|
|
166
|
+
href: string;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
A normalized mosaic source entry, the minimal shape deck.gl-geotiff's `MosaicLayer` consumes. Returned by `buildMosaicSourceMeta`.
|
|
171
|
+
|
|
172
|
+
### `RasterBandAsset`
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
interface RasterBandAsset {
|
|
176
|
+
key: string;
|
|
177
|
+
href: string;
|
|
178
|
+
commonName?: string;
|
|
179
|
+
bandCount?: number;
|
|
180
|
+
roles?: string[];
|
|
181
|
+
mediaType?: string;
|
|
182
|
+
title?: string;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
A vendor-neutral raster band asset description carrying the bits a MultiCOG band picker needs to populate dropdowns and resolve presets. `key` is the STAC asset key exactly as it appears in `item.assets` (`red`, `B04`, `image`, `analytic`, ...), it lines up 1:1 with `MultiCOGLayer.sources`'s record key. Returned by `extractRasterBandAssets` and `extractMosaicAssets`.
|
|
187
|
+
|
|
188
|
+
## Constants
|
|
189
|
+
|
|
190
|
+
### `STAC_COG_ASSET_KEYS`
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const STAC_COG_ASSET_KEYS = ['visual', 'image', 'data', 'rendered_preview'] as const;
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Asset keys providers use for the single "display COG" asset, in priority order. `pickCogAssetHref` scans these after any caller-preferred key.
|
|
197
|
+
|
|
198
|
+
## Functions
|
|
199
|
+
|
|
200
|
+
### `isStacItem(json)`
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
function isStacItem(json: unknown): json is StacItem;
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Shape-check: true when `json.type === 'Feature'` and `json.stac_version` is a string. Type guard.
|
|
207
|
+
|
|
208
|
+
### `isStacFeatureCollection(json)`
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
function isStacFeatureCollection(json: unknown): json is StacFeatureCollection;
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
True when `json.type === 'FeatureCollection'` with a non-empty `features` array. A `stac_version` string passes immediately, otherwise the first feature is run through `isStacItem`. Empty `features` returns false. Type guard.
|
|
215
|
+
|
|
216
|
+
### `isStacCollection(json)`
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
function isStacCollection(json: unknown): json is StacCollection;
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
True when `json.type === 'Collection'` with a `stac_version` string and a `links` array. Type guard.
|
|
223
|
+
|
|
224
|
+
### `isStacCatalog(json)`
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
function isStacCatalog(json: unknown): json is StacCatalog;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
True when `json.type === 'Catalog'` with a `stac_version` string and a `links` array. Type guard.
|
|
231
|
+
|
|
232
|
+
### `classifyStac(json)`
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
function classifyStac(json: unknown): StacRoutableKind;
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Classify arbitrary parsed JSON into one of the STAC routing buckets. Checks in order: Item, FeatureCollection (item-collection), Collection, Catalog, falling back to `{ kind: 'none' }`. This is the entry point that decides which viewer or `StacSource` implementation to build.
|
|
239
|
+
|
|
240
|
+
### `pickCogAssetHref(item, preferred?)`
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
function pickCogAssetHref(item: StacItem, preferred?: string): string | null;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Pick the COG-ish asset href from an Item. Priority:
|
|
247
|
+
|
|
248
|
+
1. The named asset under `preferred` when given and it has an href.
|
|
249
|
+
2. The first of `STAC_COG_ASSET_KEYS` (`visual`, `image`, `data`, `rendered_preview`) that exists.
|
|
250
|
+
3. Any asset whose `type` (lowercased) contains `"tiff"`.
|
|
251
|
+
|
|
252
|
+
Returns `null` when nothing matches.
|
|
253
|
+
|
|
254
|
+
### `detectMosaicCapable(item)`
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
function detectMosaicCapable(item: StacItem): boolean;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
True when the Item exposes both a bbox (`stacItemBbox`) and a COG-ish asset (`pickCogAssetHref`), the minimum for a single source in a mosaic.
|
|
261
|
+
|
|
262
|
+
### `detectMultiCogCapable(item)`
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
function detectMultiCogCapable(item: StacItem): boolean;
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
True when the Item has Sentinel-2 RGB bands (`hasRgbBands(extractSentinelBandAssets(item))`) or at least three compositable single-band raster COGs (`hasCompositableBands(extractRasterBandAssets(item))`). Drives whether `MultiCogViewer` is offered for the Item.
|
|
269
|
+
|
|
270
|
+
### `stacItemBbox(item)`
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
function stacItemBbox(item: StacItem): [number, number, number, number] | null;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Read the WGS84 bbox as `[minX, minY, maxX, maxY]`, coercing each component with `Number()`. Returns `null` when `item.bbox` is absent or shorter than four entries. Extra entries (a 6-element 3D bbox) are tolerated, only the first four are read.
|
|
277
|
+
|
|
278
|
+
### `buildMosaicSourceMeta(input, assetKey?)`
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
function buildMosaicSourceMeta(
|
|
282
|
+
input:
|
|
283
|
+
| StacItem
|
|
284
|
+
| { id?: string; bbox: [number, number, number, number] | number[]; href: string },
|
|
285
|
+
assetKey?: string
|
|
286
|
+
): MosaicSourceMeta | null;
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Normalize either a full STAC Item or a plain `{ id?, bbox, href }` record into a `MosaicSourceMeta`. For an Item it derives bbox via `stacItemBbox` and href via `pickCogAssetHref(item, assetKey)`, returning `null` if either is missing. For a plain record it requires a 4+ element `bbox` array and a string `href`. The `id` falls back to the href when no id is present.
|
|
290
|
+
|
|
291
|
+
### `spatialCellKey(item, bbox)`
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
function spatialCellKey(item: StacItem, bbox: [number, number, number, number]): string;
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Compute a stable per-footprint cell key, used to dedupe revisits when the caller wants only the freshest scene per footprint. STAC providers default to descending-datetime sort, so the first item seen per key is the newest. Resolution order:
|
|
298
|
+
|
|
299
|
+
1. STAC `properties['grid:code']`, prefixed `g:`.
|
|
300
|
+
2. Sentinel-2 MGRS triplet `properties['mgrs:utm_zone']` + `['mgrs:latitude_band']` + `['mgrs:grid_square']`, prefixed `m:`.
|
|
301
|
+
3. `properties['s2:mgrs_tile']`, prefixed `m:`.
|
|
302
|
+
4. The supplied `bbox` rounded to three decimals, prefixed `b:`, so non-S2 providers still dedupe.
|
|
303
|
+
|
|
304
|
+
### `extractSentinelBandAssets(item)`
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
function extractSentinelBandAssets(item: StacItem): BandMap;
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Map a Sentinel-2 Item's assets to a `BandMap`. For each asset with an href it prefers `eo:bands[0].common_name` (lowercased, when it is a recognized `BandSlot`), then falls back to asset-key heuristics for Microsoft Planetary Computer / Element 84 / AWS S2 L2A bucket conventions (`B04`, `B03`, `nir08`, `swir16`, ...). First match per slot wins. Returns an empty map when no bands are identifiable so callers can fall back to a different viewer.
|
|
311
|
+
|
|
312
|
+
### `hasRgbBands(map)`
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
function hasRgbBands(map: BandMap): boolean;
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
True when `map` carries `red`, `green`, and `blue`, enough for a True Color composite.
|
|
319
|
+
|
|
320
|
+
### `extractRasterBandAssets(item)`
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
function extractRasterBandAssets(item: StacItem): RasterBandAsset[];
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Enumerate every asset that looks like a single-band raster COG suitable for compositing in `MultiCOGLayer`. Inclusion rules:
|
|
327
|
+
|
|
328
|
+
- `type` must match `image/(tiff|geotiff)` (case-insensitive, COG profile suffix allowed) when present. A missing `type` is permitted, since some catalogs omit it for COGs.
|
|
329
|
+
- Assets whose `roles` include `thumbnail`, `overview`, or `metadata` are dropped.
|
|
330
|
+
- Pre-baked multi-band visuals (`raster:bands.length > 1` or `eo:bands.length > 1`) are dropped, compositing needs single-band sources, the multi-band visual belongs in `CogViewer`.
|
|
331
|
+
|
|
332
|
+
`bandCount` is reported as `1` when neither band tag is present, so vendor catalogs that omit `eo:bands` are still pickable. Callers wanting strictness can filter on `bandCount === 1`.
|
|
333
|
+
|
|
334
|
+
### `resolveBandSlotAssetKey(assets, slot)`
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
function resolveBandSlotAssetKey(
|
|
338
|
+
assets: RasterBandAsset[],
|
|
339
|
+
slot: BandSlot
|
|
340
|
+
): string | undefined;
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Resolve a semantic band slot to an asset key on this Item. Priority:
|
|
344
|
+
|
|
345
|
+
1. The first asset whose `commonName` equals the slot.
|
|
346
|
+
2. The first asset whose `key` appears in the vendor fallback list for the slot (`B04`, `red-jp2`, ...).
|
|
347
|
+
|
|
348
|
+
Returns the asset key (NOT the href) so callers can plumb it into `composite: { r, g, b }` and look it up in `extractRasterBandAssets()`. Returns `undefined` when no asset resolves.
|
|
349
|
+
|
|
350
|
+
### `resolvePresetComposite(assets, composite)`
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
function resolvePresetComposite(
|
|
354
|
+
assets: RasterBandAsset[],
|
|
355
|
+
composite: { r: BandSlot; g: BandSlot; b: BandSlot }
|
|
356
|
+
): { r: string; g: string; b: string } | null;
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Resolve a preset's R/G/B `BandSlot` triple into asset keys for this Item via `resolveBandSlotAssetKey`. Returns `null` when any of the three required slots cannot be resolved, so the caller can disable the preset rather than half-apply it.
|
|
360
|
+
|
|
361
|
+
### `hasCompositableBands(assets)`
|
|
362
|
+
|
|
363
|
+
```ts
|
|
364
|
+
function hasCompositableBands(assets: RasterBandAsset[]): boolean;
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
True when at least three single-band raster COG assets exist, so a manual RGB pick is viable.
|
|
368
|
+
|
|
369
|
+
### `extractMosaicAssets(item)`
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
function extractMosaicAssets(item: StacItem): RasterBandAsset[];
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Same media-type and role filtering as `extractRasterBandAssets`, but does NOT drop multi-band assets. Used by the mosaic asset picker, where a 3-band pre-baked `visual` TCI is a legitimate choice alongside per-band single-band COGs. `bandCount` is reported only when known (`raster:bands.length` or `eo:bands.length`), otherwise left `undefined` so the consuming UI can probe the COG.
|
|
376
|
+
|
|
377
|
+
## Example
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
import {
|
|
381
|
+
classifyStac,
|
|
382
|
+
buildMosaicSourceMeta,
|
|
383
|
+
detectMultiCogCapable,
|
|
384
|
+
extractRasterBandAssets,
|
|
385
|
+
resolvePresetComposite,
|
|
386
|
+
spatialCellKey,
|
|
387
|
+
stacItemBbox,
|
|
388
|
+
type StacItem,
|
|
389
|
+
type MosaicSourceMeta,
|
|
390
|
+
} from '@walkthru-earth/objex-utils';
|
|
391
|
+
|
|
392
|
+
const json: unknown = await fetch(url).then((r) => r.json());
|
|
393
|
+
const routed = classifyStac(json);
|
|
394
|
+
|
|
395
|
+
if (routed.kind === 'item-collection') {
|
|
396
|
+
// Build a deduped mosaic, freshest scene per footprint.
|
|
397
|
+
const seen = new Set<string>();
|
|
398
|
+
const sources: MosaicSourceMeta[] = [];
|
|
399
|
+
for (const item of routed.fc.features) {
|
|
400
|
+
const bbox = stacItemBbox(item);
|
|
401
|
+
if (!bbox) continue;
|
|
402
|
+
const key = spatialCellKey(item, bbox);
|
|
403
|
+
if (seen.has(key)) continue; // first per key is newest (datetime-desc)
|
|
404
|
+
seen.add(key);
|
|
405
|
+
const meta = buildMosaicSourceMeta(item);
|
|
406
|
+
if (meta) sources.push(meta);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (routed.kind === 'item') {
|
|
411
|
+
const item: StacItem = routed.item;
|
|
412
|
+
if (detectMultiCogCapable(item)) {
|
|
413
|
+
const bands = extractRasterBandAssets(item);
|
|
414
|
+
// Natural color = red / green / blue slots.
|
|
415
|
+
const rgb = resolvePresetComposite(bands, { r: 'red', g: 'green', b: 'blue' });
|
|
416
|
+
if (rgb) {
|
|
417
|
+
// rgb = { r: 'B04', g: 'B03', b: 'B02' } (or whatever keys the catalog uses)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Peer dependencies
|
|
424
|
+
|
|
425
|
+
None. Every function is pure and runtime-agnostic, operating only on already-parsed JSON objects.
|
package/docs/storage.md
CHANGED
|
@@ -4,8 +4,8 @@ URL parsing, provider registry, and the `StorageAdapter` contract.
|
|
|
4
4
|
|
|
5
5
|
Sources:
|
|
6
6
|
|
|
7
|
-
- `
|
|
8
|
-
- `
|
|
7
|
+
- `packages/objex-utils/src/storage-url.ts` — generic URL / bucket parser
|
|
8
|
+
- `packages/objex-utils/src/cloud-url.ts` — cloud-scheme → HTTPS resolver
|
|
9
9
|
- `src/lib/storage/providers.ts` — provider registry + access-mode logic
|
|
10
10
|
- `src/lib/storage/adapter.ts` — the `StorageAdapter` interface
|
|
11
11
|
- `src/lib/storage/url-adapter.ts` — adapter for arbitrary HTTPS URLs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkthru-earth/objex-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Pure TypeScript utilities from objex — WKB parser, GeoArrow builder, storage URL parser, file type registry",
|
|
5
5
|
"author": "Youssef Harby <yharby@walkthru.earth>",
|
|
6
6
|
"license": "CC-BY-4.0",
|
|
@@ -51,10 +51,17 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"apache-arrow": "^21.1.0",
|
|
55
|
+
"hyparquet": "^1.26.0",
|
|
56
|
+
"hyparquet-compressors": "^1.1.1",
|
|
54
57
|
"tsup": "^8.5.0",
|
|
55
|
-
"typescript": "^
|
|
58
|
+
"typescript": "^6.0.3",
|
|
59
|
+
"vitest": "^4.1.7",
|
|
60
|
+
"yaml": "^2.9.0"
|
|
56
61
|
},
|
|
57
62
|
"scripts": {
|
|
58
|
-
"build": "tsup"
|
|
63
|
+
"build": "tsup && node ../../scripts/verify-objex-utils-bundle.mjs",
|
|
64
|
+
"verify-bundle": "node ../../scripts/verify-objex-utils-bundle.mjs",
|
|
65
|
+
"test": "vitest run"
|
|
59
66
|
}
|
|
60
67
|
}
|