{"version":3,"sources":["../src/loaders.ts","../src/utils.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Dynamic data loaders for @countrystatecity/postalcodes\n * Uses dynamic import() to enable code-splitting and lazy loading\n * Falls back to fs.readFileSync for CommonJS environments\n */\n\nimport type { IPostalCode, IPostalCodeManifestEntry } from './types';\n\n/**\n * Thrown by loadJSON when a data file simply does not exist (every candidate\n * path failed with ENOENT). Loaders translate this into an empty result;\n * every other failure (corrupted JSON, permission errors) propagates.\n */\nclass DataFileNotFoundError extends Error {\n  code = 'MODULE_NOT_FOUND';\n}\n\n// Country dirs are strictly two uppercase letters; state files are short\n// uppercase alphanumerics (the only other file, _unassigned.json, is never\n// caller-addressable). Anything else never touches the filesystem.\nconst COUNTRY_CODE_PATTERN = /^[A-Z]{2}$/;\nconst STATE_CODE_PATTERN = /^[A-Z0-9]{1,10}$/;\n\n/** Uppercase and validate an ISO2 country code; null if not plausibly one. */\nfunction normalizeCountryCode(code: string): string | null {\n  const normalized = String(code).toUpperCase();\n  return COUNTRY_CODE_PATTERN.test(normalized) ? normalized : null;\n}\n\n/** Uppercase and validate a state code; null if not plausibly one. */\nfunction normalizeStateCode(code: string): string | null {\n  const normalized = String(code).toUpperCase();\n  return STATE_CODE_PATTERN.test(normalized) ? normalized : null;\n}\n\n/**\n * Minimal LRU cache over Map insertion order, bounding memory while avoiding\n * a disk read + JSON.parse of multi-MB state files on every call.\n */\nclass LRUCache<V> {\n  private entries = new Map<string, V>();\n  constructor(private maxSize: number) {}\n\n  /** Get a value, marking it most recently used; undefined on miss. */\n  get(key: string): V | undefined {\n    const value = this.entries.get(key);\n    if (value === undefined) return undefined;\n    this.entries.delete(key);\n    this.entries.set(key, value);\n    return value;\n  }\n\n  /** Store a value, evicting the least recently used entry at capacity. */\n  set(key: string, value: V): void {\n    this.entries.delete(key);\n    this.entries.set(key, value);\n    if (this.entries.size > this.maxSize) {\n      this.entries.delete(this.entries.keys().next().value!);\n    }\n  }\n\n  /** Remove all entries. */\n  clear(): void {\n    this.entries.clear();\n  }\n}\n\nlet manifestCache: IPostalCodeManifestEntry[] | null = null;\nconst fileCache = new LRUCache<IPostalCode[]>(50);\n\n/** Return caller-owned postal-code records without exposing cached objects. */\nfunction copyPostalCodes(codes: IPostalCode[]): IPostalCode[] {\n  return codes.map((code) => ({ ...code }));\n}\n\n/** Return caller-owned manifest entries, including their nested state arrays. */\nfunction copyManifest(entries: IPostalCodeManifestEntry[]): IPostalCodeManifestEntry[] {\n  return entries.map((entry) => ({ ...entry, state_codes: [...entry.state_codes] }));\n}\n\n/**\n * Clear all in-memory data caches (manifest and state files).\n * Mainly useful in tests; data only changes between package versions.\n */\nexport function clearCache(): void {\n  manifestCache = null;\n  fileCache.clear();\n}\n\n// Helper to check if we're in a Node.js environment\nfunction isNodeEnvironment(): boolean {\n  return typeof process !== 'undefined' &&\n         process.versions != null &&\n         process.versions.node != null;\n}\n\n// Helper to conditionally import Node.js modules\n// Uses webpack magic comment to prevent bundling in client-side code\nasync function importNodeModule(moduleName: string): Promise<any> {\n  if (!isNodeEnvironment()) {\n    throw new Error(`Module ${moduleName} is not available in browser environment`);\n  }\n\n  // The webpackIgnore magic comment tells webpack to not try to bundle this module\n  // This works because webpack will see it's a runtime variable and skip it\n  switch (moduleName) {\n    case 'fs':\n      return import(/* webpackIgnore: true */ 'fs');\n    case 'path':\n      return import(/* webpackIgnore: true */ 'path');\n    case 'url':\n      return import(/* webpackIgnore: true */ 'url');\n    default:\n      throw new Error(`Unsupported module: ${moduleName}`);\n  }\n}\n\n// Helper function to load JSON data\n//\n// Note: this deliberately does NOT attempt a dynamic `import(path, { assert/with: { type: 'json' } })`\n// before falling back to fs. That pattern is fragile across Node/bundler versions — Node 22+ requires\n// the `with` import attribute (the older `assert` form is rejected), and esbuild has been observed to\n// drop the attributes object entirely for non-literal specifiers, producing a bare `import(path)` that\n// Node then refuses for `.json` files. Since this package is server-side only anyway (browser callers\n// get the friendly error below regardless), reading the file directly via fs is simpler and version-stable.\nasync function loadJSON<T>(path: string): Promise<T> {\n  if (!isNodeEnvironment()) {\n    throw new Error(\n      `@countrystatecity/postalcodes cannot load data in browser environments. ` +\n      `This package is designed for server-side use only. ` +\n      `Please use one of these approaches:\\n` +\n      `1. Create an API endpoint that calls this package on the server\\n` +\n      `2. Generate static JSON at build time\\n` +\n      `3. Use in SSR/SSG context only (e.g., SvelteKit load functions, Next.js server components)\\n` +\n      `See documentation at: https://github.com/dr5hn/countrystatecity-npm/tree/main/packages/postalcodes#readme`\n    );\n  }\n\n  const fs = await importNodeModule('fs');\n  const pathModule = await importNodeModule('path');\n  const { fileURLToPath } = await importNodeModule('url');\n\n  // Resolve path relative to this file\n  let basePath: string;\n  if (typeof __dirname !== 'undefined') {\n    basePath = __dirname;\n  } else {\n    basePath = pathModule.dirname(fileURLToPath(import.meta.url));\n  }\n\n  // Try multiple path resolution strategies for different environments\n  const possiblePaths = [\n    pathModule.join(basePath, path),\n    pathModule.join(basePath, '..', path), // In case dist structure is different\n    pathModule.join(process.cwd(), 'node_modules', '@countrystatecity', 'postalcodes', 'dist', path), // Vercel/serverless\n  ];\n\n  let data: string | null = null;\n  const readErrors: any[] = [];\n\n  for (const fullPath of possiblePaths) {\n    try {\n      data = fs.readFileSync(fullPath, 'utf-8');\n      break;\n    } catch (readError) {\n      readErrors.push(readError);\n      continue;\n    }\n  }\n\n  if (data === null) {\n    // Missing file everywhere -> \"not found\"; anything else (EACCES, EISDIR, ...)\n    // is a real environment problem the caller must see, not an empty result.\n    const realError = readErrors.find((e) => e?.code !== 'ENOENT');\n    if (realError) throw realError;\n    throw new DataFileNotFoundError(\n      `Failed to load JSON file: ${path}. Tried paths: ${possiblePaths.join(', ')}`\n    );\n  }\n\n  return JSON.parse(data);\n}\n\n/**\n * Translate a data-loading failure into an empty result where that is the\n * documented contract (file absent, browser environment), rethrow otherwise.\n */\nfunction handleLoadError(error: unknown): [] {\n  if (error instanceof DataFileNotFoundError) return [];\n  if (error instanceof Error && (error.message.includes('browser') || error.message.includes('Node.js environment'))) {\n    console.warn(`@countrystatecity/postalcodes: ${error.message}`);\n    return [];\n  }\n  throw error;\n}\n\n/**\n * Get the manifest of all countries that have postal code data.\n * Not all 250 countries have postal codes — currently ~125 do.\n * Cached in memory after the first load.\n * @bundle ~21KB - Loads manifest.json\n */\nexport async function getManifest(): Promise<IPostalCodeManifestEntry[]> {\n  if (!manifestCache) {\n    manifestCache = await loadJSON<IPostalCodeManifestEntry[]>('./data/manifest.json');\n  }\n  return copyManifest(manifestCache);\n}\n\n/**\n * Get all postal codes for a specific country + state.\n * @param countryCode - ISO2 country code (e.g., 'US', 'AD')\n * @param stateCode - State code as used by the upstream database\n * @returns Promise with array of postal codes, or empty array if not found\n * @bundle Varies by state — largest known file (Portugal's biggest state) is ~3.2MB\n */\nexport async function getPostalCodesOfState(\n  countryCode: string,\n  stateCode: string\n): Promise<IPostalCode[]> {\n  const country = normalizeCountryCode(countryCode);\n  const state = normalizeStateCode(stateCode);\n  if (!country || !state) return [];\n\n  const key = `${country}/${state}`;\n  const cached = fileCache.get(key);\n  if (cached) return copyPostalCodes(cached);\n\n  try {\n    const data = await loadJSON<IPostalCode[]>(`./data/${country}/${state}.json`);\n    fileCache.set(key, data);\n    return copyPostalCodes(data);\n  } catch (error) {\n    return handleLoadError(error);\n  }\n}\n\n/**\n * Get postal codes that have no state subdivision in the upstream data\n * (small territories/city-states, or a country's non-state-linked subset).\n * @param countryCode - ISO2 country code\n * @returns Promise with array of postal codes, or empty array if none\n */\nexport async function getUnassignedPostalCodesOfCountry(countryCode: string): Promise<IPostalCode[]> {\n  const country = normalizeCountryCode(countryCode);\n  if (!country) return [];\n\n  const key = `${country}/_unassigned`;\n  const cached = fileCache.get(key);\n  if (cached) return copyPostalCodes(cached);\n\n  try {\n    const data = await loadJSON<IPostalCode[]>(`./data/${country}/_unassigned.json`);\n    fileCache.set(key, data);\n    return copyPostalCodes(data);\n  } catch (error) {\n    return handleLoadError(error);\n  }\n}\n\n/**\n * Get ALL postal codes for an entire country: every state file plus the\n * unassigned bucket, concatenated.\n * WARNING: can be large — Portugal alone is ~197K records.\n * @param countryCode - ISO2 country code\n * @returns Promise with array of all postal codes in the country\n */\nexport async function getAllPostalCodesOfCountry(countryCode: string): Promise<IPostalCode[]> {\n  const country = normalizeCountryCode(countryCode);\n  if (!country) return [];\n\n  const manifest = await getManifest();\n  const entry = manifest.find((e) => e.country_code === country);\n  if (!entry) return [];\n\n  const all: IPostalCode[] = [];\n  for (const stateCode of entry.state_codes) {\n    all.push(...(await getPostalCodesOfState(country, stateCode)));\n  }\n  if (entry.has_unassigned) {\n    all.push(...(await getUnassignedPostalCodesOfCountry(country)));\n  }\n  return all;\n}\n","/**\n * Helper utilities for @countrystatecity/postalcodes\n */\n\nimport type { IPostalCode } from './types';\nimport {\n  getManifest,\n  getAllPostalCodesOfCountry,\n  getPostalCodesOfState,\n} from './loaders';\n\n/**\n * Check whether a postal code exists in the dataset for a country.\n *\n * This is an EXISTENCE check, not a format/regex check — the upstream\n * database doesn't expose postal code format patterns through any versioned\n * release asset, only through a mutable, unversioned branch file that this\n * package deliberately avoids depending on. An existence check also catches\n * typos in otherwise-plausible codes that a format regex would miss.\n *\n * @param countryCode - ISO2 country code\n * @param code - The postal code to check\n * @param stateCode - Optional state code to narrow the search (faster)\n */\nexport async function validatePostalCode(\n  countryCode: string,\n  code: string,\n  stateCode?: string\n): Promise<boolean> {\n  const matches = await lookupPostalCode(countryCode, code, stateCode);\n  return matches.length > 0;\n}\n\n/**\n * Look up all records matching an exact postal code.\n * Never assumes uniqueness — the same code can legitimately appear more\n * than once within a country (different localities sharing a code).\n *\n * @param countryCode - ISO2 country code\n * @param code - The postal code to look up\n * @param stateCode - Optional state code to narrow the search (faster)\n */\nexport async function lookupPostalCode(\n  countryCode: string,\n  code: string,\n  stateCode?: string\n): Promise<IPostalCode[]> {\n  const pool = stateCode\n    ? await getPostalCodesOfState(countryCode, stateCode)\n    : await getAllPostalCodesOfCountry(countryCode);\n  return pool.filter((p) => p.code === code);\n}\n\n/**\n * Search postal codes within a country + state by locality name (case-insensitive substring match).\n * There is no city_id linkage in the upstream data, so locality name is the only usable place field.\n */\nexport async function searchPostalCodesByLocality(\n  countryCode: string,\n  stateCode: string,\n  searchTerm: string\n): Promise<IPostalCode[]> {\n  const codes = await getPostalCodesOfState(countryCode, stateCode);\n  const term = searchTerm.toLowerCase();\n  return codes.filter((p) => p.locality_name != null && p.locality_name.toLowerCase().includes(term));\n}\n\n/**\n * Search postal codes across an entire country by locality name (case-insensitive substring match).\n */\nexport async function searchPostalCodesByLocalityInCountry(\n  countryCode: string,\n  searchTerm: string\n): Promise<IPostalCode[]> {\n  const codes = await getAllPostalCodesOfCountry(countryCode);\n  const term = searchTerm.toLowerCase();\n  return codes.filter((p) => p.locality_name != null && p.locality_name.toLowerCase().includes(term));\n}\n\n/**\n * Get the list of country codes that have postal code data.\n * Not all countries do — currently ~125 of 250.\n */\nexport async function getSupportedCountryCodes(): Promise<string[]> {\n  const manifest = await getManifest();\n  return manifest.map((e) => e.country_code);\n}\n\n/**\n * Check whether a country has any postal code data.\n */\nexport async function isCountrySupported(countryCode: string): Promise<boolean> {\n  const codes = await getSupportedCountryCodes();\n  return codes.includes(countryCode);\n}\n"]}