sri-lanka-police
v1.0.1
Published
API client & CLI for the Sri Lanka Police recruitment portal (joinus.police.lk). Browse provinces, districts, police divisions, divisional secretariats, and police stations.
Maintainers
Readme
Sri Lanka Police — Recruitment Portal API & CLI
Unofficial Node.js API client & CLI for the Sri Lanka Police recruitment portal. Browse the full administrative hierarchy:
Province → District → Police Division / Divisional Secretariat → Police Station
Features
- Interactive CLI — Browse the hierarchy step by step with live progress
- Data Collector — Fetch all data at once across all provinces/districts
- CSV / JSON Export — Save data directly to files for analysis
- Programmatic API — Use the API in your Node.js projects
- Dynamic Sessions — Automatically refreshes cookies & CSRF tokens (no hardcoded tokens)
- Multi-language — Supports Sinhala, Tamil, and English responses
- TypeScript friendly — Type definitions included
Installation
npm install sri-lanka-policeGlobal install (for CLI usage)
npm install -g sri-lanka-policeNow you can run sri-lanka-police or sl-police from anywhere.
CLI Usage — Interactive Wizard
npx sri-lanka-policeNavigate through the hierarchy step by step:
╔══════════════════════════════════════════════════════════════╗
║ Sri Lanka Police — Recruitment Portal CLI ║
║ Province → District → Division / DivSec → Police ║
║ S=Summary C=Divisions P=Police H=Hierarchy E=Export ║
╚══════════════════════════════════════════════════════════════╝
Available Provinces:
1. Western (බස්නාහිර)
2. Central (මධ්යම)
...
0. Exit
──
S. Data Summary (📊)
C. Collect All Divisions
P. Collect All Police Stations
H. Full Hierarchy Tree
E. Export Data to File (CSV/JSON)Interactive letter commands
| Key | Action | Description |
|-----|--------|-------------|
| S | Summary | Show counts for all entity types |
| C | Divisions | Collect all 47 police divisions with progress bar |
| P | Police | Collect all 608 police stations with progress bar |
| H | Hierarchy | Show the complete nested tree |
| E | Export | Interactive export menu (choose type & collect) |
After collecting data via C or P, you'll be asked: "Export this data to file? (y/N)"
CLI Usage — Direct Mode
Quick lookups
# Get districts in a province
npx sri-lanka-police 1
# Get divisions & divsecs for a district
npx sri-lanka-police 1 2
# Get divisions, divsecs & police stations
npx sri-lanka-police 1 2 13Data collector commands
# Quick summary of all data
npx sri-lanka-police --summary
# → 9 provinces, 25 districts, 47 divisions, 338 divsecs, 608 police
# Collect all districts (flat list)
npx sri-lanka-police --collect districts
# Collect all police divisions (flat list with province/district context)
npx sri-lanka-police --collect divisions
# Collect all divisional secretariats
npx sri-lanka-police --collect divsecs
# Collect all police stations (makes ~200 API calls — shows progress)
npx sri-lanka-police --collect police
# Full hierarchy tree (nested by province > district)
npx sri-lanka-police --hierarchyExport commands
# Export all districts to CSV (default format)
npx sri-lanka-police --export districts
# Export police stations to JSON
npx sri-lanka-police --export police --format json
# Export to a custom file path
npx sri-lanka-police --export divisions --format csv --output ./data/divisions.csv
# Export hierarchy (auto-switches to JSON — nested data)
npx sri-lanka-police --export hierarchy
# Export summary as JSON
npx sri-lanka-police --export summary --format jsonExport auto-generates filenames with timestamps:
./sri-lanka-police-police-20260728-023015.csv
| Flag | Description |
|------|-------------|
| --format csv\|json | Output format (default: CSV for flat data, JSON for nested) |
| --output <path> | Custom output file path |
Programmatic API
const police = require('sri-lanka-police');
// Fetch districts in province 1 (Western)
const districts = await police.getDistricts(1);
// Fetch police divisions for district 2
const divisions = await police.getDivisions(2);
// Fetch divisional secretariats for district 2
const divsecs = await police.getDivsecs(2);
// Fetch police stations for division 13
const stations = await police.getPolice(13);API Reference
Individual endpoint functions
getDistricts(provinceId, lang?)
Fetches all districts in a province.
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| provinceId | number \| string | required | Province ID (1–9) |
| lang | string | 'sinhala' | Language: sinhala, tamil, or english |
Returns: Promise<Array<{ id: number, district: string, district_si?: string }>>
getDivisions(districtId, lang?)
Fetches police divisions in a district.
Returns: Promise<Array<{ id: number, division: string, division_si?: string }>>
getDivsecs(districtId, lang?)
Fetches divisional secretariats (DivSec) in a district.
Returns: Promise<Array<{ id: number, divsec: string, divsec_si?: string }>>
getPolice(divisionId, lang?)
Fetches police stations in a police division.
Returns: Promise<Array<{ id: number, police: string, police_si?: string }>>
Language support
// Fetch in Tamil
const districts = await police.getDistricts(1, 'tamil');
// Fetch in English
const districts = await police.getDistricts(1, 'english');Data collector functions
These aggregate functions traverse the full hierarchy to collect all data at once. Progress callbacks are supported for long-running operations.
getAllDistricts()
Fetches ALL districts across all 9 provinces in parallel.
Returns: Promise<Array<{ id, district, district_si, provinceId, provinceName }>>
const allDistricts = await police.getAllDistricts();
console.log(allDistricts.length); // 25
// → [{ id: 1, district: 'කොළඹ', provinceId: 1, provinceName: 'Western (බස්නාහිර)' }, ...]getAllDivisions(opts?)
Fetches ALL police divisions across every district. Each record includes district & province context.
| Option | Type | Description |
|--------|------|-------------|
| onProgress | function | Callback ({ done, total, current }) for live progress |
Returns: Promise<Array<{ id, division, division_si, districtId, districtName, provinceId, provinceName }>>
const divisions = await police.getAllDivisions({
onProgress: ({ done, total, current }) => console.log(`${done}/${total} ${current}`)
});
// → 47 divisions with full contextgetAllDivsecs(opts?)
Fetches ALL divisional secretariats across every district.
Returns: 338 records with district & province context.
getAllPolice(opts?)
Fetches ALL police stations across every division. ⚠ Makes ~200 API calls.
Returns: 608 records with full hierarchy context (division, district, province names).
getFullHierarchy(opts?)
Fetches the COMPLETE administrative hierarchy as a nested tree.
const hierarchy = await police.getFullHierarchy();
// → [{
// provinceId: 1,
// provinceName: 'Western (බස්නාහිර)',
// districts: [{
// id: 1,
// district: 'කොළඹ',
// divisions: [{ id, division, police: [...] }],
// divsecs: [{ id, divsec }]
// }]
// }]getSummary()
Quick statistical summary — counts for every entity type. Data is shared internally (no redundant API calls).
const summary = await police.getSummary();
// → { provinces: 9, districts: 25, divisions: 47, divsecs: 338, police: 608 }startWizard()
Launches the interactive CLI wizard programmatically. Useful if you want to embed the CLI in your own tool.
const { startWizard } = require('sri-lanka-police');
await startWizard();PROVINCES
A lookup object mapping province IDs to names.
console.log(police.PROVINCES[1]);
// → "Western (බස්නාහිර)"Province IDs
| ID | Province | |----|----------| | 1 | Western (බස්නාහිර) | | 2 | Central (මධ්යම) | | 3 | Southern (දකුණු) | | 4 | Northern (උතුරු) | | 5 | Eastern (නැගෙනහිර) | | 6 | North Western (වයඹ) | | 7 | North Central (උතුරු මැද) | | 8 | Uva (ඌව) | | 9 | Sabaragamuwa (සබරගමුව) |
Technical Details
Dynamic Sessions
Cookies and CSRF tokens are no longer hardcoded. On first use, the package scrapes joinus.police.lk/home to obtain fresh credentials:
XSRF-TOKENandlaravel-sessioncookies are extracted fromSet-Cookieheaders- CSRF token is extracted from
<meta name="csrf-token">in the HTML - Sessions automatically refresh on HTTP 419 (CSRF token expired)
Caching
In-memory caches avoid re-fetching data during a session:
- Districts are cached per province
- Divisions are cached per district
- Collector functions share data internally (e.g.,
getSummary()fetches districts once and reuses them)
Project Structure
sri-lanka-police/
├── bin/
│ └── sri-lanka-police.js # CLI binary entry point
├── src/
│ ├── index.js # Programmatic API (main entry)
│ ├── cli.js # Interactive CLI wizard + collector commands
│ ├── collector.js # Aggregate data-collector functions
│ ├── exporter.js # CSV/JSON file export
│ ├── session.js # Dynamic session scraper (cookies + CSRF)
│ ├── police-api.js # Shared HTTP helper with auto-retry
│ ├── get-district.js # Districts endpoint
│ ├── get-division.js # Police divisions endpoint
│ ├── get-divsec.js # Divisional secretariats endpoint
│ └── get-police.js # Police stations endpoint
├── types/
│ └── index.d.ts # TypeScript declarations
├── package.json
├── README.md
└── LICENSELicense
MIT © DEW Coders
