Files
gods-eye-view/src/app/catalog.js
T
Said TurkseverandClaude Fable 5.1 9ba6f96d87 Merge upstream/main into pr/mapillary-layer
Upstream took share token '2' for fire perimeters, so Street Level moves to
'3'. mapillary-js joins upstream's optimizeDeps include list instead of
overriding it; catalog and registry tests count the new upstream layers.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-25 17:58:27 +01:00

62 lines
2.0 KiB
JavaScript

const CONTROL_LAYER_IDS = Object.freeze({
trafficLayer: 'traffic',
flightsLayer: 'flights',
militaryFlightsLayer: 'military',
satellitesLayer: 'satellites',
cctvLayer: 'cctv',
mapillaryLayer: 'mapillary',
radioLayer: 'radio',
bikeshareLayer: 'bikeshare',
transitLayer: 'transit',
aisLiveVesselsLayer: 'ais-live-vessels',
militaryAwarenessLayer: 'military-awareness',
militaryInstallationsLayer: 'military-installations',
rocketLaunchesLayer: 'rocket-launches',
localAdsbLayer: 'local-adsb',
});
/** Capture the ordered application instances and their serialization metadata. */
export function createLayerCatalog(layers, metadata) {
if (!Array.isArray(layers) || !Array.isArray(metadata))
throw new TypeError(
'Layer instances and serialization metadata are required',
);
const byId = new Map();
for (const layer of layers) {
if (typeof layer?.id !== 'string' || !layer.id || byId.has(layer.id))
throw new TypeError(`Invalid or duplicate catalog layer: ${layer?.id}`);
byId.set(layer.id, layer);
}
const ids = new Set();
for (const entry of metadata) {
if (!byId.has(entry?.id) || ids.has(entry.id))
throw new TypeError(
`Unmatched or duplicate catalog metadata: ${entry?.id}`,
);
ids.add(entry.id);
}
if (ids.size !== byId.size)
throw new TypeError('Catalog metadata is incomplete');
return Object.freeze({
layers: Object.freeze([...layers]),
metadata: Object.freeze(
metadata.map((entry) => Object.freeze({ ...entry })),
),
get: (id) => byId.get(id),
});
}
/** Bind the current control surface to the exact instances registered by the app. */
export function catalogControlServices(catalog) {
if (!catalog?.get)
throw new TypeError('An application layer catalog is required');
return Object.fromEntries(
Object.entries(CONTROL_LAYER_IDS).map(([role, id]) => {
const layer = catalog.get(id);
if (!layer)
throw new TypeError(`Control layer missing from catalog: ${id}`);
return [role, layer];
}),
);
}