/** * Items — GeoJSON boundary fetcher. * * Reads geometry from a local GeoPackage file when available, * falls back to the GADM CDN. Results include corrected names * from the parquet database. */ import { getNames } from './names.js'; import { getBoundaryFromGpkg } from './gpkg-reader.js'; import { readFileSync } from 'fs'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; const __filename_ = fileURLToPath(import.meta.url); const __dirname_ = dirname(__filename_); // ---------- constants ---------- const GADM_URL = 'https://geodata.ucdavis.edu/gadm/gadm4.1/json/gadm41_{}_{}.json'; /** Continent → ISO3 codes mapping */ const CONTINENT_MAP = JSON.parse(readFileSync(resolve(__dirname_, '../data/gadm_continent.json'), 'utf-8')); // ---------- main function ---------- /** * Fetch GeoJSON boundaries for administrative areas. * Tries local GeoPackage first, falls back to GADM CDN. */ export async function getItems(opts) { let { name, admin, contentLevel = -1, cache } = opts; // Normalize to arrays let names = typeof name === 'string' ? [name] : (name || []); let admins = typeof admin === 'string' ? [admin] : (admin || []); if (names.length === 0 && admins.length === 0) { throw new Error('At least "name" or "admin" need to be set.'); } // Continent expansion if (names.length === 1 && names[0].toLowerCase() in CONTINENT_MAP) { admins = CONTINENT_MAP[names[0].toLowerCase()]; names = []; } // Fetch all items const allFeatures = []; for (const n of names) { const features = await fetchSingleItem(n, '', contentLevel, cache); allFeatures.push(...features); } for (const a of admins) { const features = await fetchSingleItem('', a, contentLevel, cache); allFeatures.push(...features); } return { type: 'FeatureCollection', features: allFeatures, }; } // ---------- internal ---------- async function fetchSingleItem(name, admin, contentLevel, cache) { // Step 1: Look up the area to find its level + GID const lookupOpts = name ? { name } : { admin }; const lookup = await getNames(lookupOpts); if (lookup.rows.length > 1) { const id = name || admin; throw new Error(`The requested name ("${id}") is not unique (${lookup.rows.length} results). ` + `Use the "admin" parameter instead. ` + `To find the GADM code, use: getNames({ name: "${id}" })`); } const level = lookup.level; const gidCol = `GID_${level}`; const gadmId = lookup.rows[0][gidCol] || ''; // Step 2: Resolve content level const contentLookup = await getNames({ ...(name ? { name } : { admin }), contentLevel, }); const resolvedLevel = contentLookup.level; // Step 3: Try local GeoPackage first let localResult = await tryLocalGpkg(gadmId, name || admin, level, resolvedLevel, cache); // Step 4: Fallback to GADM CDN if (!localResult) { localResult = await fetchFromCDN(name, admin, gadmId, level, resolvedLevel); } if (resolvedLevel === level) { localResult.forEach(f => f.properties.isOuter = true); } return localResult; } /** * Read boundaries from local GeoPackage. * Returns features with all matching rows at the resolved content level. */ async function tryLocalGpkg(gadmId, id, level, resolvedLevel, cache) { // Query the GeoPackage for all rows belonging to this region const gidCol = `GID_${level}`; const nameCols = []; for (let l = 0; l <= Math.min(resolvedLevel, 5); l++) { nameCols.push(`NAME_${l}`, `GID_${l}`); } const result = await getBoundaryFromGpkg(gadmId, resolvedLevel, cache); if (!result || result.features.length === 0) return null; // Convert BoundaryFeature → GeoJSONFeature const features = result.features.map(f => ({ type: 'Feature', properties: f.properties, geometry: f.geometry, })); return features; } /** * Fallback: fetch from GADM CDN + correct names from parquet. */ async function fetchFromCDN(name, admin, gadmId, level, resolvedLevel) { const iso3 = gadmId.substring(0, 3); const url = GADM_URL.replace('{}', iso3).replace('{}', String(resolvedLevel)); let data; try { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); data = await res.json(); } catch (e) { throw new Error(`Cannot retrieve data from GADM server. ` + `Try opening: ${url}. ` + `If it fails, the error is from GADM servers.`); } // Convert to features const rawFeatures = data.features || []; let features = rawFeatures.map((f) => ({ type: 'Feature', properties: { ...f.properties, ...(f.properties?.COUNTRY ? { NAME_0: f.properties.COUNTRY } : {}) }, geometry: f.geometry, })); // Name correction from parquet const isos = [...new Set(features.map(f => f.properties.GID_0).filter(Boolean))]; if (isos.length > 0) { const completeRows = []; for (const iso of isos) { const nr = await getNames({ admin: iso, contentLevel: resolvedLevel, complete: true }); completeRows.push(...nr.rows); } const gidKey = (row) => { const parts = []; for (let i = 0; i <= resolvedLevel; i++) { parts.push(row[`GID_${i}`] || ''); } return parts.join('|'); }; const nameLookup = new Map(); for (const row of completeRows) { nameLookup.set(gidKey(row), row); } for (const feature of features) { const key = gidKey(feature.properties); const correct = nameLookup.get(key); if (correct) { for (let i = 0; i <= resolvedLevel; i++) { if (correct[`NAME_${i}`]) { feature.properties[`NAME_${i}`] = correct[`NAME_${i}`]; } } } } } // Filter to the requested area const id = name || admin; const colPrefix = name ? 'NAME_' : 'GID_'; const filterCol = `${colPrefix}${level}`; features = features.filter(f => f.properties[filterCol]?.toLowerCase() === id.toLowerCase()); return features; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlbXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlbXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN0QyxPQUFPLEVBQUUsbUJBQW1CLEVBQWtCLE1BQU0sa0JBQWtCLENBQUM7QUFDdkUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLElBQUksQ0FBQztBQUNsQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN4QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXBDLE1BQU0sV0FBVyxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ25ELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQThCeEMsa0NBQWtDO0FBRWxDLE1BQU0sUUFBUSxHQUFHLGlFQUFpRSxDQUFDO0FBRW5GLHFDQUFxQztBQUNyQyxNQUFNLGFBQWEsR0FBNkIsSUFBSSxDQUFDLEtBQUssQ0FDdEQsWUFBWSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsNkJBQTZCLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FDNUUsQ0FBQztBQUVGLHNDQUFzQztBQUV0Qzs7O0dBR0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLFFBQVEsQ0FBQyxJQUFrQjtJQUM3QyxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBRXJELHNCQUFzQjtJQUN0QixJQUFJLEtBQUssR0FBRyxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lB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