GODSIGH/js/keyed.js

91 lines
3.7 KiB
JavaScript

// Key-gated features (Wave 4.1) — the upstream God's Eye View extras, built in
// but dormant until a working key activates them. Keys live in assets/keys.json
// (gitignored — copy assets/keys.json.example) and are CLIENT-EXPOSED by
// design: restrict each key at its provider (see README §Key-gated extras).
// No file / empty key = the feature stays hidden or explains itself.
//
// google → "3D" basemap mode: Google Photorealistic 3D Tiles (metered 🔴)
// cesiumIon → "Bing" basemap mode: Bing aerial via Cesium ion (free 🟡)
// tomtom → Traffic flow overlay layer (free 🟡)
//
// OpenAI voice is NOT here — its key must never ship to a server; see voice.js.
export async function loadKeys() {
try {
const r = await fetch('assets/keys.json', { cache: 'no-store' });
if (r.ok) return await r.json();
} catch { /* absent file = no keys, by design */ }
return {};
}
// hooks: { onBasemapReady(kind, resource), mode3dActive(), solarActive() }
export async function initKeyed(ctx, hooks) {
const { viewer, Cesium } = ctx;
const keys = await loadKeys();
// ---- Bing aerial (Cesium ion asset 2) → "Bing" basemap mode ----
if (keys.cesiumIon) {
try {
Cesium.Ion.defaultAccessToken = keys.cesiumIon;
const prov = await Cesium.IonImageryProvider.fromAssetId(2);
const layer = viewer.imageryLayers.addImageryProvider(prov);
layer.show = false;
hooks.onBasemapReady('bing', layer);
} catch (err) {
console.warn('[godsigh] Cesium ion key configured but Bing failed:', err);
}
}
// ---- Google Photorealistic 3D Tiles → "3D" basemap mode ----
if (keys.google) {
try {
const tiles = await Cesium.Cesium3DTileset.fromUrl(
`https://tile.googleapis.com/v1/3dtiles/root.json?key=${encodeURIComponent(keys.google)}`,
{ showCreditsOnScreen: true }, // Google attribution is a licence condition
);
tiles.show = false;
viewer.scene.primitives.add(tiles);
// keyed.js owns tiles.show: on only in 3D mode and never inside Solar
// System mode (which hides the globe but not this primitive — without
// this, tiles would render under the orrery and stream paid quota).
viewer.scene.preUpdate.addEventListener(() => {
const want = hooks.mode3dActive() && !hooks.solarActive();
if (tiles.show !== want) tiles.show = want;
});
hooks.onBasemapReady('3d', tiles);
} catch (err) {
console.warn('[godsigh] Google key configured but 3D tiles failed:', err);
}
}
// ---- TomTom live traffic flow — row always present so the capability is
// discoverable; keyless it just says how to get the (free) key. ----
initTraffic(ctx, keys.tomtom);
return keys;
}
function initTraffic({ viewer, ui, Cesium }, key) {
let layer = null;
if (key) {
const prov = new Cesium.UrlTemplateImageryProvider({
url: `https://api.tomtom.com/traffic/map/4/tile/flow/relative0/{z}/{x}/{y}.png?key=${encodeURIComponent(key)}`,
maximumLevel: 20,
credit: 'Traffic © TomTom',
});
layer = viewer.imageryLayers.addImageryProvider(prov);
layer.alpha = 0.75;
layer.show = false;
}
ui.addLayer('tomtom', 'Traffic flow (TomTom)', false, (on) => {
if (!layer) {
// ponytail: key is not validated up front; a bad key just renders no tiles
ui.setStatus('tomtom', on ? 'needs key — assets/keys.json (free: developer.tomtom.com)' : '', on ? 'warn' : 'off');
return;
}
layer.show = on;
ui.setStatus('tomtom', on ? 'live congestion tiles · © TomTom' : '', on ? 'ok' : 'off');
}, 'Context');
ui.setStatus('tomtom', key ? 'key loaded — toggle on' : 'off — free key unlocks', 'off');
}