/** * Wrapper API — replaces gadm_wrapper.py CLI. * * Provides the same 3 operations: searchRegions, getBoundary, getRegionNames. * Includes file-based caching identical to the Python wrapper. */ import { getNames } from './names.js'; import { getItems } from './items.js'; import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import { enrichFeatureWithGHS } from './enrich-ghs.js'; // ---------- cache ---------- const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); const LOCAL_CACHE_DIR = join(_dirname, '../cache/gadm'); const CACHE_DIR = process.env.GADM_CACHE || LOCAL_CACHE_DIR; function getCacheKey(prefix, value) { const safeValue = value.replace(/[^a-zA-Z0-9\.\-_]/g, '_').substring(0, 50); return `${prefix}_${safeValue}`; } function cachePath(key) { return join(CACHE_DIR, `${key}.json`); } async function readCache(key, extCache) { if (extCache) { try { const cached = await extCache.get(key); if (cached) return cached; } catch { } return null; // fallback or ignore } const path = cachePath(key); if (!existsSync(path)) return null; try { return JSON.parse(readFileSync(path, 'utf-8')); } catch { return null; } } async function writeCache(key, data, extCache) { if (extCache) { try { await extCache.set(key, data); } catch { } return; } const path = cachePath(key); try { mkdirSync(dirname(path), { recursive: true }); console.log('Writing cache:', path); writeFileSync(path, JSON.stringify(data)); } catch (e) { console.error('Cache write failed:', e); } } /** * Search for admin regions by name. * Returns metadata rows or GeoJSON FeatureCollection. */ export async function searchRegions(opts) { const { query, contentLevel, geojson = false, country, cache } = opts; const prefix = `search_${contentLevel ?? 'all'}_${geojson ? 'geo' : 'meta'}_${country ?? 'all'}`; const key = getCacheKey(prefix, query); const cached = await readCache(key, cache); if (cached) return cached; try { if (geojson) { // GeoJSON mode — use Items const itemOpts = { name: [query], cache }; if (contentLevel != null) itemOpts.contentLevel = contentLevel; try { const gdf = await getItems(itemOpts); const output = { type: 'FeatureCollection', features: gdf.features, }; await writeCache(key, output, cache); return output; } catch (e) { // Try first part if comma-separated if (query.includes(',')) { const first = query.split(',')[0].trim(); itemOpts.name = [first]; try { const gdf = await getItems(itemOpts); const output = { type: 'FeatureCollection', features: gdf.features, }; await writeCache(key, output, cache); return output; } catch { return { data: [] }; } } throw e; } } else { // Metadata mode — use Names const namesOpts = { name: query }; if (contentLevel != null) namesOpts.contentLevel = contentLevel; if (country) namesOpts.admin = country; try { const result = await getNames(namesOpts); const output = { data: result.rows }; await writeCache(key, output, cache); return output; } catch { // Try first part if comma-separated if (query.includes(',')) { const first = query.split(',')[0].trim(); namesOpts.name = first; try { const result = await getNames(namesOpts); const output = { data: result.rows }; await writeCache(key, output, cache); return output; } catch { return { data: [] }; } } return { data: [] }; } } } catch (e) { return { error: e.stack || e.message }; } } import { getBoundaryFromGpkg } from './gpkg-reader.js'; /** * Get boundary GeoJSON for a specific GADM ID. * Optionally enriches the boundary with GHS Population and Built-up Area data! */ export async function getBoundary(gadmId, contentLevel, cache, enrichOptions, resolution = 3) { const enrichKeySuffix = enrichOptions ? '_enriched' : ''; const keySuffix = `${contentLevel ?? 'auto'}_${gadmId}${enrichKeySuffix}`; const key = getCacheKey(`boundary`, keySuffix); // 1. Check if we already have the EXACT requested state cached const cached = await readCache(key, cache); if (cached) return cached; // 2. Fetch the base geometry let baseCollection = null; // First try the far superior SQLite GeoPackage const gpkgRes = await getBoundaryFromGpkg(gadmId, contentLevel, cache, resolution); if (gpkgRes) { baseCollection = gpkgRes; } else { // Fallback exactly as before to Parquet mode const baseKey = getCacheKey(`boundary_${contentLevel ?? 'auto'}`, gadmId); const baseCached = await readCache(baseKey, cache); if (baseCached) { baseCollection = baseCached; } else { try { const gdf = await getItems({ admin: [gadmId], contentLevel, cache }); if (gdf.features.length === 0) { return { error: 'Region not found' }; } baseCollection = gdf; await writeCache(baseKey, baseCollection, cache); } catch (e) { return { error: e.message }; } } } let collectionToReturn = baseCollection; // 3. Apply GeoTIFF enrichment if requested — skip if already enriched (e.g. from C++ cache) const alreadyEnriched = baseCollection?.features?.some((f) => f.properties?.ghsPopulation !== undefined); if (enrichOptions && !alreadyEnriched && baseCollection && baseCollection.features) { // Deep clone so we don't mutate an in-memory cached object accidentally collectionToReturn = JSON.parse(JSON.stringify(baseCollection)); for (const feature of collectionToReturn.features) { try { const enrichResult = await enrichFeatureWithGHS(feature, enrichOptions); Object.assign(feature.properties, enrichResult); // Set the default population property to the highly accurate GHS number if (enrichResult.ghsPopulation !== undefined) { feature.properties.population = enrichResult.ghsPopulation; } } catch (e) { console.error('GHS Enrichment failed for feature', feature.properties?.name || '', e); } } await writeCache(key, collectionToReturn, cache); } return collectionToReturn; } /** * Get names for all sub-regions of an admin area, optionally recursing through levels. */ export async function getRegionNames(opts) { const { admin, contentLevel, depth = 1, cache } = opts; const key = getCacheKey(`names_${admin}_${contentLevel}_${depth}`, 'names'); const cached = await readCache(key, cache); if (cached) return cached; try { const allResults = []; // Determine starting level from admin code let startLevel; if (contentLevel != null) { startLevel = contentLevel; } else { // GID format: XXX.L1.L2_1 — count dots + 1 startLevel = admin.split('.').length; // "ESP" = 1 dot → level 1 start if (!admin.includes('.')) startLevel = 1; // country code → start at level 1 } // Handle infinite depth const depthStr = String(depth).toLowerCase(); const limit = (depthStr === 'infinite' || depthStr === 'inf' || depthStr === '-1') ? 5 : Number(depth); let currentLevel = startLevel; for (let i = 0; i < limit; i++) { try { const result = await getNames({ admin, contentLevel: currentLevel, }); if (result.rows.length === 0) break; allResults.push(...result.rows); } catch { break; // Level doesn't exist } currentLevel++; } const output = { data: allResults }; await writeCache(key, output, cache); return output; } catch (e) { return { error: e.stack || e.message }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JhcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy93cmFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBQ0gsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN0QyxPQUFPLEVBQUUsUUFBUSxFQUErQyxNQUFNLFlBQVksQ0FBQztBQUNuRixPQUFPLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFHcEMsT0FBTyxFQUFFLG9CQUFvQixFQUF5QixNQUFNLGlCQUFpQixDQUFDO0FBRTlFLDhCQUE4QjtBQUU5QixNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNqRCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7QUFFcEMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxlQUFlLENBQUMsQ0FBQztBQUN4RCxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxlQUFlLENBQUM7QUFFNUQsU0FBUyxXQUFXLENBQUMsTUFBYyxFQUFFLEtBQWE7SUFDOUMsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsRUFBRSxHQUFHLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzVFLE9BQU8sR0FBRyxNQUFNLElBQUksU0FBUyxFQUFFLENBQUM7QUFDcEMsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLEdBQVc7SUFDMUIsT0FBTyxJQUFJLENBQUMsU0FBUyxFQUFFLEdB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