@geolibre/core 2.8.0 → 2.9.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.mjs CHANGED
@@ -331,6 +331,7 @@ const DEFAULT_PROJECT_PREFERENCES = {
331
331
  ellipsoidId: "earth",
332
332
  scaleUnit: "metric",
333
333
  showPointerElevation: false,
334
+ terrainEnabled: false,
334
335
  coordinateFormat: "dd"
335
336
  },
336
337
  environmentVariables: [],
@@ -1400,6 +1401,175 @@ function isRegionalBasemapSentinel(styleUrl) {
1400
1401
  return Boolean(styleUrl?.startsWith(REGIONAL_BASEMAP_SENTINEL_PREFIX));
1401
1402
  }
1402
1403
  //#endregion
1404
+ //#region src/cesium-imagery.ts
1405
+ /**
1406
+ * Maps the project's basemap onto imagery the Cesium globe can render.
1407
+ *
1408
+ * The 2D panes render `basemapStyleUrl` through MapLibre, which understands
1409
+ * vector GL styles and GeoLibre's `geolibre://` sentinels. Cesium understands
1410
+ * neither: it draws imagery from tile providers only. So a globe pane that
1411
+ * simply mounted the store basemap would show nothing, which is why the pane
1412
+ * used to hardcode Ion World Imagery (with a token) or OpenStreetMap (without)
1413
+ * and ignore the user's choice entirely — leaving a bright globe beside dark 2D
1414
+ * panes and breaking the "same map, different projection" promise the multi-map
1415
+ * grid makes.
1416
+ *
1417
+ * This module is the translation. It is deliberately **engine-free** — it
1418
+ * returns a plain descriptor and never imports Cesium — so it lives in
1419
+ * `@geolibre/core` beside the basemap catalogs it reads, the 2D and 3D
1420
+ * renderers share one source of truth, and the Cesium chunk boundary in
1421
+ * `vite.config.ts` stays intact.
1422
+ *
1423
+ * Three outcomes are possible, and the caller has to handle all three (see
1424
+ * {@link CesiumBasemapImagery}): tiles to draw, nothing to draw, or "no raster
1425
+ * equivalent exists — pick your own default".
1426
+ */
1427
+ const OSM_CREDIT = "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors";
1428
+ /** EOX Maps serves these layers keyless under CC BY-SA 4.0. */
1429
+ const EOX_CREDIT = "<a href=\"https://maps.eox.at\">EOX Maps</a> (CC BY-SA 4.0)";
1430
+ const eoxLayer = (layer, extension) => `https://tiles.maps.eox.at/wmts/1.0.0/${layer}/default/g/{z}/{y}/{x}.${extension}`;
1431
+ /** Colourful streets — the tone of Liberty and Bright. */
1432
+ const STREETS = {
1433
+ template: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
1434
+ attribution: OSM_CREDIT,
1435
+ maximumLevel: 19
1436
+ };
1437
+ /** Light and muted — the tone of Positron and the pale Protomaps flavors. */
1438
+ const LIGHT = {
1439
+ template: eoxLayer("terrain-light_3857", "jpg"),
1440
+ attribution: `Terrain Light · ${OSM_CREDIT} · ${EOX_CREDIT}`,
1441
+ maximumLevel: 16
1442
+ };
1443
+ /**
1444
+ * Dark — the tone of Dark, Fiord, and the dark Protomaps flavors. NASA's Black
1445
+ * Marble night lights is the one keyless dark raster basemap left, and it suits
1446
+ * a globe: the point of matching here is that a dark project does not end up
1447
+ * with a glaring bright globe in the corner.
1448
+ */
1449
+ const DARK = {
1450
+ template: eoxLayer("blackmarble_3857", "jpg"),
1451
+ attribution: `Black Marble © NASA Earth Observatory · ${EOX_CREDIT}`,
1452
+ maximumLevel: 8
1453
+ };
1454
+ /** Raster analogue per OpenFreeMap style name (the last path segment). */
1455
+ const OPENFREEMAP_ANALOGUES = {
1456
+ liberty: STREETS,
1457
+ bright: STREETS,
1458
+ positron: LIGHT,
1459
+ dark: DARK,
1460
+ fiord: DARK
1461
+ };
1462
+ /** Raster analogue per Protomaps v5 flavor. */
1463
+ const PROTOMAPS_ANALOGUES = {
1464
+ light: LIGHT,
1465
+ white: LIGHT,
1466
+ grayscale: LIGHT,
1467
+ dark: DARK,
1468
+ black: DARK
1469
+ };
1470
+ function toImagery(analogue) {
1471
+ return {
1472
+ kind: "xyz",
1473
+ template: analogue.template,
1474
+ attribution: analogue.attribution,
1475
+ maximumLevel: analogue.maximumLevel
1476
+ };
1477
+ }
1478
+ /**
1479
+ * Whether two descriptors would draw the same thing.
1480
+ *
1481
+ * Descriptors are built fresh on every call, so two basemaps resolving to the
1482
+ * same analogue — OpenFreeMap `liberty` and `bright` are both the streets
1483
+ * tone — yield equal but distinct objects. A renderer that remembers the
1484
+ * descriptor it drew (to skip redundant work) must compare by value: a
1485
+ * reference check would miss that case and tear down and re-add an identical
1486
+ * tile provider, costing a flash and a round of re-requested tiles for no
1487
+ * visible change.
1488
+ */
1489
+ function sameCesiumImagery(a, b) {
1490
+ if (a.kind !== b.kind) return false;
1491
+ if (a.kind !== "xyz" || b.kind !== "xyz") return true;
1492
+ return a.template === b.template && a.attribution === b.attribution && a.maximumLevel === b.maximumLevel && a.scheme === b.scheme && a.overlayTemplate === b.overlayTemplate;
1493
+ }
1494
+ /**
1495
+ * `decodeURIComponent` that reports failure instead of throwing. A URL keeps a
1496
+ * malformed escape (`%E0%A4`) in its pathname quite happily, but decoding one
1497
+ * throws `URIError` — and this runs inside a React render, so an unhandled throw
1498
+ * would take the globe pane down instead of falling through to the default.
1499
+ */
1500
+ function safeDecode(value) {
1501
+ try {
1502
+ return decodeURIComponent(value);
1503
+ } catch {
1504
+ return;
1505
+ }
1506
+ }
1507
+ /**
1508
+ * The raster analogue for a vector GL style URL, or undefined when the style is
1509
+ * not one GeoLibre ships (a provider style, a user's own URL, a Mapbox style).
1510
+ * Matching on host + path rather than searching the URL for "dark"/"light"
1511
+ * keeps an unrelated style whose *key* happens to contain one of those words
1512
+ * from being mapped to the wrong tone.
1513
+ */
1514
+ function vectorStyleAnalogue(styleUrl) {
1515
+ let parsed;
1516
+ try {
1517
+ parsed = new URL(styleUrl);
1518
+ } catch {
1519
+ return;
1520
+ }
1521
+ if (parsed.hostname === "tiles.openfreemap.org") {
1522
+ const name = parsed.pathname.split("/").filter(Boolean).at(-1);
1523
+ return name ? OPENFREEMAP_ANALOGUES[name] : void 0;
1524
+ }
1525
+ if (parsed.hostname === "api.protomaps.com") {
1526
+ const segments = parsed.pathname.split("/").filter(Boolean);
1527
+ const flavor = segments[0] === "styles" ? segments[2] : void 0;
1528
+ const decoded = flavor ? safeDecode(flavor) : void 0;
1529
+ return decoded ? PROTOMAPS_ANALOGUES[decoded] : void 0;
1530
+ }
1531
+ }
1532
+ /**
1533
+ * Translate a basemap style URL into imagery for the Cesium globe.
1534
+ *
1535
+ * Planetary and regional basemaps are already raster tile sets, so they carry
1536
+ * straight over — the globe shows the same Mars/Moon/Amap tiles the 2D panes
1537
+ * do. GeoLibre's own vector styles map to a keyless raster basemap of matching
1538
+ * tone, so switching the project to a dark basemap darkens the globe too.
1539
+ * Everything else reports `default`, leaving the choice of fallback imagery to
1540
+ * the renderer (which knows whether an Ion token is configured).
1541
+ *
1542
+ * A `geolibre://` sentinel that no longer resolves is treated as the default
1543
+ * basemap, mirroring what `resolveMapStyle` does for the 2D map rather than
1544
+ * handing the sentinel onward as if it were fetchable.
1545
+ *
1546
+ * @param styleUrl - The project's `basemapStyleUrl`.
1547
+ * @returns What the globe should draw beneath the data layers.
1548
+ */
1549
+ function basemapToCesiumImagery(styleUrl) {
1550
+ if (styleUrl === "") return { kind: "none" };
1551
+ const url = styleUrl ?? "https://tiles.openfreemap.org/styles/liberty";
1552
+ const planetary = getPlanetaryBasemapByStyleUrl(url);
1553
+ if (planetary) return {
1554
+ kind: "xyz",
1555
+ template: planetary.tileUrl,
1556
+ attribution: planetary.attribution,
1557
+ maximumLevel: planetary.maxZoom,
1558
+ ...planetary.scheme ? { scheme: planetary.scheme } : {}
1559
+ };
1560
+ const regional = getRegionalBasemapByStyleUrl(url);
1561
+ if (regional) return {
1562
+ kind: "xyz",
1563
+ template: regional.tileUrl,
1564
+ attribution: regional.attribution,
1565
+ maximumLevel: regional.maxZoom,
1566
+ ...regional.scheme ? { scheme: regional.scheme } : {},
1567
+ ...regional.overlayTileUrl ? { overlayTemplate: regional.overlayTileUrl } : {}
1568
+ };
1569
+ const analogue = vectorStyleAnalogue(url.startsWith("geolibre://") ? DEFAULT_BASEMAP : url);
1570
+ return analogue ? toImagery(analogue) : { kind: "default" };
1571
+ }
1572
+ //#endregion
1403
1573
  //#region src/geojson-z.ts
1404
1574
  /**
1405
1575
  * Helpers for vector data whose coordinates carry a Z value (elevation), e.g.
@@ -2383,13 +2553,18 @@ function getMapboxAccessToken(env) {
2383
2553
  /**
2384
2554
  * Resolves the Cesium Ion access token from the runtime environment.
2385
2555
  *
2386
- * The 3D-globe view's world imagery and terrain need a Cesium Ion token. It is
2556
+ * Cesium World Terrain and Ion World Imagery need a Cesium Ion token. It is
2387
2557
  * supplied via `VITE_CESIUM_TOKEN` (baked in at build time from the bare
2388
2558
  * `CESIUM_TOKEN` env var, which `vite.config.ts` copies into the prefixed name)
2389
2559
  * or set at runtime through Settings → Environment variables
2390
2560
  * (`window.__GEOLIBRE_RUNTIME_ENV__`, which bypasses Vite's envPrefix allowlist,
2391
- * so a bare `CESIUM_TOKEN` entry works there too). When unset, the globe cannot
2392
- * render and the 3D view is not offered.
2561
+ * so a bare `CESIUM_TOKEN` entry works there too).
2562
+ *
2563
+ * The 3D-globe view itself does **not** need one: it draws the project basemap
2564
+ * as its base imagery whenever that basemap has a raster form (see
2565
+ * {@link basemapToCesiumImagery}), and falls back to Ion World Imagery — or, with
2566
+ * no token, to OpenStreetMap — for the ones that do not. So an absent token
2567
+ * costs terrain and the quality of that fallback, not the view.
2393
2568
  *
2394
2569
  * @param env - Environment record (defaults to the runtime environment);
2395
2570
  * injectable for testing.
@@ -5228,6 +5403,171 @@ function normalizeLayerCapabilities(raw) {
5228
5403
  }
5229
5404
  return hasAny ? caps : void 0;
5230
5405
  }
5406
+ /**
5407
+ * All supported application privilege identifiers in GeoLibre.
5408
+ */
5409
+ const ALL_APP_PRIVILEGES = [
5410
+ "layers:edit",
5411
+ "layers:add-remote",
5412
+ "layers:add-local",
5413
+ "processing:run",
5414
+ "processing:sidecar",
5415
+ "project:save",
5416
+ "project:share",
5417
+ "project:share-public",
5418
+ "plugins:install",
5419
+ "assistant:use",
5420
+ "connections:manage",
5421
+ "export:data",
5422
+ "export:image",
5423
+ "settings:manage"
5424
+ ];
5425
+ /**
5426
+ * Standard privilege bundles for named application roles.
5427
+ */
5428
+ const ROLE_PRIVILEGES = {
5429
+ viewer: ["export:image", "export:data"],
5430
+ editor: [
5431
+ "export:image",
5432
+ "export:data",
5433
+ "layers:edit",
5434
+ "layers:add-local",
5435
+ "layers:add-remote",
5436
+ "processing:run",
5437
+ "project:save"
5438
+ ],
5439
+ publisher: [
5440
+ "export:image",
5441
+ "export:data",
5442
+ "layers:edit",
5443
+ "layers:add-local",
5444
+ "layers:add-remote",
5445
+ "processing:run",
5446
+ "project:save",
5447
+ "project:share",
5448
+ "project:share-public",
5449
+ "processing:sidecar",
5450
+ "assistant:use"
5451
+ ],
5452
+ administrator: ALL_APP_PRIVILEGES
5453
+ };
5454
+ /**
5455
+ * Resolves the effective privilege list for a given role, applying custom overrides if specified.
5456
+ */
5457
+ function resolveRolePrivileges(role, customPrivileges) {
5458
+ if (role === "custom") {
5459
+ if (!customPrivileges || customPrivileges.length === 0) return [];
5460
+ const validSet = new Set(ALL_APP_PRIVILEGES);
5461
+ return [...new Set(customPrivileges.filter((p) => validSet.has(p)))];
5462
+ }
5463
+ return [...ROLE_PRIVILEGES[role]];
5464
+ }
5465
+ /**
5466
+ * Intersects multiple sets of privileges to derive the effective permissions when multiple
5467
+ * policies (e.g. deployment, organization, and share link) apply simultaneously.
5468
+ */
5469
+ function intersectPrivileges(...privilegeSets) {
5470
+ if (privilegeSets.length === 0) return [];
5471
+ if (privilegeSets.length === 1) return [...new Set(privilegeSets[0])];
5472
+ let current = new Set(privilegeSets[0]);
5473
+ for (let i = 1; i < privilegeSets.length; i++) {
5474
+ const nextSet = new Set(privilegeSets[i]);
5475
+ current = new Set([...current].filter((p) => nextSet.has(p)));
5476
+ }
5477
+ return [...current];
5478
+ }
5479
+ /**
5480
+ * Evaluates whether an application capability set grants a specific privilege.
5481
+ */
5482
+ function hasAppPrivilege(capabilities, privilege) {
5483
+ if (!capabilities) return true;
5484
+ return capabilities.privileges.includes(privilege);
5485
+ }
5486
+ /**
5487
+ * Resolves why a privilege is withheld: its own reason if it has one, otherwise
5488
+ * the reason recorded for the capability set as a whole.
5489
+ *
5490
+ * @param capabilities - The active capability set, if any.
5491
+ * @param privilege - The privilege being explained.
5492
+ * @returns The reason, or undefined when none was recorded.
5493
+ */
5494
+ function appPrivilegeReason(capabilities, privilege) {
5495
+ if (!capabilities) return void 0;
5496
+ return capabilities.privilegeReasons?.[privilege] ?? capabilities.reason;
5497
+ }
5498
+ /**
5499
+ * Creates the default unconstrained application capabilities (Administrator role).
5500
+ */
5501
+ function createDefaultAppCapabilities() {
5502
+ return {
5503
+ role: "administrator",
5504
+ privileges: [...ALL_APP_PRIVILEGES]
5505
+ };
5506
+ }
5507
+ /**
5508
+ * Normalizes an untrusted array of privilege strings.
5509
+ */
5510
+ function normalizeAppPrivileges(raw) {
5511
+ if (!Array.isArray(raw)) return void 0;
5512
+ const validSet = new Set(ALL_APP_PRIVILEGES);
5513
+ const result = [];
5514
+ for (const item of raw) if (typeof item === "string" && validSet.has(item)) result.push(item);
5515
+ return result.length > 0 ? [...new Set(result)] : [];
5516
+ }
5517
+ //#endregion
5518
+ //#region src/deployment-capabilities.ts
5519
+ /** Every capability, in a stable order for docs and tests. */
5520
+ const DEPLOYMENT_CAPABILITIES = [
5521
+ "project:edit",
5522
+ "data:add",
5523
+ "processing:run",
5524
+ "export:data",
5525
+ "plugins:install",
5526
+ "settings:manage"
5527
+ ];
5528
+ /**
5529
+ * The default grant: everything. `full` must stay the default so an existing
5530
+ * deployment that configures nothing behaves exactly as it did before.
5531
+ */
5532
+ const ALL_DEPLOYMENT_CAPABILITIES = new Set(DEPLOYMENT_CAPABILITIES);
5533
+ /** Whether an arbitrary string names a capability we know how to enforce. */
5534
+ function isDeploymentCapability(value) {
5535
+ return DEPLOYMENT_CAPABILITIES.includes(value);
5536
+ }
5537
+ /**
5538
+ * The reserved token that grants nothing, for a deployment that wants the map
5539
+ * and nothing else.
5540
+ *
5541
+ * Needed because a blank value cannot mean it: the deployment env reader treats
5542
+ * an empty string as unset (a `-e VAR=` produces one), and unset has to keep
5543
+ * meaning "full" so existing deployments are unchanged. Without a spelling for
5544
+ * "none", the most locked-down configuration would be the one you cannot write.
5545
+ */
5546
+ const NO_DEPLOYMENT_CAPABILITIES = "none";
5547
+ /**
5548
+ * Parse a comma-separated capability list from deployment configuration.
5549
+ *
5550
+ * Unknown tokens are dropped rather than throwing: a newer container image may
5551
+ * be configured with a capability this build does not know about, and the safe
5552
+ * reading of an unrecognized grant is "not granted".
5553
+ *
5554
+ * Fails closed on purpose. An operator who set the variable at all meant to
5555
+ * restrict something, so a list that parses to nothing grants nothing — only an
5556
+ * absent (or blank) value falls back to the full set, which is the caller's job
5557
+ * to detect.
5558
+ *
5559
+ * @param raw - The configured value, e.g. `"data:add, export:data"`.
5560
+ * @returns The granted capabilities, with duplicates and unknown names removed.
5561
+ */
5562
+ function parseDeploymentCapabilities(raw) {
5563
+ const granted = /* @__PURE__ */ new Set();
5564
+ if (raw.trim().toLowerCase() === "none") return granted;
5565
+ for (const token of raw.split(",")) {
5566
+ const name = token.trim();
5567
+ if (isDeploymentCapability(name)) granted.add(name);
5568
+ }
5569
+ return granted;
5570
+ }
5231
5571
  //#endregion
5232
5572
  //#region src/history.ts
5233
5573
  /**
@@ -6833,6 +7173,9 @@ function scrubPrintLayoutForRemovedLayers(config, layerIds) {
6833
7173
  //#region src/project.ts
6834
7174
  /** Placeholder name a project carries before the user names it. */
6835
7175
  const DEFAULT_PROJECT_NAME = "Untitled Project";
7176
+ function normalizeBlankBackgroundColor(value) {
7177
+ return typeof value === "string" && /^#[0-9a-f]{6}$/i.test(value) ? value : null;
7178
+ }
6836
7179
  function createDefaultMapView() {
6837
7180
  return {
6838
7181
  center: [-100, 40],
@@ -6849,6 +7192,7 @@ function createEmptyProject(name = DEFAULT_PROJECT_NAME, options = {}) {
6849
7192
  basemapStyleUrl: options.basemapStyleUrl ?? "https://tiles.openfreemap.org/styles/liberty",
6850
7193
  basemapVisible: true,
6851
7194
  basemapOpacity: 1,
7195
+ blankBackgroundColor: null,
6852
7196
  layers: [],
6853
7197
  layerGroups: [],
6854
7198
  styles: {},
@@ -6970,6 +7314,7 @@ function parseProject(json) {
6970
7314
  const basemapStyleUrl = data.basemapStyleUrl ?? "https://tiles.openfreemap.org/styles/liberty";
6971
7315
  const basemapVisible = data.basemapVisible ?? true;
6972
7316
  const basemapOpacity = data.basemapOpacity ?? 1;
7317
+ const blankBackgroundColor = normalizeBlankBackgroundColor(data.blankBackgroundColor);
6973
7318
  const mapView = normalizeMapViewState(data.mapView);
6974
7319
  const { mapLayout, secondaryMapViews } = resolveMapGrid(normalizeMapLayout(data.mapLayout), normalizeSecondaryMapViews(data.secondaryMapViews), { mapView });
6975
7320
  const styleLibrary = normalizeStyleLibraryEntries(data.styleLibrary);
@@ -6981,6 +7326,7 @@ function parseProject(json) {
6981
7326
  basemapStyleUrl,
6982
7327
  basemapVisible,
6983
7328
  basemapOpacity,
7329
+ blankBackgroundColor,
6984
7330
  layers,
6985
7331
  ...selectedLayerId !== void 0 ? { selectedLayerId } : {},
6986
7332
  ...layerGroups.length > 0 ? { layerGroups } : {},
@@ -7665,6 +8011,7 @@ function normalizeProjectPreferences(preferences) {
7665
8011
  ellipsoidId: getEllipsoid(map.ellipsoidId).id,
7666
8012
  scaleUnit: normalizeScaleUnit(map.scaleUnit),
7667
8013
  showPointerElevation: normalizeBoolean(map.showPointerElevation, DEFAULT_PROJECT_PREFERENCES.map.showPointerElevation),
8014
+ terrainEnabled: normalizeBoolean(map.terrainEnabled, DEFAULT_PROJECT_PREFERENCES.map.terrainEnabled),
7668
8015
  coordinateFormat: typeof map.coordinateFormat === "string" ? map.coordinateFormat : DEFAULT_PROJECT_PREFERENCES.map.coordinateFormat
7669
8016
  },
7670
8017
  environmentVariables: Array.isArray(candidate.environmentVariables) ? candidate.environmentVariables.map(normalizeEnvironmentVariable).filter((variable) => Boolean(variable)) : [],
@@ -7897,6 +8244,7 @@ function projectFromStore(state) {
7897
8244
  basemapStyleUrl: state.basemapStyleUrl,
7898
8245
  basemapVisible: state.basemapVisible,
7899
8246
  basemapOpacity: state.basemapOpacity,
8247
+ ...state.blankBackgroundColor ? { blankBackgroundColor: state.blankBackgroundColor } : {},
7900
8248
  layers: state.layers.map(prepareLayerForSave),
7901
8249
  ...selectedLayerId !== void 0 ? { selectedLayerId } : {},
7902
8250
  ...layerGroups.length > 0 ? { layerGroups } : {},
@@ -7943,6 +8291,18 @@ function prepareLayerForSave(layer) {
7943
8291
  const { geojson: _geojson, ...rest } = layer;
7944
8292
  layer = rest;
7945
8293
  }
8294
+ if (layer.type === "wms") {
8295
+ const tiles = layer.source.tiles;
8296
+ if (!Array.isArray(tiles)) return layer;
8297
+ const portableTiles = tiles.map((tile) => portableWmsTileUrl(tile));
8298
+ return portableTiles.some((tile, index) => tile !== tiles[index]) ? {
8299
+ ...layer,
8300
+ source: {
8301
+ ...layer.source,
8302
+ tiles: portableTiles
8303
+ }
8304
+ } : layer;
8305
+ }
7946
8306
  if (layer.type !== "xyz") return layer;
7947
8307
  const originalUrl = typeof layer.metadata.originalUrl === "string" && layer.metadata.originalUrl.trim() ? layer.metadata.originalUrl : typeof layer.source.url === "string" && layer.source.url.trim() ? layer.source.url : null;
7948
8308
  if (!originalUrl) return layer;
@@ -7958,11 +8318,23 @@ function prepareLayerForSave(layer) {
7958
8318
  metadata
7959
8319
  };
7960
8320
  }
8321
+ function portableWmsTileUrl(tile) {
8322
+ if (typeof tile !== "string" || !tile.startsWith("geolibre-wms://")) return tile;
8323
+ try {
8324
+ const url = new URL(tile).searchParams.get("url");
8325
+ if (!url) return tile;
8326
+ const parsed = new URL(url);
8327
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? url : tile;
8328
+ } catch {
8329
+ return tile;
8330
+ }
8331
+ }
7961
8332
  function applyProjectToStore(project) {
7962
8333
  const layers = project.layers.map((layer) => ({
7963
8334
  ...layer,
7964
8335
  style: project.styles[layer.id] ? {
7965
8336
  ...DEFAULT_LAYER_STYLE,
8337
+ ...layer.style,
7966
8338
  ...project.styles[layer.id]
7967
8339
  } : {
7968
8340
  ...DEFAULT_LAYER_STYLE,
@@ -7978,6 +8350,7 @@ function applyProjectToStore(project) {
7978
8350
  const basemapStyleUrl = project.basemapStyleUrl;
7979
8351
  const basemapVisible = project.basemapVisible ?? true;
7980
8352
  const basemapOpacity = project.basemapOpacity ?? 1;
8353
+ const blankBackgroundColor = normalizeBlankBackgroundColor(project.blankBackgroundColor);
7981
8354
  const mapView = normalizeMapViewState(project.mapView);
7982
8355
  const { mapLayout, secondaryMapViews } = resolveMapGrid(normalizeMapLayout(project.mapLayout), normalizeSecondaryMapViews(project.secondaryMapViews), { mapView });
7983
8356
  const existingLayerIds = new Set(normalizedLayers.map((l) => l.id));
@@ -8006,6 +8379,7 @@ function applyProjectToStore(project) {
8006
8379
  basemapStyleUrl,
8007
8380
  basemapVisible,
8008
8381
  basemapOpacity,
8382
+ blankBackgroundColor,
8009
8383
  layers: normalizedLayers,
8010
8384
  layerGroups,
8011
8385
  preferences: normalizeProjectPreferences(project.preferences),
@@ -9333,6 +9707,8 @@ function createLayerLibraryEntryId() {
9333
9707
  }
9334
9708
  //#endregion
9335
9709
  //#region src/store.ts
9710
+ /** Reserved Identify target for querying every visible queryable layer at once. */
9711
+ const IDENTIFY_ALL_LAYERS_ID = "__geolibre_identify_all_layers__";
9336
9712
  const MAX_RECENT_PROJECTS = 10;
9337
9713
  /**
9338
9714
  * A fresh, inactive collaboration slice (no live session). Frozen (like
@@ -9571,6 +9947,7 @@ const useAppStore = create()(temporal((set, get) => ({
9571
9947
  basemapStyleUrl: DEFAULT_BASEMAP,
9572
9948
  basemapVisible: true,
9573
9949
  basemapOpacity: 1,
9950
+ blankBackgroundColor: null,
9574
9951
  layers: [],
9575
9952
  layerGroups: [],
9576
9953
  preferences: DEFAULT_PROJECT_PREFERENCES,
@@ -9602,7 +9979,9 @@ const useAppStore = create()(temporal((set, get) => ({
9602
9979
  metadata: {},
9603
9980
  recentProjects: [],
9604
9981
  attributeFilter: "",
9982
+ deploymentCapabilities: ALL_DEPLOYMENT_CAPABILITIES,
9605
9983
  collaboration: DEFAULT_COLLABORATION_STATE,
9984
+ capabilities: createDefaultAppCapabilities(),
9606
9985
  ui: {
9607
9986
  processingOpen: false,
9608
9987
  processingInitialTool: null,
@@ -9880,6 +10259,10 @@ const useAppStore = create()(temporal((set, get) => ({
9880
10259
  basemapOpacity: opacity,
9881
10260
  isDirty: true
9882
10261
  }),
10262
+ setBlankBackgroundColor: (color) => set({
10263
+ blankBackgroundColor: normalizeBlankBackgroundColor(color),
10264
+ isDirty: true
10265
+ }),
9883
10266
  setPreferences: (preferences) => set({
9884
10267
  preferences,
9885
10268
  isDirty: true
@@ -10229,6 +10612,7 @@ const useAppStore = create()(temporal((set, get) => ({
10229
10612
  projectName: name,
10230
10613
  isDirty: true
10231
10614
  }),
10615
+ setDeploymentCapabilities: (capabilities) => set({ deploymentCapabilities: new Set(capabilities) }),
10232
10616
  setRecentProjects: (projects) => set({ recentProjects: normalizeRecentProjects(projects) }),
10233
10617
  rememberRecentProject: (entry) => set((s) => ({ recentProjects: normalizeRecentProjects([entry, ...s.recentProjects]) })),
10234
10618
  forgetRecentProject: (path) => {
@@ -10693,6 +11077,51 @@ const useAppStore = create()(temporal((set, get) => ({
10693
11077
  name: project.name,
10694
11078
  openedAt: (/* @__PURE__ */ new Date()).toISOString()
10695
11079
  });
11080
+ },
11081
+ setAppRole: (role, options) => {
11082
+ set({ capabilities: {
11083
+ role,
11084
+ privileges: resolveRolePrivileges(role, options?.customPrivileges),
11085
+ reason: options?.reason
11086
+ } });
11087
+ },
11088
+ setAppPrivileges: (privileges, reason) => {
11089
+ set({ capabilities: {
11090
+ role: "custom",
11091
+ privileges: normalizeAppPrivileges(privileges) ?? [],
11092
+ reason
11093
+ } });
11094
+ },
11095
+ grantAppPrivilege: (privilege) => {
11096
+ const current = get().capabilities;
11097
+ if (current.privileges.includes(privilege)) return;
11098
+ const { [privilege]: _granted, ...privilegeReasons } = current.privilegeReasons ?? {};
11099
+ set({ capabilities: {
11100
+ ...current,
11101
+ role: "custom",
11102
+ privileges: [...current.privileges, privilege],
11103
+ privilegeReasons
11104
+ } });
11105
+ },
11106
+ revokeAppPrivilege: (privilege, reason) => {
11107
+ const current = get().capabilities;
11108
+ const held = current.privileges.includes(privilege);
11109
+ if (!held && !reason) return;
11110
+ set({ capabilities: {
11111
+ ...current,
11112
+ role: held ? "custom" : current.role,
11113
+ privileges: held ? current.privileges.filter((p) => p !== privilege) : current.privileges,
11114
+ privilegeReasons: reason ? {
11115
+ ...current.privilegeReasons,
11116
+ [privilege]: reason
11117
+ } : current.privilegeReasons
11118
+ } });
11119
+ },
11120
+ resetAppCapabilities: () => {
11121
+ set({ capabilities: createDefaultAppCapabilities() });
11122
+ },
11123
+ hasAppPrivilege: (privilege) => {
11124
+ return hasAppPrivilege(get().capabilities, privilege);
10696
11125
  }
10697
11126
  }), {
10698
11127
  partialize: (s) => ({
@@ -10701,10 +11130,11 @@ const useAppStore = create()(temporal((set, get) => ({
10701
11130
  basemapStyleUrl: s.basemapStyleUrl,
10702
11131
  basemapVisible: s.basemapVisible,
10703
11132
  basemapOpacity: s.basemapOpacity,
11133
+ blankBackgroundColor: s.blankBackgroundColor,
10704
11134
  storymap: s.storymap,
10705
11135
  comments: s.comments
10706
11136
  }),
10707
- equality: (a, b) => a.basemapStyleUrl === b.basemapStyleUrl && a.basemapVisible === b.basemapVisible && a.basemapOpacity === b.basemapOpacity && a.storymap === b.storymap && shallow(a.layers, b.layers) && shallow(a.comments, b.comments) && layerGroupsEqualForHistory(a.layerGroups, b.layerGroups),
11137
+ equality: (a, b) => a.basemapStyleUrl === b.basemapStyleUrl && a.basemapVisible === b.basemapVisible && a.basemapOpacity === b.basemapOpacity && a.blankBackgroundColor === b.blankBackgroundColor && a.storymap === b.storymap && shallow(a.layers, b.layers) && shallow(a.comments, b.comments) && layerGroupsEqualForHistory(a.layerGroups, b.layerGroups),
10708
11138
  limit: 100,
10709
11139
  handleSet: (baseHandleSet) => {
10710
11140
  const debounced = leadingDebounce(baseHandleSet, getHistoryCoalesceMs);
@@ -10829,6 +11259,19 @@ function clearHistory() {
10829
11259
  notifyProjectRestoreHistory();
10830
11260
  }
10831
11261
  }
11262
+ /**
11263
+ * React hook for consuming application capability state for a specific privilege.
11264
+ *
11265
+ * @param privilege - The privilege to check.
11266
+ * @returns `{ granted: boolean, reason?: string }`
11267
+ */
11268
+ function useAppCapability(privilege) {
11269
+ const capabilities = useAppStore((state) => state.capabilities);
11270
+ return {
11271
+ granted: capabilities.privileges.includes(privilege),
11272
+ reason: appPrivilegeReason(capabilities, privilege)
11273
+ };
11274
+ }
10832
11275
  //#endregion
10833
11276
  //#region src/selection-actions.ts
10834
11277
  /**
@@ -11154,6 +11597,23 @@ function formatCameraAltitude(meters, unit) {
11154
11597
  })} ${label}`;
11155
11598
  }
11156
11599
  //#endregion
11600
+ //#region src/pixel-format.ts
11601
+ /**
11602
+ * Trim a float sample to something readable. A 32-bit raster value decoded to a
11603
+ * JS double prints all 17 digits of its binary representation
11604
+ * (`48.11851119995117`), which is noise past the sensor's precision — six
11605
+ * significant digits is more than any COG carries. Integers are left alone so a
11606
+ * classification code is never shown in exponential form.
11607
+ *
11608
+ * @param value A decoded raster sample.
11609
+ * @returns The sample rendered for display.
11610
+ */
11611
+ function formatPixelValue(value) {
11612
+ if (!Number.isFinite(value)) return String(value);
11613
+ if (Number.isInteger(value)) return String(value);
11614
+ return String(Number(value.toPrecision(6)));
11615
+ }
11616
+ //#endregion
11157
11617
  //#region src/storymap-sample.ts
11158
11618
  const SAMPLE_ASSET_BASE = "https://opengeos.org/maplibre-gl-storymaps/assets";
11159
11619
  /**
@@ -12631,6 +13091,6 @@ function currentEditorIdentity() {
12631
13091
  return pickEditorIdentity(isActive ? selfName : void 0, readStoredAuthorName());
12632
13092
  }
12633
13093
  //#endregion
12634
- export { BLANK_BASEMAP, BLEND_MODES, BUILT_IN_STYLE_PRESETS, CARTOCIUDAD_MIN_INTERVAL_MS, CARTOCIUDAD_PUBLIC_HOST, CHINA_BASEMAPS, DEFAULT_BASEMAP, DEFAULT_BLEND_MODE, DEFAULT_COLLABORATION_STATE, DEFAULT_DASHBOARD_COLUMNS, DEFAULT_EDITOR_IDENTITY, DEFAULT_EDITOR_TRACKING_CONFIG, DEFAULT_ELLIPSOID_ID, DEFAULT_FORWARD_GEOCODE_ENDPOINT, DEFAULT_GEOCODING_PROVIDER_ID, DEFAULT_LAYER_GROUP_OPACITY, DEFAULT_LAYER_STYLE, DEFAULT_LEGEND_CONFIG, DEFAULT_MAP_GRID_LAYOUT, DEFAULT_PRINT_LAYOUT, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_PREFERENCES, DEFAULT_REVERSE_GEOCODE_ENDPOINT, DEFAULT_ROUTING_ENDPOINT, DEFAULT_STORY_MAP, DUCKDB_VECTOR_FEATURE_WARN_COUNT, DUCKDB_VECTOR_ROUTE_BYTES, EARTH_MEAN_RADIUS_METERS, EDITOR_IDENTITY_STORAGE_KEY, ELEVATION_REQUEST_TIMEOUT_MS, ELLIPSOIDS, EXPRESSION_FUNCTION_CATEGORIES, ElevationFetchError, FEET_PER_METER, FEET_PER_MILE, GEOCODE_DISPLAY_NAME_KEY, GEOCODE_LAT_KEY, GEOCODE_LON_KEY, GEOCODE_PROVIDER_KEY, GEOCODE_SCORE_KEY, GEOCODE_STATUS_KEY, GEOCODING_PROVIDERS, GOOGLE_MAPS_API_KEY_HEADER, LARGE_VECTOR_FEATURE_THRESHOLD, LAYER_LIBRARY_BUNDLE_TYPE, LAYER_LIBRARY_BUNDLE_VERSION, LAYER_PALETTE, LAYER_TYPES, MAX_DASHBOARD_COLUMNS, MAX_DIAGRAM_FEATURES, MAX_DIAGRAM_SCAN_FEATURES, MAX_LAYER_LIBRARY_ENTRIES, MAX_LAYER_LIBRARY_ENTRY_BYTES, MAX_MAP_GRID_DIM, MAX_POINTS_PER_REQUEST, MAX_PROCESSING_HISTORY, MAX_REDACT_DEPTH, MERCATOR_METERS_PER_PIXEL_AT_ZOOM_0, METERS_PER_FOOT, METERS_PER_MILE, METERS_PER_NAUTICAL_MILE, MIN_DASHBOARD_COLUMNS, MIN_DIAGRAM_SIZE, NETCDF_IMAGE_SOURCE_KIND, NOMINATIM_MIN_INTERVAL_MS, NOMINATIM_PUBLIC_HOST, OPENFREEMAP_BASEMAPS, PHOTO_FULL_PROPERTY, PHOTO_PROPERTY, PLANETARY_BASEMAPS, PLANETARY_BASEMAP_GROUPS, PLANETARY_BASEMAP_SENTINEL_PREFIX, PLANET_SWITCHER_OPTIONS, POINTER_ELEVATION_CACHE_LIMIT, POINTER_ELEVATION_DEBOUNCE_MS, PROJECT_CREDENTIAL_FIELDS, PROJECT_VERSION, PROTOMAPS_BASEMAPS, PUBLIC_GEOCODE_ROW_CAP, PUBLISHABLE_PLUGIN_SETTINGS, RAMP_STYLE_KEYS, RASTER_APPEARANCE_STATE_KEYS, REGIONAL_BASEMAPS, REGIONAL_BASEMAP_GROUPS, REGIONAL_BASEMAP_SENTINEL_PREFIX, RoutingRequestError, SELECTION_MODES, SQL_QUERY_SOURCE_KIND, STYLE_LIBRARY_BUNDLE_TYPE, STYLE_LIBRARY_BUNDLE_VERSION, SYMBOL_STYLE_KEYS, VECTOR_COLOR_RAMPS, activeQuickFilters, applyCopiedLayerStyle, applyGroupEffects, applyJoinsToLayer, applyLayerJoins, applyLayerVirtualFields, applyMatchedSelection, applyProjectToStore, applySelectionMode, attributeFormFieldLabel, attributeLinkUrl, batchDecodePolylines, bodyLengthToEarth, buildForwardGeocodeUrl, buildIsochroneRequest, buildLayerPanelUnits, buildLayerTree, buildMatrixRequest, buildReverseGeocodeUrl, buildRouteRequest, canRedoProjectRestore, canSaveLayerToLibrary, canUndoProjectRestore, captureLayerLibraryEntry, cascadeLayerJoinRefresh, circleRadiusValue, clearExternalNativePaintBridge, clearHistory, clearQuickFilterValues, coerceAttributeFormValue, collectDiagramData, collectTransitiveJoinSourceIds, compareSequenceValues, compileFeatureExpression, compileQuickFilter, compileQuickFilters, controlRendersLayer, copyableLayerStyleKind, createDefaultMapView, createDefaultPrintLayout, createEmptyProject, createEqualIntervalBreaks, createGraduatedClassBreaks, createLayerLibraryEntryId, createPointerElevationResolver, createProjectTemplate, createQuantileBreaks, createSampleStoryMap, createStyleLibraryEntryId, csvRowsToGeocodeRequests, currentEditorIdentity, darkenHex, decodePolyline, decodePolylineDetailed, detachProjectCopy, detectNonGeographicCoordinates, diagramAnchor, diagramPixelSize, diagramsSuppressedByPointRenderer, dominantGeometry, drawMarkerPath, earthAreaToBody, earthLengthToBody, editorTrackingFieldNames, effectiveLayerRenderState, effectiveVectorRules, encodePolyline, ensureEditorTrackingFields, evaluateMapExpression, excludeHiddenFieldsFromGeojson, excludeHiddenFieldsFromProject, extractCopiedLayerStyle, extractStyleLibraryStyle, extrusionColorValue, extrusionHeightValue, featureSelectionId, fetchElevations, formatCameraAltitude, formatExpressionPreviewValue, formatPopupValue, formatRoundNum, generatorCircleRadiusValue, generatorSizeRange, geoJSONToPolylineStr, geocodeForward, geocodeMatchToFeature, geocodeReverse, geocoderMinIntervalMs, geocoderNeedsApiKey, geojsonHasZCoordinates, getActiveBodyRadiusRatio, getActiveEllipsoid, getActiveMeanRadiusMeters, getActiveSemiMajorAxisMeters, getAttributeFormField, getBuildEnvironment, getCesiumIonToken, getEllipsoid, getExternalNativePaintBridge, getGeocoderConfig, getGeocodingProvider, getGoogleMapsApiKey, getHistoryCoalesceMs, getMapboxAccessToken, getMaxHistoryFeatureCount, getPlanetaryBasemapById, getPlanetaryBasemapByStyleUrl, getProtomapsApiKey, getProtomapsStyleUrl, getRegionalBasemapById, getRegionalBasemapByStyleUrl, getRoundNum, getRoutingConfig, getRuntimeEnvironment, getSpatialExtensionPath, getVectorColorRamp, googleMapsApiKeyHeaderValue, groupMemberIndices, hasActiveQuickFilter, hasPathTraversal, hasRestorableLayerSource, hasSimpleStyleProperties, inferFieldTypes, inferLayerCapabilities, initialLayerStyle, interpolateColors, interpolateHexColor, interpolateRampColors, invertSelection, isAbsoluteFilesystemPath, isAllowedPluginManifestUrl, isAttributeFormFieldVisible, isCredentialFieldName, isDefaultPrintLayout, isDiagramStyleEnabled, isDuckDBQueryLayer, isExternalNativeLayerRecord, isGooglePhotorealisticTilesetUrl, isHexColor, isInitialLayerStyle, isInlineImageValue, isInternalPopupField, isIpadDesktopUserAgent, isMaintainedEditorTrackingField, isPopupClickEnabled, isPopupHoverEnabled, isRegionalBasemapSentinel, isSafePopupUrl, isStyleLibraryTargetLayer, isStyleSpecColor, isVectorColorExpression, isochroneResponseToFeatures, layerGroupDepth, layerGroupMoveability, layerJoinKey, layerLibraryConfigPatch, layerLibraryEntryNeedsLocalFile, layerPanelGroupHeaders, lineWidthValue, mapZoomStepOutputs, matchFeaturesByExpression, matrixResponseToFeatures, meanRadiusMeters, mercatorMetersPerPixelAtZoom0, metersWidthExpression, nextDelayMs, nextLayerPaletteColor, nominatimResultToFeature, nominatimReverseResultToDisplay, nonEmptyRecord, normalizeDashboardColumns, normalizeGeocodingProviderId, normalizeGroupContiguity, normalizeHexColor, normalizeLayerCapabilities, normalizeLayerLibraryEntries, normalizeMapLayout, normalizeMapViewState, normalizeModelGraph, normalizeModels, normalizePrintLayoutConfig, normalizeProcessingHistory, normalizeProjectComments, normalizeSecondaryMapViews, normalizeStoryMap, normalizeStyleLibraryEntries, normalizeWidgets, parseContours, parseHexColor, parseHexColorList, parseJsonExpression, parseLayerLibrary, parseProject, parseStoryMapCsv, parseStoryMapJson, parseStyleLibrary, parseValueMapText, persistedThreeDTilesRequestHeaders, pickEditorIdentity, planLayerLibraryAdd, pluginOwnsPaint, polylineStrToGeoJSON, popupFieldLabel, printLayoutConfigsEqual, projectFromStore, projectPathLabel, proportionalRadiusExpression, proportionalSizeRange, readStoredAuthorName, reapplyLayerJoins, redactCredentials, redactProjectCredentials, redactUrlCredentials, redo, registerProjectRestoreHistory, removeTrailingJsonCommas, reorderLayerGroupInPanel, requestIsochrone, requestMatrix, requestRoute, resolveConfiguredPopupTitle, resolveEditorTrackingConfig, resolveGeocoderConfig, resolveLayerCapabilities, resolveMapGrid, resolvePopupBody, resolvePopupRows, resolvePopupTitle, resolveSvgSource, resolveThreeDTilesRequestHeaders, rgbToHex, routeResponseToFeatures, rowCap, ruleBasedColorExpression, ruleBasedVisibilityFilter, sampleMapTerrain, sampleMapTerrainPoint, sampleRemoteElevations, sanitizeLayerStylePatch, scaleAltitudeToActiveBody, scaleDenomination, scaleSpan, scrubCommentsForRemovedLayers, scrubLegendForRemovedLayers, scrubPrintLayoutForLayers, scrubPrintLayoutForRemovedLayers, scrubWidgetsForRemovedLayers, serializeLayerLibrary, serializeProject, serializeStoryMapCsv, serializeStoryMapJson, serializeStyleLibrary, setActiveEllipsoidId, setExternalNativePaintBridge, setGeocodingFetch, setHistoryCoalesceMs, setMaxHistoryFeatureCount, setStoredAuthorName, shouldThrottle, shouldUseTiledRendering, simpleStyleNumberValue, stampFeatureCollectionEditorTracking, stampFeatureEditorTracking, stampFeaturePropertiesEditorTracking, storyMapHasContent, stringifyPopupValue, stripGoogleMapsApiKeyHeader, stripJoinFields, stripVirtualFieldColumns, styleValue, subscribeProjectRestoreHistory, substituteExpressionVariables, supportsBridgedOpacity, transformGeojsonElevation, trimHistoryBySize, undo, unescapePolyline, unmatchedGeocodeFeature, unresolvedLayerLibraryJoins, useAppStore, validateAttributeFormField, validateAttributeFormValues, validateMapExpression, valueMapLabelFor, valueMapToText, vectorCircleColorValue, vectorColorExpression, vectorFillColorValue, vectorFillOpacityValue, vectorLineColorValue, vectorOutlineColorValue, vectorStrokeWidthValue, visiblePopupFields, visiblePopupProperties };
13094
+ export { ALL_APP_PRIVILEGES, ALL_DEPLOYMENT_CAPABILITIES, BLANK_BASEMAP, BLEND_MODES, BUILT_IN_STYLE_PRESETS, CARTOCIUDAD_MIN_INTERVAL_MS, CARTOCIUDAD_PUBLIC_HOST, CHINA_BASEMAPS, DEFAULT_BASEMAP, DEFAULT_BLEND_MODE, DEFAULT_COLLABORATION_STATE, DEFAULT_DASHBOARD_COLUMNS, DEFAULT_EDITOR_IDENTITY, DEFAULT_EDITOR_TRACKING_CONFIG, DEFAULT_ELLIPSOID_ID, DEFAULT_FORWARD_GEOCODE_ENDPOINT, DEFAULT_GEOCODING_PROVIDER_ID, DEFAULT_LAYER_GROUP_OPACITY, DEFAULT_LAYER_STYLE, DEFAULT_LEGEND_CONFIG, DEFAULT_MAP_GRID_LAYOUT, DEFAULT_PRINT_LAYOUT, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_PREFERENCES, DEFAULT_REVERSE_GEOCODE_ENDPOINT, DEFAULT_ROUTING_ENDPOINT, DEFAULT_STORY_MAP, DEPLOYMENT_CAPABILITIES, DUCKDB_VECTOR_FEATURE_WARN_COUNT, DUCKDB_VECTOR_ROUTE_BYTES, EARTH_MEAN_RADIUS_METERS, EDITOR_IDENTITY_STORAGE_KEY, ELEVATION_REQUEST_TIMEOUT_MS, ELLIPSOIDS, EXPRESSION_FUNCTION_CATEGORIES, ElevationFetchError, FEET_PER_METER, FEET_PER_MILE, GEOCODE_DISPLAY_NAME_KEY, GEOCODE_LAT_KEY, GEOCODE_LON_KEY, GEOCODE_PROVIDER_KEY, GEOCODE_SCORE_KEY, GEOCODE_STATUS_KEY, GEOCODING_PROVIDERS, GOOGLE_MAPS_API_KEY_HEADER, IDENTIFY_ALL_LAYERS_ID, LARGE_VECTOR_FEATURE_THRESHOLD, LAYER_LIBRARY_BUNDLE_TYPE, LAYER_LIBRARY_BUNDLE_VERSION, LAYER_PALETTE, LAYER_TYPES, MAX_DASHBOARD_COLUMNS, MAX_DIAGRAM_FEATURES, MAX_DIAGRAM_SCAN_FEATURES, MAX_LAYER_LIBRARY_ENTRIES, MAX_LAYER_LIBRARY_ENTRY_BYTES, MAX_MAP_GRID_DIM, MAX_POINTS_PER_REQUEST, MAX_PROCESSING_HISTORY, MAX_REDACT_DEPTH, MERCATOR_METERS_PER_PIXEL_AT_ZOOM_0, METERS_PER_FOOT, METERS_PER_MILE, METERS_PER_NAUTICAL_MILE, MIN_DASHBOARD_COLUMNS, MIN_DIAGRAM_SIZE, NETCDF_IMAGE_SOURCE_KIND, NOMINATIM_MIN_INTERVAL_MS, NOMINATIM_PUBLIC_HOST, NO_DEPLOYMENT_CAPABILITIES, OPENFREEMAP_BASEMAPS, PHOTO_FULL_PROPERTY, PHOTO_PROPERTY, PLANETARY_BASEMAPS, PLANETARY_BASEMAP_GROUPS, PLANETARY_BASEMAP_SENTINEL_PREFIX, PLANET_SWITCHER_OPTIONS, POINTER_ELEVATION_CACHE_LIMIT, POINTER_ELEVATION_DEBOUNCE_MS, PROJECT_CREDENTIAL_FIELDS, PROJECT_VERSION, PROTOMAPS_BASEMAPS, PUBLIC_GEOCODE_ROW_CAP, PUBLISHABLE_PLUGIN_SETTINGS, RAMP_STYLE_KEYS, RASTER_APPEARANCE_STATE_KEYS, REGIONAL_BASEMAPS, REGIONAL_BASEMAP_GROUPS, REGIONAL_BASEMAP_SENTINEL_PREFIX, ROLE_PRIVILEGES, RoutingRequestError, SELECTION_MODES, SQL_QUERY_SOURCE_KIND, STYLE_LIBRARY_BUNDLE_TYPE, STYLE_LIBRARY_BUNDLE_VERSION, SYMBOL_STYLE_KEYS, VECTOR_COLOR_RAMPS, activeQuickFilters, appPrivilegeReason, applyCopiedLayerStyle, applyGroupEffects, applyJoinsToLayer, applyLayerJoins, applyLayerVirtualFields, applyMatchedSelection, applyProjectToStore, applySelectionMode, attributeFormFieldLabel, attributeLinkUrl, basemapToCesiumImagery, batchDecodePolylines, bodyLengthToEarth, buildForwardGeocodeUrl, buildIsochroneRequest, buildLayerPanelUnits, buildLayerTree, buildMatrixRequest, buildReverseGeocodeUrl, buildRouteRequest, canRedoProjectRestore, canSaveLayerToLibrary, canUndoProjectRestore, captureLayerLibraryEntry, cascadeLayerJoinRefresh, circleRadiusValue, clearExternalNativePaintBridge, clearHistory, clearQuickFilterValues, coerceAttributeFormValue, collectDiagramData, collectTransitiveJoinSourceIds, compareSequenceValues, compileFeatureExpression, compileQuickFilter, compileQuickFilters, controlRendersLayer, copyableLayerStyleKind, createDefaultAppCapabilities, createDefaultMapView, createDefaultPrintLayout, createEmptyProject, createEqualIntervalBreaks, createGraduatedClassBreaks, createLayerLibraryEntryId, createPointerElevationResolver, createProjectTemplate, createQuantileBreaks, createSampleStoryMap, createStyleLibraryEntryId, csvRowsToGeocodeRequests, currentEditorIdentity, darkenHex, decodePolyline, decodePolylineDetailed, detachProjectCopy, detectNonGeographicCoordinates, diagramAnchor, diagramPixelSize, diagramsSuppressedByPointRenderer, dominantGeometry, drawMarkerPath, earthAreaToBody, earthLengthToBody, editorTrackingFieldNames, effectiveLayerRenderState, effectiveVectorRules, encodePolyline, ensureEditorTrackingFields, evaluateMapExpression, excludeHiddenFieldsFromGeojson, excludeHiddenFieldsFromProject, extractCopiedLayerStyle, extractStyleLibraryStyle, extrusionColorValue, extrusionHeightValue, featureSelectionId, fetchElevations, formatCameraAltitude, formatExpressionPreviewValue, formatPixelValue, formatPopupValue, formatRoundNum, generatorCircleRadiusValue, generatorSizeRange, geoJSONToPolylineStr, geocodeForward, geocodeMatchToFeature, geocodeReverse, geocoderMinIntervalMs, geocoderNeedsApiKey, geojsonHasZCoordinates, getActiveBodyRadiusRatio, getActiveEllipsoid, getActiveMeanRadiusMeters, getActiveSemiMajorAxisMeters, getAttributeFormField, getBuildEnvironment, getCesiumIonToken, getEllipsoid, getExternalNativePaintBridge, getGeocoderConfig, getGeocodingProvider, getGoogleMapsApiKey, getHistoryCoalesceMs, getMapboxAccessToken, getMaxHistoryFeatureCount, getPlanetaryBasemapById, getPlanetaryBasemapByStyleUrl, getProtomapsApiKey, getProtomapsStyleUrl, getRegionalBasemapById, getRegionalBasemapByStyleUrl, getRoundNum, getRoutingConfig, getRuntimeEnvironment, getSpatialExtensionPath, getVectorColorRamp, googleMapsApiKeyHeaderValue, groupMemberIndices, hasActiveQuickFilter, hasAppPrivilege, hasPathTraversal, hasRestorableLayerSource, hasSimpleStyleProperties, inferFieldTypes, inferLayerCapabilities, initialLayerStyle, interpolateColors, interpolateHexColor, interpolateRampColors, intersectPrivileges, invertSelection, isAbsoluteFilesystemPath, isAllowedPluginManifestUrl, isAttributeFormFieldVisible, isCredentialFieldName, isDefaultPrintLayout, isDeploymentCapability, isDiagramStyleEnabled, isDuckDBQueryLayer, isExternalNativeLayerRecord, isGooglePhotorealisticTilesetUrl, isHexColor, isInitialLayerStyle, isInlineImageValue, isInternalPopupField, isIpadDesktopUserAgent, isMaintainedEditorTrackingField, isPopupClickEnabled, isPopupHoverEnabled, isRegionalBasemapSentinel, isSafePopupUrl, isStyleLibraryTargetLayer, isStyleSpecColor, isVectorColorExpression, isochroneResponseToFeatures, layerGroupDepth, layerGroupMoveability, layerJoinKey, layerLibraryConfigPatch, layerLibraryEntryNeedsLocalFile, layerPanelGroupHeaders, lineWidthValue, mapZoomStepOutputs, matchFeaturesByExpression, matrixResponseToFeatures, meanRadiusMeters, mercatorMetersPerPixelAtZoom0, metersWidthExpression, nextDelayMs, nextLayerPaletteColor, nominatimResultToFeature, nominatimReverseResultToDisplay, nonEmptyRecord, normalizeAppPrivileges, normalizeBlankBackgroundColor, normalizeDashboardColumns, normalizeGeocodingProviderId, normalizeGroupContiguity, normalizeHexColor, normalizeLayerCapabilities, normalizeLayerLibraryEntries, normalizeMapLayout, normalizeMapViewState, normalizeModelGraph, normalizeModels, normalizePrintLayoutConfig, normalizeProcessingHistory, normalizeProjectComments, normalizeSecondaryMapViews, normalizeStoryMap, normalizeStyleLibraryEntries, normalizeWidgets, parseContours, parseDeploymentCapabilities, parseHexColor, parseHexColorList, parseJsonExpression, parseLayerLibrary, parseProject, parseStoryMapCsv, parseStoryMapJson, parseStyleLibrary, parseValueMapText, persistedThreeDTilesRequestHeaders, pickEditorIdentity, planLayerLibraryAdd, pluginOwnsPaint, polylineStrToGeoJSON, popupFieldLabel, printLayoutConfigsEqual, projectFromStore, projectPathLabel, proportionalRadiusExpression, proportionalSizeRange, readStoredAuthorName, reapplyLayerJoins, redactCredentials, redactProjectCredentials, redactUrlCredentials, redo, registerProjectRestoreHistory, removeTrailingJsonCommas, reorderLayerGroupInPanel, requestIsochrone, requestMatrix, requestRoute, resolveConfiguredPopupTitle, resolveEditorTrackingConfig, resolveGeocoderConfig, resolveLayerCapabilities, resolveMapGrid, resolvePopupBody, resolvePopupRows, resolvePopupTitle, resolveRolePrivileges, resolveSvgSource, resolveThreeDTilesRequestHeaders, rgbToHex, routeResponseToFeatures, rowCap, ruleBasedColorExpression, ruleBasedVisibilityFilter, sameCesiumImagery, sampleMapTerrain, sampleMapTerrainPoint, sampleRemoteElevations, sanitizeLayerStylePatch, scaleAltitudeToActiveBody, scaleDenomination, scaleSpan, scrubCommentsForRemovedLayers, scrubLegendForRemovedLayers, scrubPrintLayoutForLayers, scrubPrintLayoutForRemovedLayers, scrubWidgetsForRemovedLayers, serializeLayerLibrary, serializeProject, serializeStoryMapCsv, serializeStoryMapJson, serializeStyleLibrary, setActiveEllipsoidId, setExternalNativePaintBridge, setGeocodingFetch, setHistoryCoalesceMs, setMaxHistoryFeatureCount, setStoredAuthorName, shouldThrottle, shouldUseTiledRendering, simpleStyleNumberValue, stampFeatureCollectionEditorTracking, stampFeatureEditorTracking, stampFeaturePropertiesEditorTracking, storyMapHasContent, stringifyPopupValue, stripGoogleMapsApiKeyHeader, stripJoinFields, stripVirtualFieldColumns, styleValue, subscribeProjectRestoreHistory, substituteExpressionVariables, supportsBridgedOpacity, transformGeojsonElevation, trimHistoryBySize, undo, unescapePolyline, unmatchedGeocodeFeature, unresolvedLayerLibraryJoins, useAppCapability, useAppStore, validateAttributeFormField, validateAttributeFormValues, validateMapExpression, valueMapLabelFor, valueMapToText, vectorCircleColorValue, vectorColorExpression, vectorFillColorValue, vectorFillOpacityValue, vectorLineColorValue, vectorOutlineColorValue, vectorStrokeWidthValue, visiblePopupFields, visiblePopupProperties };
12635
13095
 
12636
13096
  //# sourceMappingURL=index.mjs.map