Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
1da9f0c
Keep worldwide base surface continuous at every zoom
Occumed79 Jul 28, 2026
3f8883f
Keep base landcover visible from globe zoom
Occumed79 Jul 28, 2026
a3ea969
Guard continuous globe landcover
Occumed79 Jul 28, 2026
d0805fb
Validate one continuous physical surface across zooms
Occumed79 Jul 28, 2026
8bb9888
Validate base surface continuity across zoom thresholds
Occumed79 Jul 28, 2026
457e6f8
Validate every zoom level continuously
Occumed79 Jul 28, 2026
9640247
Run a full-range zoom sweep in CI
Occumed79 Jul 28, 2026
5d15102
Add tracked outward globe atmosphere bloom
Occumed79 Jul 28, 2026
52e25c9
Render a visible exterior atmosphere halo
Occumed79 Jul 28, 2026
947f198
Guard the tracked atmosphere bloom
Occumed79 Jul 28, 2026
8444975
Prove the atmosphere bloom in globe renders
Occumed79 Jul 28, 2026
3b45fcc
Harden PMTiles range fetching and circuit breaking
Occumed79 Jul 28, 2026
63f629f
Harden worldwide tile gateway failure handling
Occumed79 Jul 28, 2026
fb71744
Harden worldwide shard routing index
Occumed79 Jul 28, 2026
a737282
Add vector tile safety budgets
Occumed79 Jul 28, 2026
1f49eca
Add worldwide gateway chaos hardening tests
Occumed79 Jul 28, 2026
8e6d9a6
Run worldwide hardening checks in every build
Occumed79 Jul 28, 2026
ec3f1f4
Aggressively harden the production map server
Occumed79 Jul 28, 2026
8590603
Clean retry abort listeners and expose circuit behavior
Occumed79 Jul 28, 2026
dd64185
Exercise PMTiles circuit breaker in chaos tests
Occumed79 Jul 28, 2026
531ad52
Keep essential retry timers referenced
Occumed79 Jul 28, 2026
3717689
Align PMTiles integration guard with hardened continuous surface
Occumed79 Jul 28, 2026
1629d87
Add candidate HTTP hardening and concurrency gate
Occumed79 Jul 28, 2026
212236d
Run candidate HTTP hardening before visual sweeps
Occumed79 Jul 28, 2026
6f2ec6b
Add production dependency and lockfile security gate
Occumed79 Jul 28, 2026
5fc67b3
Validate every MVT payload before merge or overscale
Occumed79 Jul 28, 2026
cd5028f
Guard pre-merge and pre-overscale MVT validation
Occumed79 Jul 28, 2026
8c1ce47
Capture complete hardened build diagnostics
Occumed79 Jul 28, 2026
829a405
Install pinned native dependencies before hardened build
Occumed79 Jul 28, 2026
b6a1479
Validate the virtual tile route by behavior contract
Occumed79 Jul 28, 2026
c12ca8b
Allow canonical empty protobuf vector tiles
Occumed79 Jul 28, 2026
d0bb883
Keep worldwide landcover continuous through native surface zooms
Occumed79 Jul 28, 2026
f50ab1a
Strengthen the tracked exterior atmosphere bloom
Occumed79 Jul 28, 2026
f1d83c6
Make polygon and foundation validation exhaustive and forensic
Occumed79 Jul 28, 2026
d66b830
Stress every zoom across land ocean and antimeridian
Occumed79 Jul 28, 2026
9aff4b3
Make continuous motion validation exhaustive and forensic
Occumed79 Jul 28, 2026
3864ed9
Run every runtime hardening gate and preserve all diagnostics
Occumed79 Jul 28, 2026
7bb901e
Add sustained worldwide gateway soak validation
Occumed79 Jul 28, 2026
fe673c7
Require sustained worldwide gateway soak before browser validation
Occumed79 Jul 28, 2026
8966e9f
Lock continuous surface bloom and soak protections
Occumed79 Jul 28, 2026
fc359a8
Run continuous foundation lock in every hardened build
Occumed79 Jul 28, 2026
06e7763
Keep chaos and foundation locks as separate mandatory build gates
Occumed79 Jul 28, 2026
7086755
Restore the pinned MapLibre style-spec dependency
Occumed79 Jul 28, 2026
d0f957b
Keep the atmosphere bloom synchronized with every globe movement
Occumed79 Jul 28, 2026
1558726
Make continuous motion validation cycle-safe and exhaustive
Occumed79 Jul 28, 2026
6b156d5
Make full-range zoom validation cycle-safe and non-short-circuiting
Occumed79 Jul 28, 2026
3ea75ff
Run every polygon and atmosphere regression view before failing
Occumed79 Jul 28, 2026
f6c0d95
Apply documented continuous rendering contract
Occumed79 Jul 28, 2026
ffd9482
Run documented rendering contract last
Occumed79 Jul 28, 2026
05434c4
Lock documented source and layer zoom semantics
Occumed79 Jul 28, 2026
f2adbaa
Validate continuous bathymetry instead of cutoff
Occumed79 Jul 28, 2026
a197be1
Retain the complete zoom pyramid for reverse navigation
Occumed79 Jul 28, 2026
f3b05c8
Lock full zoom-pyramid retention into continuity checks
Occumed79 Jul 28, 2026
18739fc
Use source-idle and timer sampling for motion validation
Occumed79 Jul 28, 2026
41d8dab
Validate actual globe minimum with continuous timer sampling
Occumed79 Jul 28, 2026
7ca5686
Force bathymetry into every native surface zoom
Occumed79 Jul 28, 2026
ab3b4b7
Lock low-zoom depth and documented sampling behavior
Occumed79 Jul 28, 2026
7f85130
Accept full zoom-pyramid browser retention
Occumed79 Jul 28, 2026
7c1c410
Validate full browser zoom-pyramid retention
Occumed79 Jul 28, 2026
3b748ca
Serve navigation archives from local disk
Occumed79 Jul 28, 2026
dfe1e4d
Require localized navigation assets in production
Occumed79 Jul 28, 2026
b8e6265
Prebuild coarse navigation tiles through zoom 6
Occumed79 Jul 28, 2026
faaaed0
Fix continuous zoom validation instrumentation
Occumed79 Jul 28, 2026
26ee960
placeholder
Occumed79 Jul 28, 2026
bc376f8
Create Neon integration anchor
Occumed79 Jul 28, 2026
dab64f2
Implement durable Neon navigation cache
Occumed79 Jul 28, 2026
751ee14
Wire persistent navigation cache into tile gateway
Occumed79 Jul 28, 2026
b102596
Connect Neon cache to production tile server
Occumed79 Jul 28, 2026
f8ca69b
Add Postgres client for Neon navigation cache
Occumed79 Jul 28, 2026
2efd88b
Add Neon navigation cache unit guard
Occumed79 Jul 28, 2026
74506e0
Document Neon navigation cache configuration
Occumed79 Jul 28, 2026
df20464
Verify memory-first Neon cache gateway flow
Occumed79 Jul 28, 2026
51842f8
Run focused Neon cache finalization
Occumed79 Jul 28, 2026
be74321
Use Neon HTTP SQL for durable navigation cache
Occumed79 Jul 28, 2026
6d1b43a
Keep Neon cache dependency-free
Occumed79 Jul 28, 2026
94ed983
Remove temporary Neon finalization workflow
Occumed79 Jul 28, 2026
27475bc
Remove temporary Neon integration anchor
Occumed79 Jul 28, 2026
59f5ee1
Test Neon HTTP cache transport and gateway flow
Occumed79 Jul 28, 2026
40f266b
Cap shared-project Neon cache storage safely
Occumed79 Jul 28, 2026
a7ee9b2
Document safe shared-project Neon cache limit
Occumed79 Jul 28, 2026
7ed506e
Fix Neon cache gateway guard variable
Occumed79 Jul 28, 2026
fbb0d11
Restore independent Neon project cache capacity
Occumed79 Jul 28, 2026
a4f45ef
Document independent Neon project cache capacity
Occumed79 Jul 28, 2026
df0efe4
Update continuity lock for lightweight validation sampling
Occumed79 Jul 28, 2026
71aa755
Fix continuous base surface retention
Occumed79 Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,21 @@ OCCUMED_WORLD_RELEASE_REPOSITORY=Occumed79/Map
OCCUMED_WORLD_RELEASE_TAG=occumed-world-v1
OCCUMED_WORLD_MANIFEST_URL=
OCCUMED_TILE_CACHE_MAX_BYTES=134217728

# Durable server-only cache for precomputed navigation tiles at zooms 0-6.
# Each NAV_DATABASE_URL must point to a separate Neon project so every cache
# shard has its own project storage allowance. The default retains up to 48 MiB
# per project, or approximately 384 MiB across all eight configured projects.
NAV_DATABASE_URL_1=
NAV_DATABASE_URL_2=
NAV_DATABASE_URL_3=
NAV_DATABASE_URL_4=
NAV_DATABASE_URL_5=
NAV_DATABASE_URL_6=
NAV_DATABASE_URL_7=
NAV_DATABASE_URL_8=
OCCUMED_NAV_CACHE_MAX_ZOOM=6
OCCUMED_NAV_CACHE_QUERY_TIMEOUT_MS=1500
OCCUMED_NAV_CACHE_RETRY_DELAY_MS=30000
OCCUMED_NAV_CACHE_MAX_BYTES_PER_SHARD=50331648
OCCUMED_NAV_CACHE_PRUNE_EVERY_WRITES=64
67 changes: 67 additions & 0 deletions .github/workflows/security-hardening.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Validate Map Security Hardening

on:
workflow_dispatch:
pull_request:
branches:
- main
paths:
- .github/workflows/**
- package.json
- package-lock.json
- scripts/**
- src/server/**
- src/occumed-map.js
- server.mjs

permissions:
contents: read

concurrency:
group: occumed-map-security-${{ github.ref }}
cancel-in-progress: true

jobs:
production-security:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- name: Install exactly from the committed lockfile
run: npm ci

- name: Reject production dependency vulnerabilities
run: npm audit --omit=dev --audit-level=high

- name: Validate production dependency graph
run: npm ls --omit=dev --all

- name: Reject remote Git package sources
run: |
set -euo pipefail
if grep -E '"resolved": "(?:git\+|git://|ssh://|https://github\.com/.+\.git)' package-lock.json; then
echo 'Remote Git package sources are not allowed in the production lockfile.' >&2
exit 1
fi

- name: Run deterministic gateway chaos guards
run: node scripts/check-world-hardening.mjs

- name: Capture complete hardened production build
run: |
set -o pipefail
npm run build 2>&1 | tee hardening-build.log

- uses: actions/upload-artifact@v4
if: always()
with:
name: hardening-build-${{ github.sha }}
path: hardening-build.log
if-no-files-found: error
retention-days: 7
55 changes: 49 additions & 6 deletions .github/workflows/validate-continuous-zoom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,42 +86,85 @@ jobs:
- name: Install Chromium
run: npx playwright install --with-deps chromium

- name: Run continuous zoom and pan gate
- name: Run every hardened HTTP and browser gate
run: |
set -euo pipefail
mkdir -p continuous-motion
mkdir -p continuous-motion/results continuous-motion/all-zoom-levels
OCCUMED_WORLD_OVERVIEW_URL="http://127.0.0.1:4173/virtual-assets/${OVERVIEW_ASSET}" \
OCCUMED_WORLD_SURFACE_URL="http://127.0.0.1:4173/virtual-assets/${SURFACE_ASSET}" \
OCCUMED_ENABLE_DIAGNOSTICS="true" \
node server.mjs > continuous-motion/server.log 2>&1 &
server_pid="$!"
cleanup() {
status="$?"
if [ "$status" -ne 0 ]; then
tail -300 continuous-motion/server.log || true
tail -500 continuous-motion/server.log || true
fi
kill "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
exit "$status"
}
trap cleanup EXIT

for attempt in {1..90}; do
for attempt in {1..120}; do
if curl --fail --silent http://127.0.0.1:4173/healthz > /dev/null; then
break
fi
sleep 1
done
curl --fail http://127.0.0.1:4173/healthz

OCCUMED_PREVIEW_OUTPUT=continuous-motion/results \
overall_status=0
run_gate() {
gate_name="$1"
shift
set +e
"$@" 2>&1 | tee "continuous-motion/${gate_name}.log"
gate_status="${PIPESTATUS[0]}"
set -e
printf '%s=%s\n' "$gate_name" "$gate_status" >> continuous-motion/gate-status.txt
if [ "$gate_status" -ne 0 ]; then
overall_status=1
fi
}

run_gate http-hardening \
node scripts/check-world-http-hardening.mjs

run_gate world-soak \
env OCCUMED_SOAK_OUTPUT=continuous-motion/world-soak-report.json \
node scripts/check-world-soak.mjs

run_gate continuous-motion \
env OCCUMED_PREVIEW_OUTPUT=continuous-motion/results \
node scripts/validate-continuous-zoom.mjs

run_gate all-zoom-levels \
env OCCUMED_PREVIEW_OUTPUT=continuous-motion/all-zoom-levels \
node scripts/validate-all-zoom-levels.mjs

set +e
curl --fail --silent http://127.0.0.1:4173/internal/tile-health \
> continuous-motion/tile-health.json
health_status="$?"
set -e
printf 'tile-health=%s\n' "$health_status" >> continuous-motion/gate-status.txt
if [ "$health_status" -ne 0 ]; then
overall_status=1
fi

exit "$overall_status"

- uses: actions/upload-artifact@v4
if: always()
with:
name: continuous-zoom-${{ github.sha }}
path: |
continuous-motion/results
continuous-motion/server.log
continuous-motion/all-zoom-levels
continuous-motion/*.log
continuous-motion/*.json
continuous-motion/gate-status.txt
dist/virtual-assets/occumed-world-overview.pmtiles
if-no-files-found: error
retention-days: 14
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
"type": "module",
"scripts": {
"prepare:sprites": "node scripts/build-sprites.mjs",
"prepare:style": "node scripts/build-runtime-style.mjs && node scripts/normalize-runtime-fonts.mjs && node scripts/normalize-runtime-filters.mjs && node scripts/normalize-boundary-filters.mjs && node scripts/force-runtime-filter-expressions.mjs && node scripts/apply-schema-parity.mjs && node scripts/apply-globe-parity.mjs && node scripts/apply-photo-reference.mjs && node scripts/restore-exported-cartography.mjs && node scripts/calibrate-reference-colors.mjs && node scripts/lock-exact-exported-swatches.mjs && node scripts/lock-reference-atmosphere.mjs && node scripts/normalize-runtime-fonts.mjs && node scripts/use-local-maplibre-glyphs.mjs",
"prepare:style": "node scripts/build-runtime-style.mjs && node scripts/normalize-runtime-fonts.mjs && node scripts/normalize-runtime-filters.mjs && node scripts/normalize-boundary-filters.mjs && node scripts/force-runtime-filter-expressions.mjs && node scripts/apply-schema-parity.mjs && node scripts/apply-globe-parity.mjs && node scripts/apply-photo-reference.mjs && node scripts/restore-exported-cartography.mjs && node scripts/calibrate-reference-colors.mjs && node scripts/lock-exact-exported-swatches.mjs && node scripts/lock-reference-atmosphere.mjs && node scripts/normalize-runtime-fonts.mjs && node scripts/apply-mapbox-rendering-contract.mjs && node scripts/use-local-maplibre-glyphs.mjs",
"prepare:assets": "npm run prepare:sprites && npm run prepare:style",
"tiles:build": "bash planetiler/build-region.sh",
"tiles:plan-world": "node scripts/plan-world-shards.mjs --scope all",
"check:export": "node scripts/check-export.mjs",
"check:runtime": "node scripts/check-runtime.mjs && node scripts/validate-maplibre-style.mjs && node scripts/check-globe-parity.mjs && node scripts/check-cartography-parity.mjs && node scripts/check-viewer-quality.mjs && node scripts/check-photo-reference.mjs && node scripts/check-exact-exported-swatches.mjs && node scripts/check-render-clarity.mjs && node scripts/check-pmtiles-integration.mjs && node scripts/check-world-tile-gateway.mjs",
"check:hardening": "node scripts/check-world-hardening.mjs",
"check:foundation": "node scripts/check-continuous-foundation-lock.mjs",
"check:neon-cache": "node scripts/check-neon-navigation-cache.mjs",
"check:runtime": "node scripts/check-runtime.mjs && node scripts/validate-maplibre-style.mjs && node scripts/check-globe-parity.mjs && node scripts/check-cartography-parity.mjs && node scripts/check-viewer-quality.mjs && node scripts/check-photo-reference.mjs && node scripts/check-exact-exported-swatches.mjs && node scripts/check-render-clarity.mjs && node scripts/check-pmtiles-integration.mjs && node scripts/check-world-tile-gateway.mjs && npm run check:neon-cache && npm run check:hardening && npm run check:foundation",
"check:server": "node scripts/check-server-health.mjs",
"check": "npm run check:export && npm run check:runtime",
"dev": "npm run prepare:assets && vite",
"build": "npm run prepare:assets && npm run check && vite build && npm run check:server",
"preview": "vite preview",
"start": "node server.mjs"
"start": "node scripts/start-localized-world.mjs"
},
"dependencies": {
"@mapbox/vector-tile": "2.0.4",
Expand Down
109 changes: 109 additions & 0 deletions scripts/apply-mapbox-rendering-contract.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const runtimePath = path.join(root, 'public/style/occumed-open.json');
const runtime = JSON.parse(await fs.readFile(runtimePath, 'utf8'));

const FOUNDATION_LAYERS = new Set(['land', 'landcover', 'depth']);
const PERMANENT_TILE_PATTERN = '/tiles/{z}/{x}/{y}.pbf';

function sourceLayerName(layer) {
return String(
layer?.['source-layer'] ||
layer?.metadata?.['occumed:open-source-layer'] ||
''
).toLowerCase();
}

function isPermanentWorldwideSource(source) {
return source?.type === 'vector' &&
Array.isArray(source.tiles) &&
source.tiles.some((url) => String(url).includes(PERMANENT_TILE_PATTERN));
}

let permanentSources = 0;
for (const source of Object.values(runtime.sources || {})) {
if (!isPermanentWorldwideSource(source)) continue;

// Mapbox/TileJSON semantics: source maxzoom describes the highest tile zoom
// available. The renderer may overscale those tiles above that zoom. Our
// virtual endpoint resolves through z16, so expose one uninterrupted source
// pyramid across the application's complete camera range.
source.minzoom = 0;
source.maxzoom = 16;
source.scheme = 'xyz';
permanentSources += 1;
}

if (permanentSources !== 1) {
throw new Error(`Expected exactly one permanent worldwide vector source; found ${permanentSources}.`);
}

// Prevent runtime paint-value changes from introducing an additional delayed
// fade. Zoom expressions still interpolate continuously; explicit style
// mutations apply immediately.
runtime.transition = { duration: 0, delay: 0 };

let foundationLayers = 0;
let landcoverLayers = 0;
let depthLayers = 0;
for (const layer of runtime.layers || []) {
const sourceLayer = sourceLayerName(layer);
if (!FOUNDATION_LAYERS.has(sourceLayer)) continue;

layer.minzoom = 0;
delete layer.maxzoom;
layer.layout ||= {};
layer.layout.visibility = 'visible';
layer.metadata = {
...(layer.metadata || {}),
'occumed:continuous-foundation': true,
'occumed:documented-overscaling-contract': true
};
foundationLayers += 1;

if (sourceLayer === 'landcover' && layer.type === 'fill') {
layer.paint ||= {};
layer.paint['fill-opacity'] = [
'interpolate', ['linear'], ['zoom'],
0, 0.92,
6, 0.88,
10, 0.82,
16, 0.82
];
landcoverLayers += 1;
}

if (sourceLayer === 'depth' && layer.type === 'fill') {
layer.paint ||= {};
const existingOpacity = layer.paint['fill-opacity'] ?? 1;
// Preserve each bathymetry band's authored opacity while preventing any
// exported high-zoom expression from reducing the layer to zero.
layer.paint['fill-opacity'] = ['max', 0.06, existingOpacity];
depthLayers += 1;
}
}

if (!foundationLayers || !landcoverLayers || !depthLayers) {
throw new Error(
`Incomplete documented rendering contract: ${foundationLayers} foundation, ` +
`${landcoverLayers} landcover, ${depthLayers} depth layers.`
);
}

runtime.metadata = {
...(runtime.metadata || {}),
'occumed:mapbox-style-contract-applied': true,
'occumed:single-source-minzoom': 0,
'occumed:single-source-maxzoom': 16,
'occumed:foundation-layer-maxzoom': null,
'occumed:style-transition-duration-ms': 0
};

await fs.writeFile(runtimePath, `${JSON.stringify(runtime, null, 2)}\n`);
console.log(
`Applied documented single-source rendering contract to ${foundationLayers} foundation layers ` +
`(${landcoverLayers} landcover, ${depthLayers} depth).`
);
3 changes: 2 additions & 1 deletion scripts/apply-schema-parity.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ water.metadata = {

const landcover = runtime.layers.find((layer) => layer.id === 'landcover');
if (!landcover) throw new Error('The exported landcover layer is missing from the runtime style.');
landcover.minzoom = 0;
landcover.paint ||= {};
landcover.paint['fill-opacity'] = [
'interpolate',
Expand All @@ -190,7 +191,7 @@ landcover.paint['fill-opacity'] = [
];
landcover.metadata = {
...(landcover.metadata || {}),
'occumed:purpose': 'strong exported vegetation hierarchy over open landcover data'
'occumed:purpose': 'continuous worldwide vegetation foundation with regional detail added above it'
};

runtime.metadata = {
Expand Down
19 changes: 14 additions & 5 deletions scripts/build-world-overview.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { mergeVectorTiles } from '../src/server/mvt.js';
import { RetryingFetchSource } from '../src/server/pmtiles-source.js';
import { WorldTileRoutingIndex } from '../src/server/world-tile-routing.js';

const MIN_NAVIGATION_MAX_ZOOM = 6;

function parseArgs(argv) {
const options = {
maxZoom: 5,
maxZoom: MIN_NAVIGATION_MAX_ZOOM,
concurrency: 24
};
for (let index = 0; index < argv.length; index += 1) {
Expand All @@ -26,6 +28,13 @@ function parseArgs(argv) {
if (!Number.isSafeInteger(options.maxZoom) || options.maxZoom < 0 || options.maxZoom > 8) {
throw new Error('--maxzoom must be an integer between 0 and 8.');
}
if (options.maxZoom < MIN_NAVIGATION_MAX_ZOOM) {
console.warn(
`Requested overview max zoom ${options.maxZoom} is unsafe for reverse navigation; ` +
`building through zoom ${MIN_NAVIGATION_MAX_ZOOM} instead.`
);
options.maxZoom = MIN_NAVIGATION_MAX_ZOOM;
}
if (!Number.isSafeInteger(options.concurrency) || options.concurrency < 1 || options.concurrency > 64) {
throw new Error('--concurrency must be an integer between 1 and 64.');
}
Expand Down Expand Up @@ -125,9 +134,9 @@ const metadata = await archive(metadataRegion).getMetadata();
await fs.writeFile(
path.join(options.output, 'metadata.json'),
`${JSON.stringify({
name: 'Occu-Med Worldwide Overview',
description: 'Consolidated low-zoom tiles from the Occu-Med regional storage shards',
version: '1',
name: 'Occu-Med Worldwide Navigation Overview',
description: 'Consolidated coarse-navigation tiles from the Occu-Med regional storage shards',
version: '2',
type: 'baselayer',
format: 'pbf',
minzoom: 0,
Expand All @@ -139,5 +148,5 @@ await fs.writeFile(
);

console.log(
`Worldwide overview complete: ${writtenTiles} tiles, ${sourceTileReads} shard reads, zoom 0-${options.maxZoom}.`
`Worldwide navigation overview complete: ${writtenTiles} tiles, ${sourceTileReads} shard reads, zoom 0-${options.maxZoom}.`
);
Loading
Loading