@geolibre/core 3.0.0 → 3.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/dist/index.d.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import "zustand";
2
+ import "zundo";
1
3
  //#region src/cesium-imagery.d.ts
2
4
  /**
3
5
  * Maps the project's basemap onto imagery the Cesium globe can render.
@@ -113,42 +115,19 @@ export declare const CESIUM_BASEMAPS: readonly [{
113
115
  readonly name: "OpenStreetMap";
114
116
  readonly icon: "openStreetMap.png";
115
117
  readonly category: "Other";
116
- }, {
117
- readonly id: "stadia-watercolor";
118
- readonly name: "Stadia x Stamen Watercolor";
119
- readonly icon: "stamenWatercolor.png";
120
- readonly category: "Other";
121
- readonly stadiaStyle: "stamen_watercolor";
122
- readonly maximumLevel: 16;
123
- readonly extension: "jpg";
124
- }, {
125
- readonly id: "stadia-toner";
126
- readonly name: "Stadia x Stamen Toner";
127
- readonly icon: "stamenToner.png";
128
- readonly category: "Other";
129
- readonly stadiaStyle: "stamen_toner";
130
- readonly maximumLevel: 20;
131
- readonly extension: "png";
132
- }, {
133
- readonly id: "stadia-smooth";
134
- readonly name: "Stadia Alidade Smooth";
135
- readonly icon: "stadiaAlidadeSmooth.png";
136
- readonly category: "Other";
137
- readonly stadiaStyle: "alidade_smooth";
138
- readonly maximumLevel: 20;
139
- readonly extension: "png";
140
- }, {
141
- readonly id: "stadia-dark";
142
- readonly name: "Stadia Alidade Smooth Dark";
143
- readonly icon: "stadiaAlidadeSmoothDark.png";
144
- readonly category: "Other";
145
- readonly stadiaStyle: "alidade_smooth_dark";
146
- readonly maximumLevel: 20;
147
- readonly extension: "png";
148
118
  }];
149
119
  export type CesiumBasemapId = (typeof CESIUM_BASEMAPS)[number]["id"];
150
120
  export declare function normalizeCesiumBasemap(value: unknown): CesiumBasemapId;
151
- /** Missing credentials fall back to the project background without changing the saved choice. */
121
+ /**
122
+ * Missing credentials fall back to keyless imagery without changing the saved
123
+ * choice.
124
+ *
125
+ * The fallback is ArcGIS World Imagery rather than the project background: a
126
+ * globe wants to look like the Earth, and the project's own basemap is usually
127
+ * a vector street style whose raster analogue is mostly empty ocean from
128
+ * orbit. It needs no key, so the globe looks the same with or without an Ion
129
+ * token — only terrain and the Ion-only basemaps are lost.
130
+ */
152
131
  export declare function availableCesiumBasemap(value: unknown, hasIonToken: boolean): CesiumBasemapId;
153
132
  /**
154
133
  * What the globe should draw underneath the project's data layers.
@@ -177,8 +156,6 @@ export type CesiumBasemapImagery = {
177
156
  kind: "xyz";
178
157
  /** Tile template with `{z}`/`{x}`/`{y}` placeholders. */
179
158
  template: string;
180
- /** Credentials are resolved at render time, never embedded in the descriptor. */
181
- apiKeyProvider?: "stadia";
182
159
  /** Credit to show on the globe, as the HTML the 2D map already uses. */
183
160
  attribution: string;
184
161
  /** Max native zoom of the source, so the globe overzooms rather than 404s. */
@@ -1347,6 +1324,21 @@ export interface LayerPopupConfig {
1347
1324
  bodyExpression?: string;
1348
1325
  /** `false` drops the synthetic `id` row. Defaults to `true`. */
1349
1326
  showFeatureId?: boolean;
1327
+ /**
1328
+ * Widest the click popup may grow, in CSS pixels. Unset keeps the default
1329
+ * (520px, or 420px for a popup carrying an image). Clamped to the range
1330
+ * `resolvePopupMaxWidth` enforces and always capped by the viewport, so a
1331
+ * value wider than the window still leaves the map usable.
1332
+ */
1333
+ maxWidth?: number;
1334
+ /**
1335
+ * Tallest an `"image"` field's thumbnail may draw inside the popup, in CSS
1336
+ * pixels. Unset keeps the default (`min(50vh, 420px)`). Clamped by
1337
+ * `resolvePopupImageHeight`. Pair it with {@link maxWidth} for a
1338
+ * bigger picture: the thumbnail keeps its aspect ratio, so widening the
1339
+ * popup is what lets a landscape photo use the extra height.
1340
+ */
1341
+ imageHeight?: number;
1350
1342
  /**
1351
1343
  * The fields to show and their order. An empty or absent list keeps today's
1352
1344
  * behavior: every visible property, in the feature's own key order.
@@ -1646,7 +1638,9 @@ export interface AddTileLayerOptions {
1646
1638
  tiles: string[];
1647
1639
  /**
1648
1640
  * Layer discriminator, controlling how the layer is labelled and (for WMS)
1649
- * dev-server proxied. Defaults to `"xyz"`.
1641
+ * dev-server proxied. Defaults to `"xyz"`. The layer's `source.type` is
1642
+ * always `"raster"`, so any other value (such as `"vector-tiles"` from an
1643
+ * untyped JS caller) throws rather than persisting a mislabelled source.
1650
1644
  */
1651
1645
  type?: "xyz" | "wms" | "wmts" | "raster";
1652
1646
  /** Service or base URL recorded on the source for display and restore. */
@@ -1751,13 +1745,15 @@ export interface MapGridLayout {
1751
1745
  * `"maplibre"` is the 2D MapLibre GL map that owns the app's plugin, styling,
1752
1746
  * and deck.gl integrations. `"cesium"` is the 3D globe (see `CesiumCanvas`),
1753
1747
  * which renders the same shared store state — camera, basemap, layers, group
1754
- * effects — through CesiumJS.
1748
+ * effects — through CesiumJS. `"mapbox"` is Mapbox GL JS and `"arcgis"` the
1749
+ * ArcGIS Maps SDK for JavaScript, loaded from Esri's CDN at runtime (see
1750
+ * `ArcgisCanvas`); both draw the same store state through their own engines.
1755
1751
  *
1756
1752
  * Used both for secondary panes ({@link SecondaryMapView.viewKind}) and for the
1757
1753
  * primary workspace ({@link GeoLibreProject.primaryRenderer}), so the two never
1758
1754
  * drift apart.
1759
1755
  */
1760
- export type MapRendererKind = "maplibre" | "cesium";
1756
+ export type MapRendererKind = "maplibre" | "cesium" | "mapbox" | "arcgis";
1761
1757
  /**
1762
1758
  * The engine that draws the primary map area when a project says nothing. The
1763
1759
  * 2D map: it is the renderer every tool, plugin, and panel is wired to, so an
@@ -1925,6 +1921,16 @@ export interface MapPreferences {
1925
1921
  showPointerElevation: boolean;
1926
1922
  /** Whether the built-in 3D terrain control and terrain surface are enabled. */
1927
1923
  terrainEnabled: boolean;
1924
+ /** Mapbox-only style. New projects use Streets; absent follows the shared basemap. */
1925
+ mapboxStyleUrl?: string;
1926
+ /**
1927
+ * ArcGIS-only basemap: an Esri basemap style id (`arcgis/streets`,
1928
+ * `arcgis/imagery`, `osm/standard`, ...). New projects use Streets. Absent
1929
+ * follows the shared basemap, translated to tiles the SDK can draw; the id
1930
+ * is also set aside when no ArcGIS API key is configured, since Esri's
1931
+ * basemap styles service requires one.
1932
+ */
1933
+ arcgisBasemap?: string;
1928
1934
  /** Cesium imagery override; absent follows the shared project basemap. */
1929
1935
  cesiumBasemap?: CesiumBasemapId;
1930
1936
  /**
@@ -3176,8 +3182,9 @@ export declare function horizontalBbox(box: readonly number[] | null | undefined
3176
3182
  * cached per GeoJSON object, so repeated calls on the same data are free.
3177
3183
  *
3178
3184
  * @param geojson - Any GeoJSON object (geometry, feature, or collection).
3185
+ * @param includeZero - Accept zero elevations when explicit absolute-height placement matters.
3179
3186
  */
3180
- export declare function geojsonHasZCoordinates(geojson: GeoJSON$1 | null | undefined): boolean;
3187
+ export declare function geojsonHasZCoordinates(geojson: GeoJSON$1 | null | undefined, includeZero?: boolean): boolean;
3181
3188
  /**
3182
3189
  * Returns a copy of the GeoJSON with every coordinate's Z value mapped to
3183
3190
  * `z * verticalScale + offset` (missing or non-finite Z treated as 0). Used
@@ -4423,6 +4430,23 @@ export declare function getExternalNativePaintBridge(layerId: string): ExternalN
4423
4430
  * `!pluginOwnsPaint(layer)` to decide whether to show the slider at all.
4424
4431
  */
4425
4432
  export declare function supportsBridgedOpacity(layerId: string): boolean;
4433
+ /**
4434
+ * True when the primary renderer draws this plugin-painted layer itself, from
4435
+ * the store record, and so applies `layer.opacity` without any plugin bridge.
4436
+ *
4437
+ * A Zarr layer is a MapLibre custom layer owned by the Zarr control on the 2D
4438
+ * map, but the ArcGIS view and the Cesium globe render it natively (an ArcGIS
4439
+ * layer's `opacity`, a Cesium `ImageryLayer.alpha`) and mount no control to
4440
+ * register a bridge. Without this the Opacity slider would be hidden there
4441
+ * although it works (opengeos/GeoLibre#2261).
4442
+ *
4443
+ * @param layer - A store layer.
4444
+ * @param renderer - The primary renderer (`useAppStore().primaryRenderer`).
4445
+ * @returns Whether an Opacity slider reaches the layer through the renderer.
4446
+ */
4447
+ export declare function rendererAppliesOpacity(layer: {
4448
+ type: string;
4449
+ }, renderer: string | undefined): boolean;
4426
4450
  //#endregion
4427
4451
  //#region src/attribute-form.d.ts
4428
4452
  /** Options threaded to expression evaluation (constraints, visibility). */
@@ -4516,6 +4540,36 @@ export interface PopupRow {
4516
4540
  export declare function isPopupClickEnabled(popup: LayerPopupConfig | undefined): boolean;
4517
4541
  /** Whether a hover tooltip should follow the pointer. Default: no. */
4518
4542
  export declare function isPopupHoverEnabled(popup: LayerPopupConfig | undefined): boolean;
4543
+ /**
4544
+ * Bounds for {@link LayerPopupConfig.maxWidth}, in CSS pixels. The floor is
4545
+ * the popup's own minimum width (`min-w-[18rem]`), below which the setting
4546
+ * would be overruled by the layout and read as broken; the ceiling keeps a
4547
+ * hand-edited project from authoring a popup that blankets the map.
4548
+ */
4549
+ export declare const POPUP_MAX_WIDTH_RANGE: {
4550
+ readonly min: 288;
4551
+ readonly max: 1200;
4552
+ };
4553
+ /**
4554
+ * Bounds for {@link LayerPopupConfig.imageHeight}, in CSS pixels. Below the
4555
+ * floor a thumbnail carries no information; the ceiling matches
4556
+ * {@link POPUP_MAX_WIDTH_RANGE}, since a taller picture than that is what the
4557
+ * lightbox is for.
4558
+ */
4559
+ export declare const POPUP_IMAGE_HEIGHT_RANGE: {
4560
+ readonly min: 40;
4561
+ readonly max: 1200;
4562
+ };
4563
+ /**
4564
+ * The widest the click popup may draw for a layer, in CSS pixels, or
4565
+ * `undefined` to keep the renderer's default.
4566
+ */
4567
+ export declare function resolvePopupMaxWidth(popup: LayerPopupConfig | undefined): number | undefined;
4568
+ /**
4569
+ * The tallest an `"image"` field may draw inside the popup, in CSS pixels, or
4570
+ * `undefined` to keep the stylesheet's default.
4571
+ */
4572
+ export declare function resolvePopupImageHeight(popup: LayerPopupConfig | undefined): number | undefined;
4519
4573
  /** The label a popup shows for a configured field. */
4520
4574
  export declare function popupFieldLabel(config: PopupFieldConfig): string;
4521
4575
  /**
@@ -5225,6 +5279,42 @@ export declare function createEmptyProject(name?: string, options?: CreateProjec
5225
5279
  * @returns The file contents to write.
5226
5280
  */
5227
5281
  export declare function serializeProject(project: GeoLibreProject): string;
5282
+ /**
5283
+ * Per-layer serialized text kept across {@link serializeProjectWithLayerCache}
5284
+ * calls, keyed by the layer record each entry was built from. A `WeakMap`, so a
5285
+ * layer the store has replaced or removed drops its text with it.
5286
+ */
5287
+ export type ProjectLayerSerializationCache = WeakMap<object, {
5288
+ index: number;
5289
+ text: string;
5290
+ }>;
5291
+ /** Create an empty {@link ProjectLayerSerializationCache}. */
5292
+ export declare function createProjectLayerSerializationCache(): ProjectLayerSerializationCache;
5293
+ /**
5294
+ * Serialize a project exactly as {@link serializeProject} does, reusing the
5295
+ * text of every layer whose source record is unchanged since an earlier call.
5296
+ *
5297
+ * Feature data lives inside layer records, so re-stringifying every layer on
5298
+ * each autosave costs megabytes of main-thread work for a project with large
5299
+ * GeoJSON layers — even when only the camera moved (GeoLibre#2633). The store
5300
+ * replaces a layer object whenever it changes, so object identity is a sound
5301
+ * cache key: a camera move reuses every layer, and an edit to one layer
5302
+ * re-serializes only that one.
5303
+ *
5304
+ * `layerSources[i]` must be the record `project.layers[i]` was derived from
5305
+ * (e.g. the store's `layers`, before `projectFromStore` prepared them), and that
5306
+ * derivation must depend on the record alone — as `buildProjectSnapshot`'s does
5307
+ * — or a cached entry could outlive a change it should have reflected. When the
5308
+ * two arrays differ in length the cache is bypassed rather than trusted.
5309
+ *
5310
+ * @param project Project to serialize, as built from `layerSources`.
5311
+ * @param layerSources Immutable source record for each entry of
5312
+ * `project.layers`, in the same order, used as the cache key.
5313
+ * @param cache Cache shared between calls; see
5314
+ * {@link createProjectLayerSerializationCache}.
5315
+ * @returns The same text {@link serializeProject} returns for `project`.
5316
+ */
5317
+ export declare function serializeProjectWithLayerCache(project: GeoLibreProject, layerSources: readonly object[], cache: ProjectLayerSerializationCache): string;
5228
5318
  export declare function parseProject(json: string): GeoLibreProject;
5229
5319
  /**
5230
5320
  * Validate and coerce a story map loaded from an untrusted project file.
@@ -5293,10 +5383,11 @@ export declare function normalizeMapLayout(value: unknown): MapGridLayout | null
5293
5383
  * Returns null for the default 2D map — absent, unknown, or an explicit
5294
5384
  * `"maplibre"` — because the field is only written when it is not the default,
5295
5385
  * so a MapLibre project serializes byte-identically to before this existed.
5296
- * The return type is narrowed to `"cesium" | null` rather than the full
5297
- * {@link MapRendererKind} for that reason: `"maplibre"` is never a result.
5386
+ * The return type is narrowed to `"cesium" | "mapbox" | "arcgis" | null` rather
5387
+ * than the full {@link MapRendererKind} for that reason: `"maplibre"` is never a
5388
+ * result.
5298
5389
  */
5299
- export declare function normalizePrimaryRenderer(value: unknown): "cesium" | null;
5390
+ export declare function normalizePrimaryRenderer(value: unknown): "cesium" | "mapbox" | "arcgis" | null;
5300
5391
  /**
5301
5392
  * Coerce an untrusted `secondaryMapViews` array into valid
5302
5393
  * {@link SecondaryMapView} records, dropping entries without a usable id and
@@ -5365,6 +5456,16 @@ export declare function projectFromStore(state: {
5365
5456
  comments?: ProjectComment[] | null;
5366
5457
  metadata: Record<string, unknown>;
5367
5458
  }): GeoLibreProject;
5459
+ /**
5460
+ * The plain HTTP(S) WMS template inside the desktop app's `geolibre-wms://`
5461
+ * wrapper (its CORS-exempt native fetcher), or the tile unchanged when it is
5462
+ * not wrapped or the wrapped URL is not HTTP(S). Shared by project export and
5463
+ * the ArcGIS engine's story-export templates.
5464
+ *
5465
+ * @param tile - A tile template, wrapped or not.
5466
+ * @returns The unwrapped template, or `tile` itself.
5467
+ */
5468
+ export declare function portableWmsTileUrl(tile: unknown): unknown;
5368
5469
  export declare function applyProjectToStore(project: GeoLibreProject): {
5369
5470
  projectName: string;
5370
5471
  mapView: MapViewState;
@@ -6157,6 +6258,35 @@ export declare function reorderLayerGroupInPanel(layers: GeoLibreLayer[], groups
6157
6258
  layers: GeoLibreLayer[];
6158
6259
  groups: LayerGroup[];
6159
6260
  } | null;
6261
+ /** Direction {@link sortLayerGroupInPanel} orders names in, top of panel first. */
6262
+ export type LayerGroupSortOrder = "asc" | "desc";
6263
+ /**
6264
+ * Sort what sits directly inside a group by name, A to Z (`"asc"`) or Z to A
6265
+ * (`"desc"`) from the top of the panel down (GeoLibre#2599).
6266
+ *
6267
+ * The group's own layers are sorted among themselves, and its child groups are
6268
+ * sorted among themselves by group name, each carrying everything nested inside
6269
+ * it. The two are not interleaved: a group's own layers are one contiguous
6270
+ * block (see {@link normalizeGroupContiguity}), so that block keeps its slot
6271
+ * among the child groups rather than being split between them. Only direct
6272
+ * children move; the contents of a child group keep their order.
6273
+ *
6274
+ * Like {@link reorderLayerGroupInPanel}, both arrays come back, so empty child
6275
+ * folders follow the sort too.
6276
+ *
6277
+ * @param layers Flat layer list in store (render) order.
6278
+ * @param groups Group definitions.
6279
+ * @param id Group whose children to sort.
6280
+ * @param order `"asc"` for A to Z, `"desc"` for Z to A.
6281
+ * @param locale BCP 47 tag whose collation rules to compare names by, normally
6282
+ * the app's display language. Defaults to the runtime locale.
6283
+ * @returns The new arrays, or `null` when the children are already in that
6284
+ * order and nothing would change.
6285
+ */
6286
+ export declare function sortLayerGroupInPanel(layers: GeoLibreLayer[], groups: LayerGroup[], id: string, order: LayerGroupSortOrder, locale?: string): {
6287
+ layers: GeoLibreLayer[];
6288
+ groups: LayerGroup[];
6289
+ } | null;
6160
6290
  /**
6161
6291
  * Which directions {@link reorderLayerGroupInPanel} can actually move each
6162
6292
  * group, so the layer panel can disable a menu item that would do nothing.
@@ -6169,6 +6299,16 @@ export declare function layerGroupMoveability(layers: GeoLibreLayer[], groups: L
6169
6299
  up: boolean;
6170
6300
  down: boolean;
6171
6301
  }>;
6302
+ /**
6303
+ * Which orders {@link sortLayerGroupInPanel} would actually change for each
6304
+ * group, so the layer panel can disable a sort that would do nothing.
6305
+ *
6306
+ * @param layers Flat layer list in store (render) order.
6307
+ * @param groups Group definitions.
6308
+ * @param locale Collation locale, as for {@link sortLayerGroupInPanel}.
6309
+ * @returns Per-group flags, keyed by group id.
6310
+ */
6311
+ export declare function layerGroupSortability(layers: GeoLibreLayer[], groups: LayerGroup[], locale?: string): Map<string, Record<LayerGroupSortOrder, boolean>>;
6172
6312
  //#endregion
6173
6313
  //#region src/pixel-format.d.ts
6174
6314
  /**
@@ -6308,392 +6448,364 @@ export declare function serializeStoryMapCsv(storymap: StoryMap): string;
6308
6448
  */
6309
6449
  export declare function parseStoryMapCsv(text: string, base?: StoryMap | null): StoryMap;
6310
6450
  //#endregion
6311
- //#region src/store.d.ts
6312
- type ConversionToolKind = "vector-to-vector" | "vector-to-geoparquet" | "vector-to-flatgeobuf" | "vector-to-shapefile" | "vector-to-geopackage" | "csv-to-geoparquet" | "vector-to-pmtiles" | "raster-to-pmtiles" | "raster-to-cog";
6313
- /**
6314
- * Identifiers of the vector processing tools. Kept in sync by hand with the
6315
- * `id` fields of `VECTOR_TOOLS` in `@geolibre/processing` (`vector-tools.ts`);
6316
- * deriving the type there would create a core -> processing circular import.
6317
- */
6318
- type VectorToolKind = "buffer" | "centroids" | "convex-hull" | "dissolve" | "bounding-box" | "simplify" | "clip" | "intersection" | "difference" | "union" | "spatial-join" | "attribute-join" | "select-by-value" | "select-by-location" | "random-extract" | "reproject" | "explode" | "aggregate" | "smooth" | "extract-vertices" | "points-along-geometry" | "grid" | "voronoi" | "cell-sectors" | "dggs-grid" | "dggs-bin" | "dggs-compact" | "trajectory-speed" | "detect-stops" | "space-time-proximity" | "decode-polyline" | "encode-polyline" | "merge-layers" | "check-validity" | "fix-geometries" | "check-topology-rules" | "fix-topology";
6319
- /** Identifiers of the network-analysis tools (`NETWORK_TOOLS` ids). */
6320
- type NetworkToolKind = "isochrone" | "od-matrix" | "sequential-route";
6321
- /** Identifiers of the spatial-statistics tools (`STATISTICS_TOOLS` ids). */
6322
- type StatisticsToolKind = "global-morans-i" | "local-morans-i" | "getis-ord-gi" | "average-nearest-neighbor" | "kernel-density" | "emerging-hot-spot" | "composite-score";
6323
- /**
6324
- * Identifiers of the raster processing tools. Kept in sync by hand with the
6325
- * `id` fields of `RASTER_TOOLS` in `@geolibre/processing` (`raster-tools.ts`);
6326
- * deriving the type there would create a core -> processing circular import.
6327
- */
6328
- type RasterToolKind = "hillshade" | "slope" | "aspect" | "reproject" | "resample" | "clip-extent" | "clip-mask" | "polygonize" | "contour" | "interpolate" | "zonal" | "raster-calc" | "spectral-index" | "reclassify" | "mosaic" | "focal";
6329
- /**
6330
- * Latest live device-GPS fix published by the GPS Tracking tool (issue #1316),
6331
- * read by the status bar readout. Device state, not project state: excluded
6332
- * from undo history (partialize never lists it) and from project files, and
6333
- * deliberately left untouched on project switches.
6334
- */
6335
- interface GpsStatusFix {
6336
- lng: number;
6337
- lat: number;
6338
- /** Horizontal accuracy radius in meters. */
6339
- accuracy: number;
6340
- /** Satellites used for the fix, or null when the provider does not report it. */
6341
- satellites: number | null;
6342
- /** Ground speed in m/s, or null when the device doesn't report one. */
6343
- speed: number | null;
6344
- /** Fix time in epoch milliseconds. */
6345
- timestamp: number;
6346
- }
6347
- interface AppState {
6348
- projectName: string;
6349
- projectPath: string | null;
6350
- projectGeneration: number;
6351
- isDirty: boolean;
6352
- mapView: MapViewState;
6353
- basemapStyleUrl: string;
6354
- basemapVisible: boolean;
6355
- basemapOpacity: number;
6356
- blankBackgroundColor: string | null;
6357
- layers: GeoLibreLayer[];
6358
- layerGroups: LayerGroup[];
6359
- preferences: ProjectPreferences;
6360
- projectPlugins: ProjectPluginState | null;
6361
- legend: LegendConfig;
6362
- /** Print Layout composer settings for the open project (discussion #1992). */
6363
- printLayout: PrintLayoutConfig;
6364
- storymap: StoryMap | null;
6365
- /** Saved processing pipelines (batch/model chaining; issue #344). */
6366
- models: ProcessingModel[];
6451
+ //#region src/store/capabilities-slice.d.ts
6452
+ interface CapabilitiesSlice {
6367
6453
  /**
6368
- * App-level Style Manager library (issue #1294). Lives outside the project
6369
- * lifecycle: never serialized into the project file, untouched by
6370
- * newProject/loadProject, and persisted by the desktop app (IndexedDB).
6454
+ * What this *deployment* is allowed to do (issue #1673). Set once at startup
6455
+ * from the deployment configuration; never from a project file, a URL
6456
+ * parameter, or anything else the visitor controls, and never edited from the
6457
+ * UI. Defaults to the full set so an unconfigured build behaves as before.
6458
+ *
6459
+ * Excluded from the project file and from undo history: it describes the
6460
+ * server that served the app, not the document being edited.
6371
6461
  */
6372
- styleLibrary: StyleLibraryEntry[];
6462
+ deploymentCapabilities: ReadonlySet<DeploymentCapability>;
6373
6463
  /**
6374
- * App-level Layer Library (issue #1520) — the Browser panel's My Data
6375
- * section. Like {@link styleLibrary} it lives outside the project lifecycle:
6376
- * never serialized into the project file, untouched by newProject/loadProject,
6377
- * and persisted by the desktop app (IndexedDB). Most recently saved first.
6464
+ * Ephemeral application capability model (issue #1672). Gating role and
6465
+ * privileges for the current session/deployment. Excluded from the project file
6466
+ * and undo history.
6378
6467
  */
6379
- layerLibrary: LayerLibraryEntry[];
6468
+ capabilities: AppCapabilities;
6380
6469
  /**
6381
- * App-level Template Library. Persisted by the desktop app (IndexedDB).
6470
+ * Narrow what this deployment may do. Intended for the startup path only —
6471
+ * calling it later would leave already-rendered surfaces stale.
6382
6472
  */
6383
- templateLibrary: ProjectTemplateEntry[];
6473
+ setDeploymentCapabilities: (capabilities: Iterable<DeploymentCapability>) => void;
6384
6474
  /**
6385
- * Project-scoped Style Manager entries (issue #1294), serialized into the
6386
- * `.geolibre.json` `styleLibrary` array and replaced on project load.
6475
+ * Assign an application role (e.g. "viewer", "editor", "publisher", "administrator", "custom"),
6476
+ * deriving the effective privileges and optional reason.
6387
6477
  */
6388
- projectStyleLibrary: StyleLibraryEntry[];
6389
- /** Recorded processing tool runs, oldest first (Processing History; #1292). */
6390
- processingHistory: ProcessingRun[];
6391
- /** Saved Dashboard panel chart widgets (issue #401). */
6392
- widgets: DashboardWidget[];
6393
- /** Number of columns in the Dashboard widget grid. */
6394
- dashboardColumns: number;
6478
+ setAppRole: (role: AppRole, options?: {
6479
+ customPrivileges?: AppPrivilege[];
6480
+ reason?: string;
6481
+ }) => void;
6482
+ /** Set explicit custom privileges and an optional reason. */
6483
+ setAppPrivileges: (privileges: AppPrivilege[], reason?: string) => void;
6484
+ /** Grant an individual application privilege. */
6485
+ grantAppPrivilege: (privilege: AppPrivilege) => void;
6486
+ /** Revoke an individual application privilege with an optional reason. */
6487
+ revokeAppPrivilege: (privilege: AppPrivilege, reason?: string) => void;
6488
+ /** Reset application capabilities back to the default unconstrained Administrator role. */
6489
+ resetAppCapabilities: () => void;
6490
+ /** Check if the current capabilities grant the requested privilege. */
6491
+ hasAppPrivilege: (privilege: AppPrivilege) => boolean;
6492
+ }
6493
+ //#endregion
6494
+ //#region src/store/collaboration-slice.d.ts
6495
+ /**
6496
+ * A fresh, inactive collaboration slice (no live session). Frozen (like
6497
+ * DEFAULT_LEGEND_CONFIG) to guard against accidental in-place mutation; store
6498
+ * actions always produce new objects via spread, so the frozen default is only
6499
+ * ever read.
6500
+ */
6501
+ export declare const DEFAULT_COLLABORATION_STATE: CollaborationState;
6502
+ interface CollaborationSlice {
6503
+ collaboration: CollaborationState;
6504
+ setCollaboration: (patch: Partial<CollaborationState>) => void;
6505
+ updateCollaborationPresence: (clientId: string, presence: CollaborationPresence | null) => void;
6506
+ /** Append a chat message to the session log (bounded; #754). */
6507
+ addCollaborationChat: (message: CollaborationChatMessage) => void;
6508
+ resetCollaboration: () => void;
6509
+ }
6510
+ //#endregion
6511
+ //#region src/store/layer-groups-slice.d.ts
6512
+ interface LayerGroupsSlice {
6513
+ layerGroups: LayerGroup[];
6514
+ addLayerGroup: (name?: string, layerIds?: string[]) => string;
6515
+ removeLayerGroup: (id: string, options?: {
6516
+ removeChildren?: boolean;
6517
+ }) => void;
6518
+ renameLayerGroup: (id: string, name: string) => void;
6519
+ setLayerGroupVisibility: (id: string, visible: boolean) => void;
6520
+ setLayerGroupOpacity: (id: string, opacity: number) => void;
6521
+ toggleLayerGroupCollapsed: (id: string) => void;
6522
+ moveLayerToGroup: (layerId: string, groupId: string | null, beforeLayerId?: string | null) => void;
6523
+ moveLayersToGroup: (layerIds: string[], groupId: string | null, beforeLayerId?: string | null) => void;
6524
+ moveLayerGroupToGroup: (id: string, parentId: string | null) => void;
6525
+ reorderLayerGroup: (id: string, direction: "up" | "down") => void;
6395
6526
  /**
6396
- * Multi-map grid layout (issue: split/grid view). A 1x1 grid is the normal
6397
- * single-map workspace. `rows * cols` panes are shown; pane 0 is the primary
6398
- * map driven by `mapView` / `basemap*`, panes 1.. are `secondaryMapViews`.
6527
+ * Sort a group's direct children by name, A to Z or Z to A (top of panel
6528
+ * first), collating by `locale` (the app's display language) when given.
6399
6529
  */
6400
- mapLayout: MapGridLayout;
6530
+ sortLayerGroup: (id: string, order: LayerGroupSortOrder, locale?: string) => void;
6531
+ }
6532
+ //#endregion
6533
+ //#region src/store/layers-slice.d.ts
6534
+ interface LayersSlice {
6535
+ layers: GeoLibreLayer[];
6536
+ addLayer: (layer: GeoLibreLayer, beforeLayerId?: string | null) => void;
6537
+ removeLayer: (id: string) => void;
6538
+ updateLayer: (id: string, patch: Partial<GeoLibreLayer>) => void;
6539
+ setLayerVisibility: (id: string, visible: boolean) => void;
6540
+ setLayerOpacity: (id: string, opacity: number) => void;
6541
+ setLayerStyle: (id: string, style: Partial<LayerStyle>) => void;
6401
6542
  /**
6402
- * Secondary map panes (everything past the primary pane). The store keeps
6403
- * exactly `rows * cols - 1` entries in sync with `mapLayout`.
6543
+ * Transient clipboard holding a layer's symbology, captured by
6544
+ * {@link copyLayerStyle} and applied by {@link pasteLayerStyle} (copy/paste
6545
+ * styles, issue #1339). Runtime-only: excluded from undo history
6546
+ * (`partialize` never lists it) and from the saved project. `null` until a
6547
+ * style is copied this session. Cleared by `newProject`/`loadProject` so a
6548
+ * paste can't apply an entry from a different project; it deliberately
6549
+ * survives undo/redo within a project (it holds a deep snapshot, not a live
6550
+ * layer reference, so a paste stays valid even if the source layer is undone
6551
+ * away — only the displayed source name may then be stale).
6404
6552
  */
6405
- secondaryMapViews: SecondaryMapView[];
6406
- /** User-entered label for the primary pane (shown only in multi-map mode). */
6407
- primaryMapLabel: string;
6553
+ copiedLayerStyle: CopiedLayerStyle | null;
6408
6554
  /**
6409
- * Which engine draws the primary map area (issue #2217): the 2D MapLibre map
6410
- * or the 3D Cesium globe. Both render the same store state, so switching
6411
- * keeps the camera, basemap, layers, groups, visibility, and opacity — it
6412
- * only changes what draws them. Independent of `mapLayout`: switching never
6413
- * adds or removes panes.
6555
+ * Snapshot the given layer's style into {@link copiedLayerStyle} so it can be
6556
+ * pasted onto a compatible layer. No-op when the layer is missing or has no
6557
+ * copyable symbology (leaving any prior clipboard entry untouched). Returns
6558
+ * `true` when a style was captured, so callers can skip the confirmation on a
6559
+ * no-op.
6414
6560
  */
6415
- primaryRenderer: MapRendererKind;
6416
- selectedLayerId: string | null;
6417
- selectedFeatureId: string | null;
6561
+ copyLayerStyle: (id: string) => boolean;
6418
6562
  /**
6419
- * Full set of selected feature ids. The attribute table extends the single
6420
- * selection to many rows via Ctrl/Cmd (toggle) and Shift (range). The anchor
6421
- * — `selectedFeatureId` — is the primary/last-clicked feature used for map
6422
- * fit, DuckDB highlight, and scripting, and is always one of these ids (or
6423
- * `null` when the set is empty). A single click leaves exactly one id here.
6563
+ * Apply the {@link copiedLayerStyle} clipboard entry onto the given layer.
6564
+ * No-op when the clipboard is empty, the layer is missing, or the entry's
6565
+ * style family does not match the target layer's. Returns `true` when the
6566
+ * style was applied, so callers can skip the confirmation on a no-op.
6424
6567
  */
6425
- selectedFeatureIds: string[];
6568
+ pasteLayerStyle: (id: string) => boolean;
6426
6569
  /**
6427
- * Store-layer id targeted by Identify, or {@link IDENTIFY_ALL_LAYERS_ID} for
6428
- * the map-level mode that queries every visible queryable layer — vector,
6429
- * DuckDB query, WMS, COG, NetCDF image and time-slider raster alike.
6570
+ * Replace a layer's persistent attribute joins and immediately re-derive its
6571
+ * joined columns (strip what the previous joins added, apply the new list).
6572
+ * Pass an empty array to detach every join and restore the base attributes.
6430
6573
  */
6431
- identifyLayerId: string | null;
6432
- pointerCoords: [number, number] | null;
6574
+ setLayerJoins: (id: string, joins: LayerJoin[]) => void;
6433
6575
  /**
6434
- * Ground elevation in true metres under the pointer, for the status bar
6435
- * (issue #1813). Null when it cannot be resolved — the pointer is off the
6436
- * map, terrain is off and the remote lookup has not answered (or failed), or
6437
- * the active body is not Earth. Set alongside `pointerCoords` by MapCanvas,
6438
- * which owns the map instance the terrain sample comes from.
6576
+ * Replace the layer's Attribute Form designer configuration (per-field edit
6577
+ * widgets, constraints, conditional visibility). Pass `undefined` to remove
6578
+ * the form config entirely.
6439
6579
  */
6440
- pointerElevation: number | null;
6580
+ setLayerAttributeForm: (id: string, attributeForm: AttributeFormConfig | undefined) => void;
6441
6581
  /**
6442
- * Camera height above sea level in metres — Google Earth Pro's "Eye alt"
6443
- * (issue #1816). Derived from the camera, so deliberately *not* part of
6444
- * `mapView`: that shape is persisted into the project file, and a stored
6445
- * altitude could only drift from the center/zoom/pitch it is computed from.
6446
- * Null before the map loads, or when MapLibre cannot report it.
6582
+ * Replace the layer's popup/tooltip design (which fields the Identify popup
6583
+ * shows, in what order and under what labels, plus the hover tooltip). Pass
6584
+ * `undefined` to restore the default full-property dump.
6447
6585
  */
6448
- cameraAltitude: number | null;
6449
- /** Live GPS fix for the status bar, or null while GPS tracking is off. */
6450
- gpsStatus: GpsStatusFix | null;
6451
- /** Anchored review comments on map points or features (issue #1518). */
6452
- comments: ProjectComment[];
6453
- metadata: Record<string, unknown>;
6454
- recentProjects: RecentProjectEntry[];
6455
- attributeFilter: string;
6586
+ setLayerPopup: (id: string, popup: LayerPopupConfig | undefined) => void;
6456
6587
  /**
6457
- * What this *deployment* is allowed to do (issue #1673). Set once at startup
6458
- * from the deployment configuration; never from a project file, a URL
6459
- * parameter, or anything else the visitor controls, and never edited from the
6460
- * UI. Defaults to the full set so an unconfigured build behaves as before.
6461
- *
6462
- * Excluded from the project file and from undo history: it describes the
6463
- * server that served the app, not the document being edited.
6588
+ * Replace the layer's editor tracking configuration (whether creation/edit
6589
+ * author and timestamp columns are maintained, and under which names). Pass
6590
+ * `undefined` to drop the configuration entirely.
6464
6591
  */
6465
- deploymentCapabilities: ReadonlySet<DeploymentCapability>;
6466
- collaboration: CollaborationState;
6592
+ setLayerEditorTracking: (id: string, editorTracking: EditorTrackingConfig | undefined) => void;
6467
6593
  /**
6468
- * Ephemeral application capability model (issue #1672). Gating role and
6469
- * privileges for the current session/deployment. Excluded from the project file
6470
- * and undo history.
6594
+ * Replace a layer's virtual fields and immediately re-derive its computed
6595
+ * columns (strip what the previous fields added, evaluate the new list).
6596
+ * Pass an empty array to detach every virtual field.
6471
6597
  */
6472
- capabilities: AppCapabilities;
6473
- ui: {
6474
- processingOpen: boolean;
6475
- /**
6476
- * Tool id to preselect when the Whitebox toolbox dialog opens, set when the
6477
- * user picks a specific tool from the Processing menu's category submenus.
6478
- * Consumed and cleared by ProcessingDialog. Null means "no preselection".
6479
- */
6480
- processingInitialTool: string | null;
6481
- conversionOpen: ConversionToolKind | null;
6482
- vectorToolOpen: VectorToolKind | null;
6483
- networkToolOpen: NetworkToolKind | null;
6484
- statisticsToolOpen: StatisticsToolKind | null;
6485
- rasterToolOpen: RasterToolKind | null;
6486
- segmentationOpen: boolean;
6487
- objectDetectionOpen: boolean;
6488
- segmentEverythingOpen: boolean;
6489
- geocodeOpen: boolean;
6490
- sqlWorkspaceOpen: boolean;
6491
- loadEditorFeaturesOpen: boolean;
6492
- loadEditorFeaturesLayerId: string | null;
6493
- pythonConsoleOpen: boolean;
6494
- notebookOpen: boolean;
6495
- assistantOpen: boolean;
6496
- attributeTableOpen: boolean;
6497
- /** Whether the Raster Attribute Table bottom panel is open (issue #1307). */
6498
- rasterAttributeTableOpen: boolean;
6499
- dashboardOpen: boolean;
6500
- storymapPanelOpen: boolean;
6501
- storymapPresenting: boolean;
6502
- storymapReturnToEditor: boolean;
6503
- /**
6504
- * Layer opacities the active story presentation has applied so far, keyed
6505
- * by store layer id. Playback fades layers by writing MapLibre paint
6506
- * properties directly (never the persisted `layers[].opacity`), so this is
6507
- * how renderers outside MapLibre's paint model (deck.gl diagrams, 3D
6508
- * Z-value geometry) and the on-map Legend follow a chapter's fades. Empty
6509
- * while not presenting; never saved with the project.
6510
- */
6511
- storymapLayerOpacity: Record<string, number>;
6512
- storymapComposingId: string | null;
6513
- /** The Batch tools dialog (run one tool across many layers). */
6514
- batchToolsOpen: boolean;
6515
- /** The Model Builder canvas panel (author a processing graph). */
6516
- modelBuilderOpen: boolean;
6517
- /** One-shot request for Model Builder to load a saved model. */
6518
- modelBuilderRequestedModelId: string | null;
6519
- /** Style Manager dialog visibility (issue #1294). */
6520
- styleManagerOpen: boolean;
6521
- /** Processing History panel visibility (#1292). */
6522
- processingHistoryOpen: boolean;
6523
- /** Select by Expression dialog visibility (#1314). */
6524
- selectByExpressionOpen: boolean;
6525
- selectByExpressionLayerId: string | null;
6526
- /** Select by Location dialog visibility (#1314). */
6527
- selectByLocationOpen: boolean;
6528
- /** Same contract as `selectByExpressionLayerId`, for Select by Location. */
6529
- selectByLocationLayerId: string | null;
6598
+ setLayerVirtualFields: (id: string, fields: LayerVirtualField[]) => void;
6599
+ /**
6600
+ * Replace a layer's quick filters (issue #2114). The controls persist with
6601
+ * the project and are compiled to a MapLibre filter at sync time, so this
6602
+ * only stores state — nothing re-derives the layer's data. Pass an empty
6603
+ * array to remove every control.
6604
+ */
6605
+ setLayerQuickFilters: (id: string, filters: LayerQuickFilter[]) => void;
6606
+ /** Set or clear the project-persisted expression filter for a layer. */
6607
+ setLayerFilterExpression: (id: string, expression: unknown[] | null) => void;
6608
+ reorderLayer: (id: string, direction: "up" | "down") => void;
6609
+ moveLayer: (id: string, targetIndex: number) => void;
6610
+ moveLayersRelative: (layerIds: string[], targetLayerId: string, position: "above" | "below") => void;
6611
+ addGeoJsonLayer: (name: string, geojson: FeatureCollection, sourcePath?: string, beforeLayerId?: string | null) => string;
6612
+ /**
6613
+ * Add a georeferenced image overlay (a MapLibre `image` source rendered as a
6614
+ * raster layer) from an image URL and its four corner coordinates, and return
6615
+ * its id. Used for KML/KMZ `<GroundOverlay>` imports; the layer persists and
6616
+ * renders exactly like a Raster Georeferencer overlay. Corners are `[lng,
6617
+ * lat]` in top-left, top-right, bottom-right, bottom-left order.
6618
+ */
6619
+ addImageOverlayLayer: (name: string, source: {
6620
+ url: string;
6621
+ coordinates: [number, number][];
6622
+ }, options?: {
6623
+ opacity?: number;
6624
+ bounds?: [number, number, number, number];
6625
+ sourcePath?: string;
6626
+ /** Initial visibility (default true); a time-slider frame past the first
6627
+ * starts hidden. */
6628
+ visible?: boolean;
6629
+ /** Epoch-ms time bounds of a KML `<TimeSpan>`/`<TimeStamp>` frame; the
6630
+ * Time Slider toggles this frame's visibility by the current date. */
6631
+ timeSpan?: {
6632
+ begin: number | null;
6633
+ end: number | null;
6634
+ };
6530
6635
  /**
6531
- * Pending "re-run from History" request. Written by the History panel just
6532
- * before it opens the target processing dialog; consumed and cleared by
6533
- * that dialog once it has pre-filled its parameter form. Null when idle.
6636
+ * What produced the overlay, e.g. a NetCDF grid baked to pixels. Defaults
6637
+ * to the KML ground overlay this was first written for; panels gate their
6638
+ * per-source controls on it.
6534
6639
  */
6535
- processingRerun: ProcessingRerunRequest | null;
6536
- zoomToSelectedFeature: boolean;
6537
- collaborateDialogOpen: boolean;
6538
- };
6539
- setPointerCoords: (coords: [number, number] | null) => void;
6540
- setPointerElevation: (elevation: number | null) => void;
6541
- setCameraAltitude: (altitude: number | null) => void;
6542
- setGpsStatus: (fix: GpsStatusFix | null) => void;
6543
- setCollaboration: (patch: Partial<CollaborationState>) => void;
6544
- updateCollaborationPresence: (clientId: string, presence: CollaborationPresence | null) => void;
6545
- /** Append a chat message to the session log (bounded; #754). */
6546
- addCollaborationChat: (message: CollaborationChatMessage) => void;
6547
- resetCollaboration: () => void;
6548
- setMapView: (view: Partial<MapViewState>, markDirty?: boolean) => void;
6640
+ sourceKind?: string;
6641
+ /** Extra metadata merged onto the layer (e.g. a symbology record). */
6642
+ metadata?: Record<string, unknown>;
6643
+ }, beforeLayerId?: string | null) => string;
6549
6644
  /**
6550
- * Resize the map grid. Clamps `rows`/`cols` into range and grows/shrinks
6551
- * `secondaryMapViews` so it always holds `rows * cols - 1` panes; new panes
6552
- * clone the primary map's current camera and basemap.
6645
+ * Add a native raster tile layer (XYZ, WMS, or WMTS) from one or more tile
6646
+ * URL templates and return its id. The layer appears in the Layers panel and
6647
+ * persists with the project exactly like a layer added through the Add Data
6648
+ * dialog, so callers (e.g. an external plugin) do not have to touch MapLibre
6649
+ * directly. See {@link AddTileLayerOptions}.
6553
6650
  */
6554
- setMapGrid: (rows: number, cols: number) => void;
6555
- /** Toggle synchronized camera across all panes. */
6556
- setSyncView: (syncView: boolean) => void;
6557
- /** Patch one secondary pane's camera by id (no-op if the id is unknown). */
6558
- setSecondaryMapView: (id: string, view: Partial<MapViewState>, markDirty?: boolean) => void;
6651
+ addTileLayer: (name: string, options: AddTileLayerOptions, beforeLayerId?: string | null) => string;
6652
+ }
6653
+ //#endregion
6654
+ //#region src/store/libraries-slice.d.ts
6655
+ interface LibrariesSlice {
6559
6656
  /**
6560
- * Override a layer's visibility in one secondary pane (no-op if the pane id is
6561
- * unknown). The override forces the layer visible/hidden in that pane only,
6562
- * independent of the primary map's visibility.
6657
+ * App-level Style Manager library (issue #1294). Lives outside the project
6658
+ * lifecycle: never serialized into the project file, untouched by
6659
+ * newProject/loadProject, and persisted by the desktop app (IndexedDB).
6563
6660
  */
6564
- setSecondaryLayerVisibility: (id: string, layerId: string, visible: boolean) => void;
6565
- /** Set the primary pane's custom label. */
6566
- setPrimaryMapLabel: (label: string) => void;
6661
+ styleLibrary: StyleLibraryEntry[];
6567
6662
  /**
6568
- * Switch the primary map area between the 2D map and the 3D globe (no-op if
6569
- * unchanged). Touches nothing else in the store, so the shared camera, layer,
6570
- * and basemap state carries straight across the swap.
6663
+ * App-level Layer Library (issue #1520) — the Browser panel's My Data
6664
+ * section. Like {@link styleLibrary} it lives outside the project lifecycle:
6665
+ * never serialized into the project file, untouched by newProject/loadProject,
6666
+ * and persisted by the desktop app (IndexedDB). Most recently saved first.
6571
6667
  */
6572
- setPrimaryRenderer: (renderer: MapRendererKind) => void;
6573
- /** Set one secondary pane's custom label (no-op if the id is unknown). */
6574
- setSecondaryMapLabel: (id: string, label: string) => void;
6668
+ layerLibrary: LayerLibraryEntry[];
6575
6669
  /**
6576
- * Switch one secondary pane between the 2D map and the 3D globe (no-op if the
6577
- * id is unknown or the kind is unchanged).
6670
+ * App-level Template Library. Persisted by the desktop app (IndexedDB).
6578
6671
  */
6579
- setSecondaryViewKind: (id: string, viewKind: NonNullable<SecondaryMapView["viewKind"]>) => void;
6580
- /** Remove one secondary pane and collapse the grid back toward 1x1. */
6581
- removeSecondaryMapView: (id: string) => void;
6582
- setBasemapStyleUrl: (url: string) => void;
6672
+ templateLibrary: ProjectTemplateEntry[];
6583
6673
  /**
6584
- * Apply a planetary basemap and sync the project's ellipsoid to the body it
6585
- * depicts, so measurements and the globe control use that body's radius. Used
6586
- * by both the basemap picker and the Layers-panel planet switcher.
6674
+ * Project-scoped Style Manager entries (issue #1294), serialized into the
6675
+ * `.geolibre.json` `styleLibrary` array and replaced on project load.
6587
6676
  */
6588
- applyPlanetaryBasemap: (basemap: PlanetaryBasemap) => void;
6677
+ projectStyleLibrary: StyleLibraryEntry[];
6589
6678
  /**
6590
- * Return to Earth: apply `styleUrl` (typically the Earth basemap that was
6591
- * active before a planet was selected, e.g. Liberty) and reset the ellipsoid
6592
- * to Earth. Used when a planet is deselected in the switcher.
6679
+ * Replace the app-level style library wholesale. Used by the persistence
6680
+ * layer on startup and by bundle imports.
6593
6681
  */
6594
- restoreEarthBasemap: (styleUrl: string) => void;
6595
- setBasemapVisible: (visible: boolean) => void;
6596
- setBasemapOpacity: (opacity: number) => void;
6597
- setBlankBackgroundColor: (color: string | null) => void;
6598
- setPreferences: (preferences: ProjectPreferences) => void;
6599
- setLegend: (legend: LegendConfig) => void;
6682
+ setStyleLibrary: (entries: StyleLibraryEntry[]) => void;
6600
6683
  /**
6601
- * Replace the Print Layout composer settings. A config equal to the current
6602
- * one is ignored, so re-opening the composer (or a project load seeding the
6603
- * dialog) never marks the project dirty.
6684
+ * Insert or replace (matching by `id`) a Style Manager entry in the given
6685
+ * scope. Scope-local, like {@link deleteStyleLibraryEntry}: the other
6686
+ * scope's list is never touched, since a same id there can belong to an
6687
+ * unrelated entry after loading a project authored elsewhere. Project-scope
6688
+ * saves mark the project dirty.
6604
6689
  */
6605
- setPrintLayout: (printLayout: PrintLayoutConfig) => void;
6606
- setProjectPlugins: (projectPlugins: ProjectPluginState | null, shouldMarkDirty?: boolean) => void;
6607
- selectLayer: (id: string | null) => void;
6608
- selectFeature: (id: string | null) => void;
6690
+ saveStyleLibraryEntry: (entry: StyleLibraryEntry, scope?: "app" | "project") => void;
6609
6691
  /**
6610
- * Replace the multi-selection with `ids`. The anchor (`selectedFeatureId`)
6611
- * becomes `anchorId` when provided, otherwise the last id in the list (or
6612
- * `null` when the list is empty).
6692
+ * Remove a Style Manager entry by id. When `scope` is given only that list
6693
+ * is touched — the two scopes can legitimately hold the same id after
6694
+ * loading a project authored elsewhere, and deleting a project entry must
6695
+ * not erase a local app-library style (or vice versa). Omitting `scope`
6696
+ * removes the id from both lists.
6613
6697
  */
6614
- selectFeatures: (ids: string[], anchorId?: string | null) => void;
6615
- setIdentifyLayer: (id: string | null) => void;
6616
- setAttributeFilter: (filter: string) => void;
6617
- setProcessingOpen: (open: boolean) => void;
6618
- setProcessingInitialTool: (toolId: string | null) => void;
6619
- setConversionOpen: (kind: ConversionToolKind | null) => void;
6620
- setVectorToolOpen: (kind: VectorToolKind | null) => void;
6621
- setNetworkToolOpen: (kind: NetworkToolKind | null) => void;
6622
- setStatisticsToolOpen: (kind: StatisticsToolKind | null) => void;
6623
- setRasterToolOpen: (kind: RasterToolKind | null) => void;
6624
- setSegmentationOpen: (open: boolean) => void;
6625
- setObjectDetectionOpen: (open: boolean) => void;
6626
- setSegmentEverythingOpen: (open: boolean) => void;
6627
- setGeocodeOpen: (open: boolean) => void;
6628
- setSqlWorkspaceOpen: (open: boolean) => void;
6629
- setLoadEditorFeaturesOpen: (open: boolean, layerId?: string | null) => void;
6630
- setPythonConsoleOpen: (open: boolean) => void;
6631
- setNotebookOpen: (open: boolean) => void;
6632
- setAssistantOpen: (open: boolean) => void;
6633
- setAttributeTableOpen: (open: boolean) => void;
6634
- setRasterAttributeTableOpen: (open: boolean) => void;
6635
- setDashboardOpen: (open: boolean) => void;
6636
- setStorymapPanelOpen: (open: boolean) => void;
6637
- setStorymapPresenting: (presenting: boolean, returnToEditor?: boolean) => void;
6698
+ deleteStyleLibraryEntry: (id: string, scope?: "app" | "project") => void;
6638
6699
  /**
6639
- * Record the layer opacities a story chapter applied, merging into the
6640
- * presentation's running map (see `ui.storymapLayerOpacity`).
6700
+ * Replace the app-level Layer Library wholesale. Used by the persistence
6701
+ * layer on startup and by bundle imports.
6641
6702
  */
6642
- setStorymapLayerOpacity: (changes: Record<string, number>) => void;
6643
- setStorymapComposing: (chapterId: string | null) => void;
6644
- setBatchToolsOpen: (open: boolean) => void;
6645
- setModelBuilderOpen: (open: boolean) => void;
6646
- setModelBuilderRequestedModelId: (id: string | null) => void;
6647
- setProcessingHistoryOpen: (open: boolean) => void;
6648
- /** Open/close Select by Expression, optionally preselecting a target layer. */
6649
- setSelectByExpressionOpen: (open: boolean, layerId?: string | null) => void;
6650
- /** Open/close Select by Location, optionally preselecting a target layer. */
6651
- setSelectByLocationOpen: (open: boolean, layerId?: string | null) => void;
6652
- setProcessingRerun: (request: ProcessingRerunRequest | null) => void;
6653
- setCollaborateDialogOpen: (open: boolean) => void;
6654
- setZoomToSelectedFeature: (enabled: boolean) => void;
6655
- setStyleManagerOpen: (open: boolean) => void;
6703
+ setLayerLibrary: (entries: LayerLibraryEntry[]) => void;
6704
+ /**
6705
+ * Insert or replace (matching by `id`) a Layer Library entry. New entries go
6706
+ * to the front so the most recently saved layer leads the My Data section.
6707
+ */
6708
+ saveLayerLibraryEntry: (entry: LayerLibraryEntry) => void;
6709
+ /** Rename a Layer Library entry; a blank name is ignored. */
6710
+ renameLayerLibraryEntry: (id: string, name: string) => void;
6711
+ /** Remove a Layer Library entry by id. */
6712
+ deleteLayerLibraryEntry: (id: string) => void;
6713
+ /** Replace the app-level template library wholesale. */
6714
+ setTemplateLibrary: (templates: ProjectTemplateEntry[]) => void;
6715
+ /** Insert or replace a template in the Template Library. */
6716
+ saveTemplateEntry: (entry: ProjectTemplateEntry) => void;
6717
+ /** Remove a template entry by id from the Template Library. */
6718
+ deleteTemplateEntry: (id: string) => void;
6719
+ }
6720
+ //#endregion
6721
+ //#region src/store/map-view-slice.d.ts
6722
+ interface MapViewSlice {
6723
+ mapView: MapViewState;
6724
+ basemapStyleUrl: string;
6725
+ basemapVisible: boolean;
6726
+ basemapOpacity: number;
6727
+ blankBackgroundColor: string | null;
6728
+ preferences: ProjectPreferences;
6729
+ /**
6730
+ * Multi-map grid layout (issue: split/grid view). A 1x1 grid is the normal
6731
+ * single-map workspace. `rows * cols` panes are shown; pane 0 is the primary
6732
+ * map driven by `mapView` / `basemap*`, panes 1.. are `secondaryMapViews`.
6733
+ */
6734
+ mapLayout: MapGridLayout;
6735
+ /**
6736
+ * Secondary map panes (everything past the primary pane). The store keeps
6737
+ * exactly `rows * cols - 1` entries in sync with `mapLayout`.
6738
+ */
6739
+ secondaryMapViews: SecondaryMapView[];
6740
+ /** User-entered label for the primary pane (shown only in multi-map mode). */
6741
+ primaryMapLabel: string;
6742
+ /**
6743
+ * Which engine draws the primary map area (issue #2217): the 2D MapLibre map
6744
+ * or the 3D Cesium globe. Both render the same store state, so switching
6745
+ * keeps the camera, basemap, layers, groups, visibility, and opacity — it
6746
+ * only changes what draws them. Independent of `mapLayout`: switching never
6747
+ * adds or removes panes.
6748
+ */
6749
+ primaryRenderer: MapRendererKind;
6750
+ setMapView: (view: Partial<MapViewState>, markDirty?: boolean) => void;
6656
6751
  /**
6657
- * Replace the app-level style library wholesale. Used by the persistence
6658
- * layer on startup and by bundle imports.
6752
+ * Resize the map grid. Clamps `rows`/`cols` into range and grows/shrinks
6753
+ * `secondaryMapViews` so it always holds `rows * cols - 1` panes; new panes
6754
+ * clone the primary map's current camera and basemap.
6659
6755
  */
6660
- setStyleLibrary: (entries: StyleLibraryEntry[]) => void;
6756
+ setMapGrid: (rows: number, cols: number) => void;
6757
+ /** Toggle synchronized camera across all panes. */
6758
+ setSyncView: (syncView: boolean) => void;
6759
+ /** Patch one secondary pane's camera by id (no-op if the id is unknown). */
6760
+ setSecondaryMapView: (id: string, view: Partial<MapViewState>, markDirty?: boolean) => void;
6661
6761
  /**
6662
- * Insert or replace (matching by `id`) a Style Manager entry in the given
6663
- * scope. Scope-local, like {@link deleteStyleLibraryEntry}: the other
6664
- * scope's list is never touched, since a same id there can belong to an
6665
- * unrelated entry after loading a project authored elsewhere. Project-scope
6666
- * saves mark the project dirty.
6762
+ * Override a layer's visibility in one secondary pane (no-op if the pane id is
6763
+ * unknown). The override forces the layer visible/hidden in that pane only,
6764
+ * independent of the primary map's visibility.
6667
6765
  */
6668
- saveStyleLibraryEntry: (entry: StyleLibraryEntry, scope?: "app" | "project") => void;
6766
+ setSecondaryLayerVisibility: (id: string, layerId: string, visible: boolean) => void;
6767
+ /** Set the primary pane's custom label. */
6768
+ setPrimaryMapLabel: (label: string) => void;
6669
6769
  /**
6670
- * Remove a Style Manager entry by id. When `scope` is given only that list
6671
- * is touched — the two scopes can legitimately hold the same id after
6672
- * loading a project authored elsewhere, and deleting a project entry must
6673
- * not erase a local app-library style (or vice versa). Omitting `scope`
6674
- * removes the id from both lists.
6770
+ * Switch the primary map area between the 2D map and the 3D globe (no-op if
6771
+ * unchanged). Touches nothing else in the store, so the shared camera, layer,
6772
+ * and basemap state carries straight across the swap.
6675
6773
  */
6676
- deleteStyleLibraryEntry: (id: string, scope?: "app" | "project") => void;
6774
+ setPrimaryRenderer: (renderer: MapRendererKind) => void;
6775
+ /** Set one secondary pane's custom label (no-op if the id is unknown). */
6776
+ setSecondaryMapLabel: (id: string, label: string) => void;
6677
6777
  /**
6678
- * Replace the app-level Layer Library wholesale. Used by the persistence
6679
- * layer on startup and by bundle imports.
6778
+ * Switch one secondary pane between the 2D map and the 3D globe (no-op if the
6779
+ * id is unknown or the kind is unchanged).
6680
6780
  */
6681
- setLayerLibrary: (entries: LayerLibraryEntry[]) => void;
6781
+ setSecondaryViewKind: (id: string, viewKind: NonNullable<SecondaryMapView["viewKind"]>) => void;
6782
+ /** Remove one secondary pane and collapse the grid back toward 1x1. */
6783
+ removeSecondaryMapView: (id: string) => void;
6784
+ setBasemapStyleUrl: (url: string) => void;
6682
6785
  /**
6683
- * Insert or replace (matching by `id`) a Layer Library entry. New entries go
6684
- * to the front so the most recently saved layer leads the My Data section.
6786
+ * Apply a planetary basemap and sync the project's ellipsoid to the body it
6787
+ * depicts, so measurements and the globe control use that body's radius. Used
6788
+ * by both the basemap picker and the Layers-panel planet switcher.
6685
6789
  */
6686
- saveLayerLibraryEntry: (entry: LayerLibraryEntry) => void;
6687
- /** Rename a Layer Library entry; a blank name is ignored. */
6688
- renameLayerLibraryEntry: (id: string, name: string) => void;
6689
- /** Remove a Layer Library entry by id. */
6690
- deleteLayerLibraryEntry: (id: string) => void;
6691
- /** Replace the app-level template library wholesale. */
6692
- setTemplateLibrary: (templates: ProjectTemplateEntry[]) => void;
6693
- /** Insert or replace a template in the Template Library. */
6694
- saveTemplateEntry: (entry: ProjectTemplateEntry) => void;
6695
- /** Remove a template entry by id from the Template Library. */
6696
- deleteTemplateEntry: (id: string) => void;
6790
+ applyPlanetaryBasemap: (basemap: PlanetaryBasemap) => void;
6791
+ /**
6792
+ * Return to Earth: apply `styleUrl` (typically the Earth basemap that was
6793
+ * active before a planet was selected, e.g. Liberty) and reset the ellipsoid
6794
+ * to Earth. Used when a planet is deselected in the switcher.
6795
+ */
6796
+ restoreEarthBasemap: (styleUrl: string) => void;
6797
+ setBasemapVisible: (visible: boolean) => void;
6798
+ setBasemapOpacity: (opacity: number) => void;
6799
+ setBlankBackgroundColor: (color: string | null) => void;
6800
+ setPreferences: (preferences: ProjectPreferences) => void;
6801
+ }
6802
+ //#endregion
6803
+ //#region src/store/processing-slice.d.ts
6804
+ interface ProcessingSlice {
6805
+ /** Saved processing pipelines (batch/model chaining; issue #344). */
6806
+ models: ProcessingModel[];
6807
+ /** Recorded processing tool runs, oldest first (Processing History; #1292). */
6808
+ processingHistory: ProcessingRun[];
6697
6809
  /** Insert a new model or replace an existing one matching by `id`. */
6698
6810
  saveModel: (model: ProcessingModel) => void;
6699
6811
  /** Remove a saved model by id. */
@@ -6704,6 +6816,17 @@ interface AppState {
6704
6816
  updateProcessingRun: (id: string, patch: Partial<Omit<ProcessingRun, "id">>) => void;
6705
6817
  /** Drop all recorded processing runs. */
6706
6818
  clearProcessingHistory: () => void;
6819
+ }
6820
+ //#endregion
6821
+ //#region src/store/project-content-slice.d.ts
6822
+ interface ProjectContentSlice {
6823
+ storymap: StoryMap | null;
6824
+ /** Saved Dashboard panel chart widgets (issue #401). */
6825
+ widgets: DashboardWidget[];
6826
+ /** Number of columns in the Dashboard widget grid. */
6827
+ dashboardColumns: number;
6828
+ /** Anchored review comments on map points or features (issue #1518). */
6829
+ comments: ProjectComment[];
6707
6830
  /** Append a new dashboard widget. */
6708
6831
  addWidget: (widget: DashboardWidget) => void;
6709
6832
  /** Patch an existing dashboard widget by id (no-op if absent). Merges, so an
@@ -6726,6 +6849,35 @@ interface AppState {
6726
6849
  updateStoryChapter: (id: string, patch: Partial<StoryChapter>) => void;
6727
6850
  removeStoryChapter: (id: string) => void;
6728
6851
  moveStoryChapter: (id: string, targetIndex: number) => void;
6852
+ addComment: (comment: ProjectComment) => void;
6853
+ replyToComment: (commentId: string, reply: CommentReply) => void;
6854
+ toggleResolveComment: (commentId: string, resolved?: boolean) => void;
6855
+ deleteComment: (commentId: string) => void;
6856
+ setComments: (comments: ProjectComment[]) => void;
6857
+ }
6858
+ //#endregion
6859
+ //#region src/store/project-slice.d.ts
6860
+ /** Derive a human-friendly display name from a file path or URL. */
6861
+ export declare function projectPathLabel(path: string): string;
6862
+ interface ProjectSlice {
6863
+ projectName: string;
6864
+ projectPath: string | null;
6865
+ projectGeneration: number;
6866
+ isDirty: boolean;
6867
+ projectPlugins: ProjectPluginState | null;
6868
+ legend: LegendConfig;
6869
+ /** Print Layout composer settings for the open project (discussion #1992). */
6870
+ printLayout: PrintLayoutConfig;
6871
+ metadata: Record<string, unknown>;
6872
+ recentProjects: RecentProjectEntry[];
6873
+ setLegend: (legend: LegendConfig) => void;
6874
+ /**
6875
+ * Replace the Print Layout composer settings. A config equal to the current
6876
+ * one is ignored, so re-opening the composer (or a project load seeding the
6877
+ * dialog) never marks the project dirty.
6878
+ */
6879
+ setPrintLayout: (printLayout: PrintLayoutConfig) => void;
6880
+ setProjectPlugins: (projectPlugins: ProjectPluginState | null, shouldMarkDirty?: boolean) => void;
6729
6881
  newProject: (options?: CreateProjectOptions & {
6730
6882
  name?: string;
6731
6883
  }) => void;
@@ -6735,179 +6887,223 @@ interface AppState {
6735
6887
  }) => void;
6736
6888
  setProjectPath: (path: string | null) => void;
6737
6889
  setProjectName: (name: string) => void;
6738
- /**
6739
- * Narrow what this deployment may do. Intended for the startup path only —
6740
- * calling it later would leave already-rendered surfaces stale.
6741
- */
6742
- setDeploymentCapabilities: (capabilities: Iterable<DeploymentCapability>) => void;
6743
6890
  setRecentProjects: (projects: RecentProjectEntry[]) => void;
6744
6891
  rememberRecentProject: (entry: RecentProjectEntry) => void;
6745
6892
  forgetRecentProject: (path: string) => void;
6746
6893
  clearRecentProjects: () => void;
6747
6894
  markSaved: () => void;
6895
+ }
6896
+ //#endregion
6897
+ //#region src/store/session-slice.d.ts
6898
+ /**
6899
+ * Latest live device-GPS fix published by the GPS Tracking tool (issue #1316),
6900
+ * read by the status bar readout. Device state, not project state: excluded
6901
+ * from undo history (partialize never lists it) and from project files, and
6902
+ * deliberately left untouched on project switches.
6903
+ */
6904
+ interface GpsStatusFix {
6905
+ lng: number;
6906
+ lat: number;
6907
+ /** Horizontal accuracy radius in meters. */
6908
+ accuracy: number;
6909
+ /** Satellites used for the fix, or null when the provider does not report it. */
6910
+ satellites: number | null;
6911
+ /** Ground speed in m/s, or null when the device doesn't report one. */
6912
+ speed: number | null;
6913
+ /** Fix time in epoch milliseconds. */
6914
+ timestamp: number;
6915
+ }
6916
+ /** Reserved Identify target for querying every visible queryable layer at once. */
6917
+ export declare const IDENTIFY_ALL_LAYERS_ID = "__geolibre_identify_all_layers__";
6918
+ interface SessionSlice {
6919
+ selectedLayerId: string | null;
6920
+ selectedFeatureId: string | null;
6748
6921
  /**
6749
- * Assign an application role (e.g. "viewer", "editor", "publisher", "administrator", "custom"),
6750
- * deriving the effective privileges and optional reason.
6751
- */
6752
- setAppRole: (role: AppRole, options?: {
6753
- customPrivileges?: AppPrivilege[];
6754
- reason?: string;
6755
- }) => void;
6756
- /** Set explicit custom privileges and an optional reason. */
6757
- setAppPrivileges: (privileges: AppPrivilege[], reason?: string) => void;
6758
- /** Grant an individual application privilege. */
6759
- grantAppPrivilege: (privilege: AppPrivilege) => void;
6760
- /** Revoke an individual application privilege with an optional reason. */
6761
- revokeAppPrivilege: (privilege: AppPrivilege, reason?: string) => void;
6762
- /** Reset application capabilities back to the default unconstrained Administrator role. */
6763
- resetAppCapabilities: () => void;
6764
- /** Check if the current capabilities grant the requested privilege. */
6765
- hasAppPrivilege: (privilege: AppPrivilege) => boolean;
6766
- addLayer: (layer: GeoLibreLayer, beforeLayerId?: string | null) => void;
6767
- removeLayer: (id: string) => void;
6768
- updateLayer: (id: string, patch: Partial<GeoLibreLayer>) => void;
6769
- setLayerVisibility: (id: string, visible: boolean) => void;
6770
- setLayerOpacity: (id: string, opacity: number) => void;
6771
- setLayerStyle: (id: string, style: Partial<LayerStyle>) => void;
6772
- /**
6773
- * Transient clipboard holding a layer's symbology, captured by
6774
- * {@link copyLayerStyle} and applied by {@link pasteLayerStyle} (copy/paste
6775
- * styles, issue #1339). Runtime-only: excluded from undo history
6776
- * (`partialize` never lists it) and from the saved project. `null` until a
6777
- * style is copied this session. Cleared by `newProject`/`loadProject` so a
6778
- * paste can't apply an entry from a different project; it deliberately
6779
- * survives undo/redo within a project (it holds a deep snapshot, not a live
6780
- * layer reference, so a paste stays valid even if the source layer is undone
6781
- * away — only the displayed source name may then be stale).
6782
- */
6783
- copiedLayerStyle: CopiedLayerStyle | null;
6784
- /**
6785
- * Snapshot the given layer's style into {@link copiedLayerStyle} so it can be
6786
- * pasted onto a compatible layer. No-op when the layer is missing or has no
6787
- * copyable symbology (leaving any prior clipboard entry untouched). Returns
6788
- * `true` when a style was captured, so callers can skip the confirmation on a
6789
- * no-op.
6790
- */
6791
- copyLayerStyle: (id: string) => boolean;
6792
- /**
6793
- * Apply the {@link copiedLayerStyle} clipboard entry onto the given layer.
6794
- * No-op when the clipboard is empty, the layer is missing, or the entry's
6795
- * style family does not match the target layer's. Returns `true` when the
6796
- * style was applied, so callers can skip the confirmation on a no-op.
6797
- */
6798
- pasteLayerStyle: (id: string) => boolean;
6799
- /**
6800
- * Replace a layer's persistent attribute joins and immediately re-derive its
6801
- * joined columns (strip what the previous joins added, apply the new list).
6802
- * Pass an empty array to detach every join and restore the base attributes.
6803
- */
6804
- setLayerJoins: (id: string, joins: LayerJoin[]) => void;
6805
- /**
6806
- * Replace the layer's Attribute Form designer configuration (per-field edit
6807
- * widgets, constraints, conditional visibility). Pass `undefined` to remove
6808
- * the form config entirely.
6809
- */
6810
- setLayerAttributeForm: (id: string, attributeForm: AttributeFormConfig | undefined) => void;
6811
- /**
6812
- * Replace the layer's popup/tooltip design (which fields the Identify popup
6813
- * shows, in what order and under what labels, plus the hover tooltip). Pass
6814
- * `undefined` to restore the default full-property dump.
6922
+ * Full set of selected feature ids. The attribute table extends the single
6923
+ * selection to many rows via Ctrl/Cmd (toggle) and Shift (range). The anchor
6924
+ * — `selectedFeatureId` — is the primary/last-clicked feature used for map
6925
+ * fit, DuckDB highlight, and scripting, and is always one of these ids (or
6926
+ * `null` when the set is empty). A single click leaves exactly one id here.
6815
6927
  */
6816
- setLayerPopup: (id: string, popup: LayerPopupConfig | undefined) => void;
6928
+ selectedFeatureIds: string[];
6817
6929
  /**
6818
- * Replace the layer's editor tracking configuration (whether creation/edit
6819
- * author and timestamp columns are maintained, and under which names). Pass
6820
- * `undefined` to drop the configuration entirely.
6930
+ * Store-layer id targeted by Identify, or {@link IDENTIFY_ALL_LAYERS_ID} for
6931
+ * the map-level mode that queries every visible queryable layer — vector,
6932
+ * DuckDB query, WMS, COG, NetCDF image and time-slider raster alike.
6821
6933
  */
6822
- setLayerEditorTracking: (id: string, editorTracking: EditorTrackingConfig | undefined) => void;
6934
+ identifyLayerId: string | null;
6935
+ pointerCoords: [number, number] | null;
6823
6936
  /**
6824
- * Replace a layer's virtual fields and immediately re-derive its computed
6825
- * columns (strip what the previous fields added, evaluate the new list).
6826
- * Pass an empty array to detach every virtual field.
6937
+ * Ground elevation in true metres under the pointer, for the status bar
6938
+ * (issue #1813). Null when it cannot be resolved — the pointer is off the
6939
+ * map, terrain is off and the remote lookup has not answered (or failed), or
6940
+ * the active body is not Earth. Set alongside `pointerCoords` by MapCanvas,
6941
+ * which owns the map instance the terrain sample comes from.
6827
6942
  */
6828
- setLayerVirtualFields: (id: string, fields: LayerVirtualField[]) => void;
6943
+ pointerElevation: number | null;
6829
6944
  /**
6830
- * Replace a layer's quick filters (issue #2114). The controls persist with
6831
- * the project and are compiled to a MapLibre filter at sync time, so this
6832
- * only stores state — nothing re-derives the layer's data. Pass an empty
6833
- * array to remove every control.
6834
- */
6835
- setLayerQuickFilters: (id: string, filters: LayerQuickFilter[]) => void;
6836
- /** Set or clear the project-persisted expression filter for a layer. */
6837
- setLayerFilterExpression: (id: string, expression: unknown[] | null) => void;
6838
- reorderLayer: (id: string, direction: "up" | "down") => void;
6839
- moveLayer: (id: string, targetIndex: number) => void;
6840
- moveLayersRelative: (layerIds: string[], targetLayerId: string, position: "above" | "below") => void;
6841
- addGeoJsonLayer: (name: string, geojson: FeatureCollection, sourcePath?: string, beforeLayerId?: string | null) => string;
6945
+ * Camera height above sea level in metres — Google Earth Pro's "Eye alt"
6946
+ * (issue #1816). Derived from the camera, so deliberately *not* part of
6947
+ * `mapView`: that shape is persisted into the project file, and a stored
6948
+ * altitude could only drift from the center/zoom/pitch it is computed from.
6949
+ * Null before the map loads, or when MapLibre cannot report it.
6950
+ */
6951
+ cameraAltitude: number | null;
6952
+ /** Live GPS fix for the status bar, or null while GPS tracking is off. */
6953
+ gpsStatus: GpsStatusFix | null;
6954
+ attributeFilter: string;
6955
+ setPointerCoords: (coords: [number, number] | null) => void;
6956
+ setPointerElevation: (elevation: number | null) => void;
6957
+ setCameraAltitude: (altitude: number | null) => void;
6958
+ setGpsStatus: (fix: GpsStatusFix | null) => void;
6959
+ selectLayer: (id: string | null) => void;
6960
+ selectFeature: (id: string | null) => void;
6842
6961
  /**
6843
- * Add a georeferenced image overlay (a MapLibre `image` source rendered as a
6844
- * raster layer) from an image URL and its four corner coordinates, and return
6845
- * its id. Used for KML/KMZ `<GroundOverlay>` imports; the layer persists and
6846
- * renders exactly like a Raster Georeferencer overlay. Corners are `[lng,
6847
- * lat]` in top-left, top-right, bottom-right, bottom-left order.
6962
+ * Replace the multi-selection with `ids`. The anchor (`selectedFeatureId`)
6963
+ * becomes `anchorId` when provided, otherwise the last id in the list (or
6964
+ * `null` when the list is empty).
6848
6965
  */
6849
- addImageOverlayLayer: (name: string, source: {
6850
- url: string;
6851
- coordinates: [number, number][];
6852
- }, options?: {
6853
- opacity?: number;
6854
- bounds?: [number, number, number, number];
6855
- sourcePath?: string;
6856
- /** Initial visibility (default true); a time-slider frame past the first
6857
- * starts hidden. */
6858
- visible?: boolean;
6859
- /** Epoch-ms time bounds of a KML `<TimeSpan>`/`<TimeStamp>` frame; the
6860
- * Time Slider toggles this frame's visibility by the current date. */
6861
- timeSpan?: {
6862
- begin: number | null;
6863
- end: number | null;
6864
- };
6966
+ selectFeatures: (ids: string[], anchorId?: string | null) => void;
6967
+ setIdentifyLayer: (id: string | null) => void;
6968
+ setAttributeFilter: (filter: string) => void;
6969
+ }
6970
+ //#endregion
6971
+ //#region src/store/ui-slice.d.ts
6972
+ type ConversionToolKind = "vector-to-vector" | "vector-to-geoparquet" | "vector-to-flatgeobuf" | "vector-to-shapefile" | "vector-to-geopackage" | "csv-to-geoparquet" | "vector-to-pmtiles" | "raster-to-pmtiles" | "raster-to-cog";
6973
+ /**
6974
+ * Identifiers of the vector processing tools. Kept in sync by hand with the
6975
+ * `id` fields of `VECTOR_TOOLS` in `@geolibre/processing` (`vector-tools.ts`);
6976
+ * deriving the type there would create a core -> processing circular import.
6977
+ */
6978
+ type VectorToolKind = "buffer" | "centroids" | "convex-hull" | "dissolve" | "bounding-box" | "simplify" | "clip" | "intersection" | "difference" | "union" | "spatial-join" | "attribute-join" | "select-by-value" | "select-by-location" | "random-extract" | "reproject" | "explode" | "aggregate" | "smooth" | "extract-vertices" | "points-along-geometry" | "grid" | "voronoi" | "cell-sectors" | "dggs-grid" | "dggs-bin" | "dggs-compact" | "trajectory-speed" | "detect-stops" | "space-time-proximity" | "decode-polyline" | "encode-polyline" | "merge-layers" | "check-validity" | "fix-geometries" | "check-topology-rules" | "fix-topology";
6979
+ /** Identifiers of the network-analysis tools (`NETWORK_TOOLS` ids). */
6980
+ type NetworkToolKind = "isochrone" | "od-matrix" | "sequential-route";
6981
+ /** Identifiers of the spatial-statistics tools (`STATISTICS_TOOLS` ids). */
6982
+ type StatisticsToolKind = "global-morans-i" | "local-morans-i" | "getis-ord-gi" | "average-nearest-neighbor" | "kernel-density" | "emerging-hot-spot" | "composite-score";
6983
+ /**
6984
+ * Identifiers of the raster processing tools. Kept in sync by hand with the
6985
+ * `id` fields of `RASTER_TOOLS` in `@geolibre/processing` (`raster-tools.ts`);
6986
+ * deriving the type there would create a core -> processing circular import.
6987
+ */
6988
+ type RasterToolKind = "hillshade" | "slope" | "aspect" | "reproject" | "resample" | "clip-extent" | "clip-mask" | "polygonize" | "contour" | "interpolate" | "zonal" | "raster-calc" | "spectral-index" | "reclassify" | "mosaic" | "focal";
6989
+ interface UiSlice {
6990
+ ui: {
6991
+ processingOpen: boolean;
6865
6992
  /**
6866
- * What produced the overlay, e.g. a NetCDF grid baked to pixels. Defaults
6867
- * to the KML ground overlay this was first written for; panels gate their
6868
- * per-source controls on it.
6993
+ * Tool id to preselect when the Whitebox toolbox dialog opens, set when the
6994
+ * user picks a specific tool from the Processing menu's category submenus.
6995
+ * Consumed and cleared by ProcessingDialog. Null means "no preselection".
6869
6996
  */
6870
- sourceKind?: string;
6871
- /** Extra metadata merged onto the layer (e.g. a symbology record). */
6872
- metadata?: Record<string, unknown>;
6873
- }, beforeLayerId?: string | null) => string;
6997
+ processingInitialTool: string | null;
6998
+ conversionOpen: ConversionToolKind | null;
6999
+ vectorToolOpen: VectorToolKind | null;
7000
+ networkToolOpen: NetworkToolKind | null;
7001
+ statisticsToolOpen: StatisticsToolKind | null;
7002
+ rasterToolOpen: RasterToolKind | null;
7003
+ segmentationOpen: boolean;
7004
+ objectDetectionOpen: boolean;
7005
+ segmentEverythingOpen: boolean;
7006
+ geocodeOpen: boolean;
7007
+ sqlWorkspaceOpen: boolean;
7008
+ loadEditorFeaturesOpen: boolean;
7009
+ loadEditorFeaturesLayerId: string | null;
7010
+ pythonConsoleOpen: boolean;
7011
+ notebookOpen: boolean;
7012
+ assistantOpen: boolean;
7013
+ attributeTableOpen: boolean;
7014
+ /** Whether the Raster Attribute Table bottom panel is open (issue #1307). */
7015
+ rasterAttributeTableOpen: boolean;
7016
+ dashboardOpen: boolean;
7017
+ storymapPanelOpen: boolean;
7018
+ storymapPresenting: boolean;
7019
+ storymapReturnToEditor: boolean;
7020
+ /**
7021
+ * Layer opacities the active story presentation has applied so far, keyed
7022
+ * by store layer id. Playback fades layers by writing MapLibre paint
7023
+ * properties directly (never the persisted `layers[].opacity`), so this is
7024
+ * how renderers outside MapLibre's paint model (deck.gl diagrams, 3D
7025
+ * Z-value geometry) and the on-map Legend follow a chapter's fades. Empty
7026
+ * while not presenting; never saved with the project.
7027
+ */
7028
+ storymapLayerOpacity: Record<string, number>;
7029
+ storymapComposingId: string | null;
7030
+ /** The Batch tools dialog (run one tool across many layers). */
7031
+ batchToolsOpen: boolean;
7032
+ /** The Model Builder canvas panel (author a processing graph). */
7033
+ modelBuilderOpen: boolean;
7034
+ /** One-shot request for Model Builder to load a saved model. */
7035
+ modelBuilderRequestedModelId: string | null;
7036
+ /** Style Manager dialog visibility (issue #1294). */
7037
+ styleManagerOpen: boolean;
7038
+ /** Processing History panel visibility (#1292). */
7039
+ processingHistoryOpen: boolean;
7040
+ /** Select by Expression dialog visibility (#1314). */
7041
+ selectByExpressionOpen: boolean;
7042
+ selectByExpressionLayerId: string | null;
7043
+ /** Select by Location dialog visibility (#1314). */
7044
+ selectByLocationOpen: boolean;
7045
+ /** Same contract as `selectByExpressionLayerId`, for Select by Location. */
7046
+ selectByLocationLayerId: string | null;
7047
+ /**
7048
+ * Pending "re-run from History" request. Written by the History panel just
7049
+ * before it opens the target processing dialog; consumed and cleared by
7050
+ * that dialog once it has pre-filled its parameter form. Null when idle.
7051
+ */
7052
+ processingRerun: ProcessingRerunRequest | null;
7053
+ zoomToSelectedFeature: boolean;
7054
+ collaborateDialogOpen: boolean;
7055
+ };
7056
+ setProcessingOpen: (open: boolean) => void;
7057
+ setProcessingInitialTool: (toolId: string | null) => void;
7058
+ setConversionOpen: (kind: ConversionToolKind | null) => void;
7059
+ setVectorToolOpen: (kind: VectorToolKind | null) => void;
7060
+ setNetworkToolOpen: (kind: NetworkToolKind | null) => void;
7061
+ setStatisticsToolOpen: (kind: StatisticsToolKind | null) => void;
7062
+ setRasterToolOpen: (kind: RasterToolKind | null) => void;
7063
+ setSegmentationOpen: (open: boolean) => void;
7064
+ setObjectDetectionOpen: (open: boolean) => void;
7065
+ setSegmentEverythingOpen: (open: boolean) => void;
7066
+ setGeocodeOpen: (open: boolean) => void;
7067
+ setSqlWorkspaceOpen: (open: boolean) => void;
7068
+ setLoadEditorFeaturesOpen: (open: boolean, layerId?: string | null) => void;
7069
+ setPythonConsoleOpen: (open: boolean) => void;
7070
+ setNotebookOpen: (open: boolean) => void;
7071
+ setAssistantOpen: (open: boolean) => void;
7072
+ setAttributeTableOpen: (open: boolean) => void;
7073
+ setRasterAttributeTableOpen: (open: boolean) => void;
7074
+ setDashboardOpen: (open: boolean) => void;
7075
+ setStorymapPanelOpen: (open: boolean) => void;
7076
+ setStorymapPresenting: (presenting: boolean, returnToEditor?: boolean) => void;
6874
7077
  /**
6875
- * Add a native raster tile layer (XYZ, WMS, or WMTS) from one or more tile
6876
- * URL templates and return its id. The layer appears in the Layers panel and
6877
- * persists with the project exactly like a layer added through the Add Data
6878
- * dialog, so callers (e.g. an external plugin) do not have to touch MapLibre
6879
- * directly. See {@link AddTileLayerOptions}.
7078
+ * Record the layer opacities a story chapter applied, merging into the
7079
+ * presentation's running map (see `ui.storymapLayerOpacity`).
6880
7080
  */
6881
- addTileLayer: (name: string, options: AddTileLayerOptions, beforeLayerId?: string | null) => string;
6882
- addLayerGroup: (name?: string, layerIds?: string[]) => string;
6883
- removeLayerGroup: (id: string, options?: {
6884
- removeChildren?: boolean;
6885
- }) => void;
6886
- renameLayerGroup: (id: string, name: string) => void;
6887
- setLayerGroupVisibility: (id: string, visible: boolean) => void;
6888
- setLayerGroupOpacity: (id: string, opacity: number) => void;
6889
- toggleLayerGroupCollapsed: (id: string) => void;
6890
- moveLayerToGroup: (layerId: string, groupId: string | null, beforeLayerId?: string | null) => void;
6891
- moveLayersToGroup: (layerIds: string[], groupId: string | null, beforeLayerId?: string | null) => void;
6892
- moveLayerGroupToGroup: (id: string, parentId: string | null) => void;
6893
- reorderLayerGroup: (id: string, direction: "up" | "down") => void;
6894
- addComment: (comment: ProjectComment) => void;
6895
- replyToComment: (commentId: string, reply: CommentReply) => void;
6896
- toggleResolveComment: (commentId: string, resolved?: boolean) => void;
6897
- deleteComment: (commentId: string) => void;
6898
- setComments: (comments: ProjectComment[]) => void;
7081
+ setStorymapLayerOpacity: (changes: Record<string, number>) => void;
7082
+ setStorymapComposing: (chapterId: string | null) => void;
7083
+ setBatchToolsOpen: (open: boolean) => void;
7084
+ setModelBuilderOpen: (open: boolean) => void;
7085
+ setModelBuilderRequestedModelId: (id: string | null) => void;
7086
+ setProcessingHistoryOpen: (open: boolean) => void;
7087
+ /** Open/close Select by Expression, optionally preselecting a target layer. */
7088
+ setSelectByExpressionOpen: (open: boolean, layerId?: string | null) => void;
7089
+ /** Open/close Select by Location, optionally preselecting a target layer. */
7090
+ setSelectByLocationOpen: (open: boolean, layerId?: string | null) => void;
7091
+ setProcessingRerun: (request: ProcessingRerunRequest | null) => void;
7092
+ setCollaborateDialogOpen: (open: boolean) => void;
7093
+ setZoomToSelectedFeature: (enabled: boolean) => void;
7094
+ setStyleManagerOpen: (open: boolean) => void;
6899
7095
  }
6900
- /** Reserved Identify target for querying every visible queryable layer at once. */
6901
- export declare const IDENTIFY_ALL_LAYERS_ID = "__geolibre_identify_all_layers__";
7096
+ //#endregion
7097
+ //#region src/store/types.d.ts
6902
7098
  /**
6903
- * A fresh, inactive collaboration slice (no live session). Frozen (like
6904
- * DEFAULT_LEGEND_CONFIG) to guard against accidental in-place mutation; store
6905
- * actions always produce new objects via spread, so the frozen default is only
6906
- * ever read.
7099
+ * The whole app store: every slice's state and actions in one flat object.
7100
+ * The slices are an internal split of `store.ts`; consumers see one store.
6907
7101
  */
6908
- export declare const DEFAULT_COLLABORATION_STATE: CollaborationState;
6909
- /** Derive a human-friendly display name from a file path or URL. */
6910
- export declare function projectPathLabel(path: string): string;
7102
+ interface AppState extends ProjectSlice, MapViewSlice, LayersSlice, LayerGroupsSlice, ProjectContentSlice, ProcessingSlice, LibrariesSlice, SessionSlice, CollaborationSlice, CapabilitiesSlice, UiSlice {}
7103
+ //#endregion
7104
+ //#region src/store/undo-history.d.ts
7105
+ /** The fields undo/redo snapshots, restores and compares. */
7106
+ type HistoryState = Pick<AppState, "layers" | "layerGroups" | "basemapStyleUrl" | "basemapVisible" | "basemapOpacity" | "blankBackgroundColor" | "storymap" | "comments">;
6911
7107
  export declare function subscribeProjectRestoreHistory(listener: () => void): () => void;
6912
7108
  export declare function canUndoProjectRestore(): boolean;
6913
7109
  export declare function canRedoProjectRestore(): boolean;
@@ -6918,18 +7114,6 @@ export declare function canRedoProjectRestore(): boolean;
6918
7114
  * serialized state, so it needs a full canonical project pair.
6919
7115
  */
6920
7116
  export declare function registerProjectRestoreHistory(before: GeoLibreProject, beforePath: string | null, after: GeoLibreProject, afterPath?: string | null): void;
6921
- export declare const useAppStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<AppState>, "temporal"> & {
6922
- temporal: import("zustand").StoreApi<import("zundo").TemporalState<{
6923
- layers: GeoLibreLayer[];
6924
- layerGroups: LayerGroup[];
6925
- basemapStyleUrl: string;
6926
- basemapVisible: boolean;
6927
- basemapOpacity: number;
6928
- blankBackgroundColor: string | null;
6929
- storymap: StoryMap | null;
6930
- comments: ProjectComment[];
6931
- }>>;
6932
- }>;
6933
7117
  /**
6934
7118
  * Step the layer/basemap history back one entry and mark the project dirty.
6935
7119
  * zundo restores the partialized slice via the store's set; the resulting new
@@ -6941,6 +7125,11 @@ export declare function undo(): void;
6941
7125
  export declare function redo(): void;
6942
7126
  /** Empty both the undo and redo stacks (e.g. on new/loaded project). */
6943
7127
  export declare function clearHistory(): void;
7128
+ //#endregion
7129
+ //#region src/store.d.ts
7130
+ export declare const useAppStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<AppState>, "temporal"> & {
7131
+ temporal: import("zustand").StoreApi<import("zundo").TemporalState<HistoryState>>;
7132
+ }>;
6944
7133
  /**
6945
7134
  * React hook for consuming application capability state for a specific privilege.
6946
7135
  *
@@ -6952,6 +7141,109 @@ export declare function useAppCapability(privilege: AppPrivilege): {
6952
7141
  reason?: string;
6953
7142
  };
6954
7143
  //#endregion
7144
+ //#region src/layer-selectors.d.ts
7145
+ /**
7146
+ * The fields a layer list needs: enough to draw a row, a `<select>` option or
7147
+ * a visibility checkbox. It deliberately leaves out opacity, style, source,
7148
+ * metadata and feature data, which change far more often.
7149
+ */
7150
+ interface LayerSummary {
7151
+ /** The layer id. */
7152
+ readonly id: string;
7153
+ /** The display name. */
7154
+ readonly name: string;
7155
+ /** The layer kind. */
7156
+ readonly type: LayerType;
7157
+ /** Whether the layer is shown on the primary map. */
7158
+ readonly visible: boolean;
7159
+ /** The layer panel group the layer belongs to, if any. */
7160
+ readonly groupId: string | undefined;
7161
+ }
7162
+ /**
7163
+ * The array {@link useLayersWhen} returns while inactive. Frozen, and shared so
7164
+ * the inactive selection never changes identity.
7165
+ */
7166
+ export declare const NO_LAYERS: GeoLibreLayer[];
7167
+ /**
7168
+ * Select one layer record by id.
7169
+ *
7170
+ * @param state - The app state.
7171
+ * @param id - The layer id; `null`/`undefined` selects nothing.
7172
+ * @returns The layer record, or `undefined` when there is no such layer.
7173
+ */
7174
+ export declare function selectLayerById(state: Pick<AppState, "layers">, id: string | null | undefined): GeoLibreLayer | undefined;
7175
+ /**
7176
+ * Select the layer ids in store order (bottom to top).
7177
+ *
7178
+ * Returns a new array on every call; pair it with a shallow comparison (as
7179
+ * {@link useLayerIds} does) so an unchanged id list keeps its identity.
7180
+ *
7181
+ * @param state - The app state.
7182
+ * @returns The layer ids.
7183
+ */
7184
+ export declare function selectLayerIds(state: Pick<AppState, "layers">): string[];
7185
+ /**
7186
+ * Select a {@link LayerSummary} per layer, in store order (bottom to top).
7187
+ *
7188
+ * Each summary keeps its identity while its own fields are unchanged, so the
7189
+ * returned array is shallow-equal to the previous one after an edit that
7190
+ * touches none of those fields (opacity, style, data, metadata).
7191
+ *
7192
+ * @param state - The app state.
7193
+ * @returns One summary per layer.
7194
+ */
7195
+ export declare function selectLayerSummaries(state: Pick<AppState, "layers">): LayerSummary[];
7196
+ /**
7197
+ * Build a selector for the full `layers` array that is live only while
7198
+ * `active`.
7199
+ *
7200
+ * @param active - Whether the caller currently needs the layers.
7201
+ * @returns A selector returning `state.layers` while active, and the constant
7202
+ * {@link NO_LAYERS} otherwise.
7203
+ */
7204
+ export declare function selectLayersWhen(active: boolean): (state: Pick<AppState, "layers">) => GeoLibreLayer[];
7205
+ /**
7206
+ * Subscribe to one layer record.
7207
+ *
7208
+ * Re-renders only when that layer changes (or appears/disappears), not when
7209
+ * another layer is edited.
7210
+ *
7211
+ * @param id - The layer id; `null`/`undefined` subscribes to nothing.
7212
+ * @returns The layer record, or `undefined` when there is no such layer.
7213
+ */
7214
+ export declare function useLayer(id: string | null | undefined): GeoLibreLayer | undefined;
7215
+ /**
7216
+ * Subscribe to the ordered list of layer ids.
7217
+ *
7218
+ * Re-renders only when a layer is added, removed or reordered.
7219
+ *
7220
+ * @returns The layer ids in store order (bottom to top).
7221
+ */
7222
+ export declare function useLayerIds(): string[];
7223
+ /**
7224
+ * Subscribe to a {@link LayerSummary} per layer.
7225
+ *
7226
+ * Re-renders only when a layer is added, removed, reordered, renamed, shown or
7227
+ * hidden, retyped or regrouped; opacity, style, data and metadata edits do not
7228
+ * re-render the caller.
7229
+ *
7230
+ * @returns One summary per layer, in store order (bottom to top).
7231
+ */
7232
+ export declare function useLayerSummaries(): LayerSummary[];
7233
+ /**
7234
+ * Subscribe to the full `layers` array only while `active`.
7235
+ *
7236
+ * For always-mounted surfaces (dialogs, floating panels) that need every layer
7237
+ * record while open but keep local state across closes and so cannot simply be
7238
+ * unmounted. While inactive the caller gets the constant {@link NO_LAYERS} and
7239
+ * layer edits do not re-render it.
7240
+ *
7241
+ * @param active - Whether the caller currently needs the layers (for example,
7242
+ * whether its dialog is open).
7243
+ * @returns `layers` while active, otherwise an empty, frozen array.
7244
+ */
7245
+ export declare function useLayersWhen(active: boolean): GeoLibreLayer[];
7246
+ //#endregion
6955
7247
  //#region src/history.d.ts
6956
7248
  export declare function setHistoryCoalesceMs(ms: number): void;
6957
7249
  export declare function getHistoryCoalesceMs(): number;
@@ -7420,6 +7712,23 @@ export declare function getGoogleMapsApiKey(env?: Record<string, string | undefi
7420
7712
  * @returns The trimmed token, or undefined when unset.
7421
7713
  */
7422
7714
  export declare function getMapboxAccessToken(env?: Record<string, string | undefined>): string | undefined;
7715
+ /**
7716
+ * Resolves the ArcGIS API key from the runtime environment.
7717
+ *
7718
+ * The ArcGIS renderer draws the translated project basemap and non-Esri layers
7719
+ * without a key; Esri's basemap styles and location services require one
7720
+ * (an ArcGIS Location Platform or ArcGIS Online API key credential). It is
7721
+ * supplied via `VITE_ARCGIS_API_KEY` (baked in at build time from the bare
7722
+ * `ARCGIS_API_KEY` env var, which `vite.config.ts` copies into the prefixed
7723
+ * name) or set at runtime through Settings → Environment variables
7724
+ * (`window.__GEOLIBRE_RUNTIME_ENV__`, so a bare `ARCGIS_API_KEY` entry works
7725
+ * there too). Same precedence as {@link getMapboxAccessToken}.
7726
+ *
7727
+ * @param env - Environment record (defaults to the runtime environment);
7728
+ * injectable for testing.
7729
+ * @returns The trimmed key, or undefined when unset.
7730
+ */
7731
+ export declare function getArcgisApiKey(env?: Record<string, string | undefined>): string | undefined;
7423
7732
  /**
7424
7733
  * Resolves the Cesium Ion access token from the runtime environment.
7425
7734
  *
@@ -7486,12 +7795,31 @@ type CesiumIonAssetKind = "3d-tiles" | "imagery";
7486
7795
  export declare const CESIUM_OSM_BUILDINGS_ASSET_ID = 96188;
7487
7796
  /** Bing Maps Aerial through Ion, the imagery asset every Ion account can use. */
7488
7797
  export declare const CESIUM_BING_AERIAL_ASSET_ID = 2;
7489
- /** Ion assets offered as one-click picks in the Add Data dialog. */
7490
- export declare const CESIUM_ION_QUICK_PICKS: ReadonlyArray<{
7798
+ /**
7799
+ * Google Photorealistic 3D Tiles served through Ion. Unlike the two above it
7800
+ * is not free on every plan: Ion accounts without it get a 403 the globe
7801
+ * surfaces as a layer error.
7802
+ */
7803
+ export declare const CESIUM_GOOGLE_PHOTOREALISTIC_ASSET_ID = 2275207;
7804
+ /**
7805
+ * Which tier of the Ion catalog a quick pick comes from. `global` assets ship
7806
+ * with every Ion account; `depot` assets are Asset Depot samples the account
7807
+ * has to add once at ion.cesium.com before they stream (until then the
7808
+ * endpoint 404s and the globe reports a layer error).
7809
+ */
7810
+ type CesiumIonQuickPickGroup = "global" | "depot";
7811
+ interface CesiumIonQuickPick {
7491
7812
  assetId: number;
7492
7813
  kind: CesiumIonAssetKind;
7493
7814
  name: string;
7494
- }>;
7815
+ group: CesiumIonQuickPickGroup;
7816
+ }
7817
+ /**
7818
+ * Ion assets offered as one-click picks in the Add Data dialog. Asset ids are
7819
+ * the dropdown's option values, so they have to stay unique; the ids below are
7820
+ * the ones Cesium's own samples use.
7821
+ */
7822
+ export declare const CESIUM_ION_QUICK_PICKS: ReadonlyArray<CesiumIonQuickPick>;
7495
7823
  /** Parse an Ion asset id the way the Add Data form and the project file carry it. */
7496
7824
  export declare function parseCesiumIonAssetId(value: unknown): number | null;
7497
7825
  /**
@@ -7577,6 +7905,8 @@ interface CzmlLayerOptions {
7577
7905
  url?: string;
7578
7906
  /** Local path when loaded from disk. */
7579
7907
  sourcePath?: string;
7908
+ /** Credit shown in the globe's attribution control while the layer is present. */
7909
+ attribution?: string;
7580
7910
  }
7581
7911
  /**
7582
7912
  * Build a typed GeoLibreLayer representing a CZML dynamic scene on the Cesium globe.
@@ -7859,5 +8189,5 @@ export declare function localFileName(path: string): string;
7859
8189
  /** Keep imported layers distinguishable, including within a multi-file import. */
7860
8190
  export declare function uniqueImportedLayerName(name: string, names: Iterable<string>): string;
7861
8191
  //#endregion
7862
- export type { AppState, CesiumIonAssetKind, CesiumIonLayerOptions, CesiumKmlLayerOptions, ConversionToolKind, CredentialRedactionResult, CzmlDocument, CzmlLayerOptions, CzmlPacket, CzmlSource, GeocodeMatch, GeocodeRequest, GeocodeStatus, GeocoderConfig, GeocodingPreferenceInput, GeocodingProvider, GeocodingProviderId, GpsStatusFix, NetworkToolKind, NominatimForwardResult, NominatimReverseResult, RasterToolKind, ReverseGeocodeDisplay, StatisticsToolKind, VectorToolKind };
8192
+ export type { AppState, CesiumIonAssetKind, CesiumIonLayerOptions, CesiumIonQuickPick, CesiumIonQuickPickGroup, CesiumKmlLayerOptions, ConversionToolKind, CredentialRedactionResult, CzmlDocument, CzmlLayerOptions, CzmlPacket, CzmlSource, GeocodeMatch, GeocodeRequest, GeocodeStatus, GeocoderConfig, GeocodingPreferenceInput, GeocodingProvider, GeocodingProviderId, GpsStatusFix, LayerSummary, NetworkToolKind, NominatimForwardResult, NominatimReverseResult, RasterToolKind, ReverseGeocodeDisplay, StatisticsToolKind, VectorToolKind };
7863
8193
  //# sourceMappingURL=index.d.mts.map