{"version":3,"file":"index.mjs","names":[],"sources":["../src/utils/resolve-data-path.ts","../src/utils/cache.ts","../src/utils/criteria-matcher.ts","../src/utils/create-service.ts","../src/services/district.ts","../src/utils/record-to-array.ts","../src/services/postal-code.ts","../src/services/province.ts","../src/services/subdistrict.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Resolves the path to a data file, checking production path first then falling back to development path\n *\n * @param filename - The name of the data file (e.g., \"geo.json\", \"metadata.json\")\n * @param importMetaUrl - The import.meta.url from the calling module\n * @returns The resolved path to the data file\n */\nexport function resolveDataPath(\n  filename: string,\n  importMetaUrl: string,\n): string {\n  const currentDir = dirname(fileURLToPath(importMetaUrl));\n\n  // Find the project root by looking for the src directory\n  // From src/services -> go up 2 levels\n  // From src -> go up 1 level\n  const srcDir = currentDir.includes(\"/services\")\n    ? join(currentDir, \"../..\")\n    : join(currentDir, \"..\");\n\n  const prodPath = join(srcDir, \"dist/data\", filename);\n  const devPath = join(srcDir, \"data/data/v4\", filename);\n\n  return existsSync(prodPath) ? prodPath : devPath;\n}\n","type CacheItem<T> = {\n  value: T;\n  expiry?: number;\n};\n\nclass Cache {\n  private readonly cacheMap: Map<string, CacheItem<unknown>> = new Map();\n  private readonly defaultTTL: number = 60 * 60 * 1000; // 1 hour in milliseconds\n\n  public has(key: string): boolean {\n    const item = this.cacheMap.get(key);\n    if (item) {\n      if (item.expiry && Date.now() > item.expiry) {\n        this.cacheMap.delete(key);\n        return false;\n      }\n      return true;\n    }\n    return false;\n  }\n\n  public get<T>(key: string): T | undefined {\n    if (this.has(key)) {\n      return this.cacheMap.get(key)?.value as T;\n    }\n    return undefined;\n  }\n\n  public set<T>(key: string, value: T, ttl?: number): void {\n    const expiry = Date.now() + (ttl ?? this.defaultTTL);\n    this.cacheMap.set(key, { value, expiry });\n  }\n\n  public clear(): void {\n    this.cacheMap.clear();\n  }\n}\n\nexport const cache = new Cache();\n","/**\n * Checks if an item matches the given search criteria.\n *\n * @param item - The item to check against the criteria\n * @param criterion - The partial object containing the criteria to match\n * @returns True if the item matches all criteria, false otherwise\n */\nexport function matchCriteria<T>(item: T, criterion: Partial<T>): boolean {\n  return Object.entries(criterion).every(([key, value]) => {\n    return item[key as keyof T] === value;\n  });\n}\n","import { matchCriteria } from \"./criteria-matcher\";\n\n/**\n * Creates a service for managing and querying a collection of data items.\n *\n * @param data - The array of data items to manage\n * @param idKey - The key to use as the unique identifier for each item\n * @returns An object with methods to query the data collection\n */\nexport function createService<T>(data: T[], idKey: keyof T) {\n  const dataMap = new Map<number, T>(\n    data.map((item) => [item[idKey] as number, item]),\n  );\n\n  return {\n    getAll: (): T[] => Array.from(dataMap.values()),\n    getByCode: (code: string): T | undefined => dataMap.get(Number(code)),\n    getByCriterion: (criterion: Partial<T>): T[] => {\n      return Array.from(dataMap.values()).filter((item) =>\n        matchCriteria(item, criterion),\n      );\n    },\n  };\n}\n","import { readFileSync } from \"node:fs\";\nimport type { District, DistrictIndex, Province } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst provinces = JSON.parse(\n  readFileSync(resolveDataPath(\"geo.json\", import.meta.url), \"utf-8\"),\n) as Province[];\n\n// Flatten all districts from all provinces\nconst districts: District[] = provinces.flatMap(\n  (province) => province.districts,\n);\n\nexport const createDistrictService = (data: District[]) => {\n  return createService<District>(data, \"code\");\n};\n\nconst districtService = createService<District>(districts, \"code\");\n\n/**\n * Retrieves all districts from the database.\n *\n * @returns An array of all district objects\n */\nexport function getAllDistricts(): District[] {\n  const key = \"districts\";\n  const cached = cache.get<District[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const allDistricts = districtService.getAll();\n  cache.set<District[]>(key, allDistricts);\n  return allDistricts;\n}\n\n/**\n * Retrieves a district by its unique code.\n *\n * @param code - The unique identifier code of the district\n * @returns The district object if found, undefined otherwise\n */\nexport function getDistrictByCode(code: DistrictIndex): District | undefined {\n  const key = `district-${code}`;\n  const cached = cache.get<District>(key);\n  if (cached) {\n    return cached;\n  }\n  const district = districtService.getByCode(code);\n  cache.set(key, district);\n  return district;\n}\n\n/**\n * Retrieves districts that match the specified search criteria.\n *\n * @param criterion - The partial district object containing search criteria\n * @returns An array of districts matching the criteria\n */\nexport function getDistrictsByCriterion(\n  criterion: Partial<District>,\n): District[] {\n  const key = `districts-${JSON.stringify(criterion)}`;\n  const cached = cache.get<District[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const matchedDistricts = districtService.getByCriterion(criterion);\n  cache.set(key, matchedDistricts);\n  return matchedDistricts;\n}\n","/**\n * Converts a record object to an array of its values.\n *\n * @param record - The record object to convert\n * @returns An array containing all values from the record\n */\nexport function recordToArray<K extends string | number | symbol, T>(\n  record: Record<K, T>,\n): T[] {\n  return Object.values(record);\n}\n","import { readFileSync } from \"node:fs\";\nimport type { PostalCode, PostalCodeIndex } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { recordToArray } from \"../utils/record-to-array\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst postalLookup = JSON.parse(\n  readFileSync(resolveDataPath(\"postal_lookup.json\", import.meta.url), \"utf-8\"),\n) as Record<string, PostalCode>;\nconst postalCodes = recordToArray(postalLookup);\n\nexport const createPostalCodeService = (data: PostalCode[]) => {\n  return createService<PostalCode>(data, \"postal_code\");\n};\n\nconst postalCodeService = createService<PostalCode>(postalCodes, \"postal_code\");\n\n/**\n * Retrieves all postal codes from the database.\n *\n * @returns An array of all postal code objects\n */\nexport function getAllPostalCodes(): PostalCode[] {\n  const key = \"postal-codes\";\n  const cached = cache.get<PostalCode[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const allPostalCodes = postalCodeService.getAll();\n  cache.set<PostalCode[]>(key, allPostalCodes);\n  return allPostalCodes;\n}\n\n/**\n * Retrieves a postal code by its unique code.\n *\n * @param code - The unique identifier code of the postal code\n * @returns The postal code object if found, undefined otherwise\n */\nexport function getPostalCode(code: PostalCodeIndex): PostalCode | undefined {\n  const key = `postal-codes-${code}`;\n  const cached = cache.get<PostalCode>(key);\n  if (cached) {\n    return cached;\n  }\n  const postalCode = postalCodeService.getByCode(code);\n  cache.set(key, postalCode);\n  return postalCode;\n}\n","import { readFileSync } from \"node:fs\";\nimport type { Province, ProvinceIndex } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst provinces = JSON.parse(\n  readFileSync(resolveDataPath(\"geo.json\", import.meta.url), \"utf-8\"),\n) as Province[];\n\nexport const createProvinceService = (data: Province[]) => {\n  return createService<Province>(data, \"code\");\n};\n\nconst provinceService = createService<Province>(provinces, \"code\");\n\n/**\n * Retrieves all provinces from the database.\n *\n * @returns An array of all province objects\n */\nexport function getAllProvinces(): Province[] {\n  const key = \"provinces\";\n  const cached = cache.get<Province[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const allProvinces = provinceService.getAll();\n  cache.set<Province[]>(key, allProvinces);\n  return allProvinces;\n}\n\n/**\n * Retrieves a province by its unique code.\n *\n * @param code - The unique identifier code of the province\n * @returns The province object if found, undefined otherwise\n */\nexport function getProvinceByCode(code: ProvinceIndex): Province | undefined {\n  const key = `province-${code}`;\n  const cached = cache.get<Province>(key);\n  if (cached) {\n    return cached;\n  }\n  const province = provinceService.getByCode(code);\n  cache.set(key, province);\n  return province;\n}\n\n/**\n * Retrieves provinces that match the specified search criteria.\n *\n * @param criterion - The partial province object containing search criteria\n * @returns An array of provinces matching the criteria\n */\nexport function getProvincesByCriterion(\n  criterion: Partial<Province>,\n): Province[] {\n  const key = `provinces-${JSON.stringify(criterion)}`;\n  const cached = cache.get<Province[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const matchedProvinces = provinceService.getByCriterion(criterion);\n  cache.set(key, matchedProvinces);\n  return matchedProvinces;\n}\n\n// Export the raw data for other services\nexport { provinces as rawProvinces };\n","import { readFileSync } from \"node:fs\";\nimport type { Province, Subdistrict, SubdistrictIndex } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst provinces = JSON.parse(\n  readFileSync(resolveDataPath(\"geo.json\", import.meta.url), \"utf-8\"),\n) as Province[];\n\n// Flatten all subdistricts from all districts from all provinces\nconst subdistricts: Subdistrict[] = provinces.flatMap((province) =>\n  province.districts.flatMap((district) => district.subdistricts),\n);\n\nexport const createSubdistrictService = (data: Subdistrict[]) => {\n  return createService<Subdistrict>(data, \"code\");\n};\n\nconst subdistrictService = createService<Subdistrict>(subdistricts, \"code\");\n\n/**\n * Retrieves all subdistricts from the database.\n *\n * @returns An array of all subdistrict objects\n */\nexport function getAllSubdistricts(): Subdistrict[] {\n  const key = \"subdistricts\";\n  const cached = cache.get<Subdistrict[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const allSubdistricts = subdistrictService.getAll();\n  cache.set<Subdistrict[]>(key, allSubdistricts);\n  return allSubdistricts;\n}\n\n/**\n * Retrieves a subdistrict by its unique code.\n *\n * @param code - The unique identifier code of the subdistrict\n * @returns The subdistrict object if found, undefined otherwise\n */\nexport function getSubdistrictByCode(\n  code: SubdistrictIndex,\n): Subdistrict | undefined {\n  const key = `subdistrict-${code}`;\n  const cached = cache.get<Subdistrict>(key);\n  if (cached) {\n    return cached;\n  }\n  const subdistrict = subdistrictService.getByCode(code);\n  cache.set(key, subdistrict);\n  return subdistrict;\n}\n\n/**\n * Retrieves subdistricts that match the specified search criteria.\n *\n * @param criterion - The partial subdistrict object containing search criteria\n * @returns An array of subdistricts matching the criteria\n */\nexport function getSubdistrictsByCriterion(\n  criterion: Partial<Subdistrict>,\n): Subdistrict[] {\n  const key = `subdistricts-${JSON.stringify(criterion)}`;\n  const cached = cache.get<Subdistrict[]>(key);\n  if (cached) {\n    return cached;\n  }\n  const matchedSubdistricts = subdistrictService.getByCriterion(criterion);\n  cache.set(key, matchedSubdistricts);\n  return matchedSubdistricts;\n}\n","import { readFileSync } from \"node:fs\";\nimport type { Metadata } from \"./types\";\nimport { resolveDataPath } from \"./utils/resolve-data-path\";\n\nexport * from \"./services/district\";\nexport * from \"./services/postal-code\";\nexport * from \"./services/province\";\nexport * from \"./services/subdistrict\";\nexport * from \"./types\";\nexport * from \"./utils/criteria-matcher\";\n\nconst metaData = JSON.parse(\n  readFileSync(resolveDataPath(\"metadata.json\", import.meta.url), \"utf-8\"),\n) as Metadata;\n\nexport const metadata: Metadata = metaData;\n"],"mappings":"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"}