{"id":48889490,"url":"https://github.com/disocy/disocy-geo","last_synced_at":"2026-05-17T08:08:38.356Z","repository":{"id":351133488,"uuid":"1209708359","full_name":"disocy/disocy-geo","owner":"disocy","description":"Disocy Geo is a domain-driven geo intelligence library for countries, subdivisions, localities, addressing, shipping, and operational metadata, built to power structured product workflows with normalized, searchable geographic data.","archived":false,"fork":false,"pushed_at":"2026-05-14T06:35:44.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-14T08:39:27.020Z","etag":null,"topics":["geo","geojson","geolocation","geolocation-api"],"latest_commit_sha":null,"homepage":"https://disocy.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/disocy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-13T17:46:25.000Z","updated_at":"2026-04-13T20:18:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/disocy/disocy-geo","commit_stats":null,"previous_names":["disocy/disocy-geo"],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/disocy/disocy-geo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/disocy%2Fdisocy-geo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/disocy%2Fdisocy-geo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/disocy%2Fdisocy-geo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/disocy%2Fdisocy-geo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/disocy","download_url":"https://codeload.github.com/disocy/disocy-geo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/disocy%2Fdisocy-geo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33131452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T06:27:06.342Z","status":"ssl_error","status_checked_at":"2026-05-17T06:26:59.432Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["geo","geojson","geolocation","geolocation-api"],"created_at":"2026-04-16T07:03:47.382Z","updated_at":"2026-05-17T08:08:38.313Z","avatar_url":"https://github.com/disocy.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @disocy/geo\n\nDisocy geographic intelligence library for normalized country, subdivision, locality, addressing, compliance, metadata, and search workflows.\n\nThis package is intended to be the geo source of truth for the platform:\n\n- Countries, ISO codes, and UN M49 data\n- Subdivisions and locality shards\n- Search by normalized place name\n- Country operational metadata for addressing and shipping\n- Customs and trade-region slices\n- Metadata such as capital, currency, languages, TLD, and timezones\n\n## Scope\n\n`@disocy/geo` is split into domain-oriented public entrypoints:\n\n- `@disocy/geo/core`\n- `@disocy/geo/addressing`\n- `@disocy/geo/compliance`\n- `@disocy/geo/metadata`\n- `@disocy/geo/search`\n- `@disocy/geo/populate`\n\nThe default root export re-exports the most useful runtime APIs.\n\n## Package Layout\n\n```text\nlib/@disocy/geo/\n  src/\n    core/\n    addressing/\n    compliance/\n    metadata/\n    search/\n    runtime/\n    populate/\n    build/\n    scripts/\n    sources/ (ignored, normalized backups)\n  dist/ (ignored, deployed to GitHub Pages)\n    core/\n      countries.json\n      subdivisions-by-country/\n        ES.json\n        US.json\n      localities/\n        manifest.json\n        by-country-state/\n          ES/51.json\n          ES/52.json\n          US/CA.json\n    addressing/\n      country-operational/\n        ES.json\n        US.json\n    compliance/\n      customs/\n        ES.json\n      trade-regions/\n        ES.json\n    metadata/\n      countries/\n        ES.json\n        AE.json\n```\n\n## Dist Design\n\nThe generated `dist/` is organized by domain and country shard to minimize runtime overhead:\n\n- `dist/core/countries.json`\n  Canonical country catalog.\n- `dist/core/subdivisions-by-country/{COUNTRY}.json`\n  Only loads subdivisions for the requested country.\n- `dist/core/localities/manifest.json`\n  Lists available locality shards.\n- `dist/core/localities/by-country-state/{COUNTRY}/{SUBDIVISION}.json`\n  Loads one locality shard at a time.\n- `dist/addressing/country-operational/{COUNTRY}.json`\n  Addressing and shipping metadata for one country.\n- `dist/compliance/customs/{COUNTRY}.json`\n  Customs-focused compliance slice.\n- `dist/compliance/trade-regions/{COUNTRY}.json`\n  Trade-region slice for one country.\n- `dist/metadata/countries/{COUNTRY}.json`\n  Country metadata such as currency, languages, capital, TLD, and timezones.\n\nThis keeps runtime reads narrow and predictable instead of loading giant global JSON blobs.\n\n## GitHub Pages As Dataset API\n\nThis repository keeps code in Git while publishing the generated dataset to GitHub Pages as static JSON shards.\n\nThe intended flow is:\n\n1. GitHub Actions checks upstream GeoNames and UN sources every day.\n2. If upstream changed, the workflow runs `populate:data`.\n3. The workflow builds `dist/`.\n4. The workflow deploys `dist/` to GitHub Pages.\n5. Runtime consumers fetch only the shards they need over HTTPS.\n\nThis avoids committing multi-gigabyte generated artifacts into Git while also avoiding local dataset installs in consumer apps.\n\n### Daily Refresh Workflow\n\nThe workflow lives in `.github/workflows/refresh-geo-dataset.yml`.\n\nIt:\n\n- runs daily on a cron schedule\n- checks upstream headers through `.github/scripts/check-geo-sources.mjs`\n- skips the expensive rebuild when sources did not change\n- deploys the refreshed `dist/` to GitHub Pages when they did\n\n### Runtime Base URL\n\nThe runtime uses GitHub Pages directly:\n\n```txt\nhttps://disocy.github.io/disocy-geo/\n```\n\nExamples:\n\n- `https://disocy.github.io/disocy-geo/core/countries.json`\n- `https://disocy.github.io/disocy-geo/core/subdivisions-by-country/ES.json`\n- `https://disocy.github.io/disocy-geo/core/localities/by-country-state/ES/51.json`\n- `https://disocy.github.io/disocy-geo/addressing/postal-codes/ES.json`\n\nAll public data access APIs are asynchronous because they fetch remote shards.\n\n## Public API\n\n### Root\n\n```js\nimport {\n  getCountry,\n  listSubdivisions,\n  findCityByName,\n  getCityDetails,\n  getCountryOperationalMetadata,\n  getCountryMetadata,\n} from \"@disocy/geo\";\n\nconst country = await getCountry(\"ES\");\nconst subdivisions = await listSubdivisions(\"ES\");\n```\n\n### Core\n\n```js\nimport {\n  listCountries,\n  getCountry,\n  listSubdivisions,\n  getSubdivision,\n  listCityShards,\n  listCitiesBySubdivision,\n  findCityByGeonameId,\n  findCityByName,\n  getCityDetails,\n} from \"@disocy/geo/core\";\n\nconst countries = await listCountries();\nconst city = await getCityDetails({ name: \"Jatar\", countryCode: \"ES\" });\n```\n\n### Addressing\n\n```js\nimport {\n  getShippingProfile,\n  getCountryOperationalMetadata,\n} from \"@disocy/geo/addressing\";\n\nconst shipping = await getCountryOperationalMetadata(\"ES\");\n```\n\n### Compliance\n\n```js\nimport {\n  getCustomsMetadata,\n  getTradeRegionMetadata,\n} from \"@disocy/geo/compliance\";\n\nconst customs = await getCustomsMetadata(\"ES\");\n```\n\n### Metadata\n\n```js\nimport {\n  getPhoneMetadata,\n  getCountryMetadata,\n  listCountryMetadata,\n} from \"@disocy/geo/metadata\";\n\nconst metadata = await getCountryMetadata(\"ES\");\n```\n\n### Search\n\n```js\nimport {\n  normalizePlaceName,\n  searchCities,\n  findCityByName,\n  getCityDetails,\n} from \"@disocy/geo/search\";\n\nconst cities = await searchCities(\"Jatar\", { countryCode: \"ES\" });\n```\n\n## Main Runtime Entities\n\n### Country\n\nCountry records include:\n\n- `code`\n- `iso3`\n- `m49`\n- `name`\n- `continent`\n- `continentCode`\n- `region`\n- `subregion`\n- `capital`\n- `currencyCode`\n- `currencyName`\n- `tld`\n- `languages`\n\n### Subdivision\n\nSubdivision records include:\n\n- `code`\n- `countryCode`\n- `name`\n- `type`\n\n### Locality\n\nLocality records include:\n\n- `geonameId`\n- `name`\n- `asciiName`\n- `countryCode`\n- `subdivisionCode`\n- `admin1Code`\n- `admin2Code`\n- `population`\n- `lat`\n- `lng`\n- `timezone`\n\n### Country Operational Metadata\n\nCountry operational metadata includes:\n\n- `countryCode`\n- `customsRegion`\n- `locodeCountryCode`\n- `phonePrefix`\n- `postalCodeFormat`\n- `postalCodeRegex`\n- `requiresSubdivisionForShipping`\n\n## Usage Examples\n\n### Country + Subdivisions\n\n```js\nimport { getCountry, listSubdivisions } from \"@disocy/geo/core\";\n\nconst spain = getCountry(\"ES\");\nconst spainSubdivisions = listSubdivisions(\"ES\");\n```\n\n### Search A Place By Name\n\n```js\nimport { findCityByName } from \"@disocy/geo/search\";\n\nconst jatar = findCityByName(\"Játar\", {\n  countryCode: \"ES\",\n});\n```\n\n### Get Maximum City Detail\n\n```js\nimport { getCityDetails } from \"@disocy/geo/search\";\n\nconst details = getCityDetails({\n  name: \"Játar\",\n  countryCode: \"ES\",\n});\n\nconsole.log(details);\n```\n\nReturned shape:\n\n- `city`\n- `country`\n- `subdivision`\n- `shipping`\n- `continent`\n- `region`\n- `subregion`\n\n### Addressing / Shipping Metadata\n\n```js\nimport { getCountryOperationalMetadata } from \"@disocy/geo/addressing\";\n\nconst esOperational = getCountryOperationalMetadata(\"ES\");\n```\n\n### Metadata Slice\n\n```js\nimport { getCountryMetadata, getPhoneMetadata } from \"@disocy/geo/metadata\";\n\nconst esMetadata = getCountryMetadata(\"ES\");\nconst esPhone = getPhoneMetadata(\"ES\");\n```\n\n### Customs Slice\n\n```js\nimport { getCustomsMetadata } from \"@disocy/geo/compliance\";\n\nconst esCustoms = getCustomsMetadata(\"ES\");\n```\n\n## Search Behavior\n\nSearch is normalized with accent stripping and case folding.\n\nExamples:\n\n- `Játar` -\u003e `jatar`\n- `Los Ángeles` -\u003e `los angeles`\n\nThe search layer currently supports:\n\n- normalized name search\n- exact and non-exact matching\n- country filtering\n- subdivision filtering\n- match ranking plus population bias\n\n## Populate Pipeline\n\nRun the full ingestion pipeline:\n\n```bash\npnpm run populate:data\n```\n\nThe populate pipeline:\n\n1. Downloads upstream providers\n2. Normalizes country, subdivision, locality, and operational metadata\n3. Rebuilds the domain-oriented `dist/`\n\nOptional source override variables for maintainers:\n\n```bash\nDISOCY_GEO_UN_M49_URL=\nDISOCY_GEO_ISO_COUNTRIES_URL=\nDISOCY_GEO_ISO_SUBDIVISIONS_URL=\nDISOCY_GEO_ADMIN2_SUBDIVISIONS_URL=\nDISOCY_GEO_GEONAMES_CITIES_URL=\nDISOCY_GEO_GEONAMES_POSTAL_CODES_URL=\nDISOCY_GEO_GEONAMES_ALTERNATE_NAMES_BASE_URL=\nDISOCY_GEO_SHIPPING_URL=\n```\n\nThese are only intended for source maintenance, mirrors, or debugging the ingest pipeline. Consumer apps do not need to set any geo-specific environment variables.\n\n## Build Dist From Existing Source Snapshots\n\n```bash\npnpm run build:data\n```\n\nThis rebuilds `dist/` from the normalized snapshots under `src/sources/*`.\n\n## Test\n\n```bash\npnpm test\n```\n\n## Source Inputs\n\nCurrent upstream model:\n\n- `UN M49`\n  Continent, region, subregion, numeric country codes\n- `GeoNames countryInfo.txt`\n  Country codes, ISO3, capital, TLD, currency, phone prefix, postal fields, languages\n- `GeoNames admin1Codes.txt` (UTF-8 names)\n  Primary subdivision catalog\n- `GeoNames admin2Codes.txt`\n  Secondary subdivision catalog\n- `GeoNames allCountries.zip`\n  Localities, coordinates, population, admin hierarchy, timezone\n- optional curated shipping input\n  Explicit overrides for operational metadata when needed\n\nIf no external shipping payload is provided, shipping metadata is derived from country metadata plus subdivision presence.\n\n## Current Notes\n\n- Runtime fetches shards via HTTPS natively, meaning it is Edge, Serverless (Vercel), and Browser compatible without relying on local disks.\n- `dist/` and `src/sources/*` are ignored in git and published exclusively to GitHub Pages to prevent blowing past Vercel payload limits or bloating the NPM package with hundreds of megabytes of JSON.\n- Large locality imports are handled through shard-oriented processing to avoid giant in-memory JSON objects.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdisocy%2Fdisocy-geo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdisocy%2Fdisocy-geo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdisocy%2Fdisocy-geo/lists"}