npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@classytic/bd-areas

v1.1.0

Published

Bangladesh delivery areas with multi-provider support (RedX, Pathao, Steadfast) - 8 divisions, 64 districts, 2836+ areas

Downloads

209

Readme

@classytic/bd-areas

Bangladesh delivery taxonomy as static data — zero network, zero API calls. Two entry points:

  • @classytic/bd-areas — unified shape (8 divisions, 64 districts, 2,836 areas with RedX IDs). Best for cascading address dropdowns built around the RedX area model.
  • @classytic/bd-areas/pathao — Pathao-native taxonomy (64 cities, 1,258 zones). Best for Pathao-only flows (cascading dropdowns, CSV exports). ~80 KB instead of ~400 KB.

Both subpaths are independent — import only the one your UI needs and tree-shaking does the rest.

Install

npm install @classytic/bd-areas

Subpath: @classytic/bd-areas (unified)

Used by RedX flows. Area records have a providers.redx numeric ID for every entry; providers.pathao and providers.steadfast are mostly empty (Pathao IDs don't fit the unified Area model — see the /pathao subpath instead).

import {
  getDivisions, getDistrictsByDivision, getAreasByDistrict,
  getArea, searchAreas, resolveArea,
} from '@classytic/bd-areas';

const divisions = getDivisions();              // 8 entries
const districts = getDistrictsByDivision('dhaka');
const areas = getAreasByDistrict('dhaka');     // [{ internalId, name, providers: { redx }, ... }]
const area = getArea(1206);                    // by internalId
const matches = searchAreas('mirpur');         // free-text, default limit 20
const full = resolveArea(1206);                // adds full division + district objects

API summary

| Function | Purpose | |---|---| | getDivisions() / getDivisionById(id) / getDivisionByName(name) | 8 BD divisions | | getDistrictsByDivision(divisionId) / getDistrictById(id) / getAllDistricts() | 64 districts | | getArea(internalId) / getAllAreas() | 2,836 areas | | getAreasByDistrict(id) / getAreasByDivision(id) / getAreasByPostCode(code) | filters | | searchAreas(query, limit?) | free-text autocomplete | | getAreaByProvider('redx', id) | inverse lookup | | convertProviderId('redx', id, 'pathao') | cross-provider (Pathao mostly null today) | | resolveArea(internalId) | area + full division + district | | getStats() | dataset coverage report |

Types

interface Area {
  internalId: number;       // store this in your DB
  name: string;
  postCode: number | null;
  zoneId: number;            // internal zone (1-6) for tier pricing
  districtId: string;
  districtName: string;
  divisionId: string;
  divisionName: string;
  providers: { redx?: number; pathao?: number; steadfast?: number };
}

Subpath: @classytic/bd-areas/pathao (Pathao-native)

A static snapshot of merchant.pathao.com — exactly the data the Pathao web UI uses to populate its own dropdowns. Use this for any Pathao flow:

  • Cascading city → zone dropdowns in checkout / address forms
  • CSV bulk-upload exports (Pathao's CSV uses city + zone names, not IDs)
  • Validating recipient city/zone before calling the Pathao API
import {
  PATHAO_CITIES,           // PathaoCity[] — alphabetical, all 64 cities
  PATHAO_ZONES_BY_CITY,    // Record<cityId, PathaoZone[]>
  findCity,                // by cityId
  findCityByName,          // case-insensitive, falls back to substring
  getZonesByCity,          // PathaoZone[] for a city
  findZone,                // (cityId, zoneId)
  findZoneByName,          // (cityId, name)
  searchZones,             // cross-city zone search, returns { ...zone, city }
  getPathaoStats,          // diagnostic counts per city
} from '@classytic/bd-areas/pathao';

// Cascading dropdown
const [cityId, setCityId] = useState<number>();
const zones = cityId ? getZonesByCity(cityId) : [];

// CSV row from address-with-IDs
const city = findCity(addr.cityId);
const zone = city ? findZone(city.cityId, addr.zoneId) : undefined;
csv.push({ RecipientCity: city?.cityName, RecipientZone: zone?.zoneName });

Why a separate subpath?

  • Granularity mismatch. Pathao zones are landmark/neighborhood-level (Gulshan, Banani) — they don't map 1:1 to the unified Area shape (which is thana-level). Forcing them into one shape loses information.
  • Bundle weight. A Pathao-only checkout shouldn't ship 2,836 RedX areas (~400 KB unified) — the /pathao subpath is ~80 KB.
  • Update cadence. Pathao adds zones every few months; refreshing this subpath doesn't require touching the unified dataset.

Refresh: snapshot script

The /pathao data is regenerated by scripts/snapshot-pathao-merchant.mjs. Pathao changes infrequently — run this manually every few months and republish.

# 1. Get a fresh JWT from https://merchant.pathao.com (DevTools → any
#    address-search request → copy `Authorization: Bearer <token>`)
# 2. Set in .env:
PATHAO_MERCHANT_TOKEN=<that token>

# 3. Run (resumable, hard-fails on rate limit, ~3 min):
node scripts/snapshot-pathao-merchant.mjs

# 4. Commit src/pathao/cities.ts + src/pathao/zones.ts + bump version.

The snapshot writes after every city, so a mid-run rate-limit just resumes from _progress.json on the next run. Pass PATHAO_SNAPSHOT_MAX_CITIES=10 for a smoke run.


Tests

Three tiers per testing-infrastructure.md. Single vitest.config.ts with projects: [unit, integration, e2e].

| Command | What runs | |---|---| | npm test | unit + integration (default) — pure data assertions + cross-package shape tests | | npm run test:unit | dataset shape, helpers | | npm run test:integration | uses real RedXAdapter + composite resolver via mocked fetch — proves the dataset is shaped correctly for @classytic/carrier-bd | | npm run test:e2e | env-gated live Pathao audit — reports drift between bd-areas and the live merchant API |

tests/unit and tests/integration MUST stay network-free.


Best practices

Storing addresses

// Unified (RedX) — store internalId
await saveAddress({ areaId: area.internalId, areaName: area.name, ... });

// Pathao — store cityId + zoneId
await saveAddress({ pathaoCityId: city.cityId, pathaoZoneId: zone.zoneId, ... });

Calling carrier APIs (via @classytic/carrier-bd)

import { getArea } from '@classytic/bd-areas';
import { findZone } from '@classytic/bd-areas/pathao';

// RedX
const area = getArea(savedAddress.areaId);
await redxAdapter.buyLabel({ destination, packages, metadata: {
  deliveryAreaId: area.providers.redx,
  deliveryAreaName: area.name,
} }, ctx);

// Pathao
await pathaoAdapter.buyLabel({ destination, packages, metadata: {
  deliveryCityId: savedAddress.pathaoCityId,
  deliveryZoneId: savedAddress.pathaoZoneId,
} }, ctx);

License

MIT © Classytic