era-phone-validator
v1.0.2
Published
Validator, parser, formatter, generator, dan detector nomor telepon Indonesia (operator/brand/network/lokasi). TypeScript-first, zero dependencies, dual ESM+CJS, tree-shakeable.
Maintainers
Readme
era-phone-validator
Cek, parse, format, generate, sampai deteksi operator nomor HP Indonesia — semua dalam satu library. TypeScript-first, tanpa dependency, ringan, dan gampang dipakai.
npm install era-phone-validatorNggak perlu database, nggak perlu API call, nggak perlu file aneh-aneh. Install, import, langsung gas.
Daftar Isi
- Kenapa pakai ini?
- Install
- Langsung Gas (Quick Start)
- Anatomi Nomor HP Indonesia
- Daftar Fungsi
- Tipe Data
- Format Input yang Diterima
- Aturan Validasi & Pesan Error
- Ngurusin Error
- Operator & Prefix
- Import Hemat (Tree-shaking)
- Contoh di Next.js & Tempat Lain
- Tanya Jawab (FAQ)
- Kompatibilitas
- Buat Ngoprek Sendiri
- Mau Nyumbang? (Kontribusi)
- Changelog
- Lisensi
Kenapa pakai ini?
- Cek format — beneran nomor HP apa cuma typo? Ketahuan.
- Bongkar komponen — ambil operator, brand, prefix, dan segala format sekaligus.
- Ubah format — mau E.164, internasional, lokal, atau polosan? Bebas.
- Bikin nomor — butuh nomor buat testing atau seeding? Tinggal generate.
- Deteksi operator — Telkomsel? XLSMART? Indosat? Langsung kebaca.
- Data operator terbaru — 42 prefix aktif, udah ngikutin merger XLSMART (Mei 2025).
- Aman buat TypeScript — auto-complete jalan, tipe ketat, hasil bisa di-narrow pakai
result.valid. - Error bahasa Indonesia — pesannya kebaca, nggak bikin bingung user.
- Ringan banget — zero dependency, tree-shakeable, aman buat browser & server.
- Dual ESM + CJS — mau import modern atau require jadul, dua-duanya jalan.
Install
npm install era-phone-validator
# atau
yarn add era-phone-validator
# atau
pnpm add era-phone-validatorPakai ES Module / TypeScript:
import { validatePhone, parsePhone } from "era-phone-validator";Pakai CommonJS:
const { validatePhone, parsePhone } = require("era-phone-validator");Langsung Gas (Quick Start)
import {
validatePhone,
parsePhone,
formatPhone,
generatePhone,
detectProvider,
getProviderDetails,
} from "era-phone-validator";
// 1. Valid nggak nih nomornya?
validatePhone("081234567890"); // { valid: true }
// 2. Bongkar semua isinya
const parsed = parsePhone("081234567890");
if (parsed.valid) {
parsed.operator; // "Telkomsel"
parsed.brand; // "simPATI"
parsed.e164; // "+6281234567890"
parsed.domestic; // "0812-3456-7890"
}
// 3. Ubah ke format lain
formatPhone("0812-3456-7890", "e164"); // "+6281234567890"
// 4. Bikin nomor buat testing
generatePhone({ operator: "Telkomsel" }); // "0812xxxxxxxx"
// 5. Operator apa nih?
detectProvider("088112345678"); // "XLSMART"
// 6. Mau info lengkap? Sekali tembak
getProviderDetails("081234567890");
// {
// provider: "Telkomsel",
// brand: "simPATI",
// network: "GSM",
// type: "mobile",
// prefix: "0812",
// location: "Nasional",
// locationDetail: "Cakupan Telkomsel (portabel/nasional)"
// }Anatomi Nomor HP Indonesia
Nomor HP kita bentuknya gini: 08XX-XXXX-XXXX
0812 3456 7890
│ └──────── Nomor pelanggan
└───────────── Prefix operator (4 digit: 0 + 8 + 2 digit valid)| Bagian | Penjelasan |
| ---------------------- | ----------------------------------- |
| Kode negara | +62 |
| Trunk prefix | 0 |
| Penanda seluler | 8 (habis angka 0) |
| Digit ke-3 | 1,2,3,5,6,7,8,9 (bukan 0 / 4) |
| Total digit (lokal) | 10–13 digit |
Daftar Fungsi
Sekilas semua fungsinya:
| Fungsi | Balikin | Bisa error? | Buat apa |
| --------------------- | ----------------------------- | ----------- | ------------------------------------- |
| validatePhone | ValidationResult | Nggak | Cek valid, kasih tau alasannya |
| isValidPhone | boolean | Nggak | Cek valid, langsung true/false |
| parsePhone | PhoneResult | Nggak | Bongkar ke semua komponen |
| formatPhone | string | Iya | Ubah ke format tertentu |
| generatePhone | string | Iya | Bikin nomor valid |
| detectProvider | string | Nggak | Nama operator |
| detectBrand | string | Nggak | Nama brand |
| detectNetwork | NetworkType \| undefined | Nggak | Tipe jaringan |
| detectLocation | LocationResult \| string | Nggak | Cakupan operator |
| getProviderDetails | DetectionResult \| string | Nggak | Semua info operator |
| getOperator | Operator \| undefined | Nggak | Cari operator dari prefix |
| getOperators | [string, Operator][] | Nggak | Semua data operator |
| getPrefixesByOperator | string[] | Nggak | Semua prefix punya operator |
| getOperatorNames | string[] | Nggak | Daftar nama operator |
| isKnownPrefix | boolean | Nggak | Prefix ini kedaftar nggak |
validatePhone — cek valid atau nggak
Ngecek format nomor step-by-step (berhenti di error pertama). Nggak pernah error, selalu balikin objek.
import { validatePhone } from "era-phone-validator";
// atau: import { validatePhone } from "era-phone-validator/validate";
validatePhone("081234567890"); // { valid: true }
validatePhone("+62 812-3456-7890"); // { valid: true }
validatePhone("812-3456-7890"); // { valid: true }
validatePhone("bukan-nomor"); // { valid: false, error: "Nomor telepon hanya boleh berisi angka" }Enaknya, hasilnya bisa di-narrow otomatis sama TypeScript:
const r = validatePhone(input);
if (r.valid) {
// aman, ini pasti valid
} else {
console.error(r.error); // ada pesan errornya
}isValidPhone — versi buru-buru
Kalau cuma butuh true/false, pakai ini aja. Pas banget buat filter.
import { isValidPhone } from "era-phone-validator";
isValidPhone("081234567890"); // true
isValidPhone("bukan"); // false
["081234567890", "abc", "085512345678"].filter(isValidPhone);
// ["081234567890", "085512345678"]parsePhone — bongkar semua komponen
Pecah nomor jadi semua bagiannya. Nggak error, kalau invalid ya balikin { valid: false, error }.
import { parsePhone } from "era-phone-validator";
// atau: import { parsePhone } from "era-phone-validator/parse";
const r = parsePhone("+62 812-3456-7890");
if (r.valid) {
r.number; // "081234567890"
r.e164; // "+6281234567890"
r.international; // "+62 812 3456 7890"
r.domestic; // "0812-3456-7890"
r.compact; // "081234567890"
r.countryCode; // "62"
r.prefix; // "0812"
r.operator; // "Telkomsel"
r.brand; // "simPATI"
r.network; // "GSM"
r.networkType; // "mobile"
}Kalau formatnya bener tapi prefix-nya belum kedaftar, tetep dianggap
valid: truekok. Cumaoperator/brand-nya jadi"Tidak diketahui".
formatPhone — ubah ke format lain
Ubah nomor ke format yang kamu mau. Awas, ini bisa throw Error kalau nomornya invalid (pesannya bahasa Indonesia).
import { formatPhone } from "era-phone-validator";
// atau: import { formatPhone } from "era-phone-validator/format";
formatPhone("081234567890", "e164"); // "+6281234567890"
formatPhone("081234567890", "international"); // "+62 812 3456 7890"
formatPhone("081234567890", "domestic"); // "0812-3456-7890"
formatPhone("081234567890", "compact"); // "081234567890"| Format | Hasilnya |
| --------------- | ------------------- |
| e164 | +6281234567890 |
| international | +62 812 3456 7890 |
| domestic | 0812-3456-7890 |
| compact | 081234567890 |
generatePhone — bikin nomor buat testing
Butuh nomor palsu tapi valid buat testing atau seeding? Nih. Bisa throw Error kalau operator/prefix-nya nggak dikenal.
import { generatePhone } from "era-phone-validator";
// atau: import { generatePhone } from "era-phone-validator/generate";
generatePhone(); // random bebas
generatePhone({ operator: "Telkomsel" }); // random tapi Telkomsel
generatePhone({ operator: "XLSMART" });
generatePhone({ prefix: "0812" }); // prefix spesifik
generatePhone({ format: "e164" }); // "+62812xxxxxxx"
generatePhone({ format: "international" }); // "+62 812 xxxx xxxx"
generatePhone({ format: "domestic" }); // "0812-xxxx-xxxx"
generatePhone({ operator: "Telkomsel", format: "e164" });| Opsi | Tipe | Default | Keterangan |
| ---------- | -------------- | ----------- | --------------------------------- |
| operator | string | random | Nama operator (nggak case-sensitive) |
| prefix | string | random | Prefix 4 digit spesifik |
| format | PhoneFormat | "compact" | Format output |
Kalau
prefixdanoperatordikasih dua-duanya, yang dipakaiprefix.
detectProvider & kawan-kawan
import {
detectProvider,
detectBrand,
detectNetwork,
detectLocation,
} from "era-phone-validator";
// atau: import { ... } from "era-phone-validator/detect";
detectProvider("081234567890"); // "Telkomsel"
detectProvider("088112345678"); // "XLSMART"
detectProvider("089512345678"); // "Indosat Ooredoo Hutchison"
detectProvider("bukan"); // "Nomor telepon tidak valid"
detectBrand("083112345678"); // "Axis"
detectNetwork("086812345678"); // "satellite"
detectLocation("081234567890");
// { location: "Nasional", locationDetail: "Cakupan Telkomsel (portabel/nasional)" }Soal lokasi, jujur ya: nomor HP Indonesia itu bisa pindah operator tanpa ganti nomor (MNP), jadi nggak bisa nentuin kota asli pemiliknya cuma dari prefix. Makanya fungsi lokasi cuma balikin cakupan operator (nasional), bukan kota. Biar nggak nyesatin.
getProviderDetails — info lengkap sekali tembak
import { getProviderDetails } from "era-phone-validator";
const d = getProviderDetails("081234567890");
if (typeof d !== "string") {
d.provider; // "Telkomsel"
d.brand; // "simPATI"
d.network; // "GSM"
d.type; // "mobile"
d.prefix; // "0812"
d.location; // "Nasional"
d.locationDetail; // "Cakupan Telkomsel (portabel/nasional)"
}Database Operator
Butuh data mentahnya? Ambil sepuasnya.
import {
OPERATOR_MAP,
getOperator,
getOperators,
getPrefixesByOperator,
getOperatorNames,
isKnownPrefix,
} from "era-phone-validator";
// atau: import { ... } from "era-phone-validator/operators";
getOperator("0812");
// { name: "Telkomsel", brand: "simPATI", network: "GSM", type: "mobile" }
getOperator("9999"); // undefined
getPrefixesByOperator("Telkomsel");
// ["0811", "0812", "0813", "0821", "0822", "0823", "0851", "0852", "0853"]
getOperators(); // [["0811", {...}], ["0812", {...}], ...] (42 entri)
getOperatorNames(); // ["Indosat Ooredoo Hutchison", "PSN", "Telkomsel", "XLSMART"]
isKnownPrefix("0812"); // trueTipe Data
import type {
NetworkType,
NumberType,
PhoneFormat,
Operator,
ValidationResult,
PhoneResult,
GenerateOptions,
DetectionResult,
LocationResult,
} from "era-phone-validator";
// atau tipe intinya dari: "era-phone-validator/types"type NetworkType = "GSM" | "CDMA" | "satellite";
type NumberType = "mobile" | "satellite";
type PhoneFormat = "e164" | "international" | "domestic" | "compact";
interface Operator {
name: string;
brand: string;
network: NetworkType;
type: NumberType;
}
type ValidationResult = { valid: true } | { valid: false; error: string };
interface PhoneValid {
valid: true;
number: string;
e164: string;
international: string;
domestic: string;
compact: string;
countryCode: string;
prefix: string;
operator: string;
brand: string;
network: NetworkType;
networkType: NumberType;
}
type PhoneResult = PhoneValid | { valid: false; error: string };
interface GenerateOptions {
operator?: string;
prefix?: string;
format?: PhoneFormat;
}
interface DetectionResult {
provider: string;
brand: string;
network: NetworkType;
type: NumberType;
prefix: string;
location?: string;
locationDetail?: string;
}
interface LocationResult {
location?: string;
locationDetail?: string;
}Format Input yang Diterima
Tenang, formatnya fleksibel. Semua ini kebaca:
| Format | Contoh |
| ----------------------- | ---------------------------------------------------- |
| Lokal | 081234567890 |
| Pakai pemisah | 0812-3456-7890, 0812 3456 7890, 0812.3456.7890 |
| E.164 | +6281234567890 |
| Internasional tanpa + | 6281234567890 |
| Tanpa angka 0 depan | 81234567890 |
Pemisah yang otomatis dibersihin: spasi, strip (-), titik (.), dan kurung.
Aturan Validasi & Pesan Error
Ngeceknya urut, berhenti di error pertama. Ini urutannya:
| # | Yang dicek | Pesan Error |
| --- | ----------------------------------- | ------------------------------------------------------- |
| 1 | Harus string | Nomor telepon harus berupa string |
| 2 | Nggak boleh kosong | Nomor telepon tidak boleh kosong |
| 3 | Cuma boleh angka (habis dibersihin) | Nomor telepon hanya boleh berisi angka |
| 4 | Harus mulai 08 | Nomor telepon harus diawali 08 |
| 5 | Digit ke-3 valid (bukan 0 / 4) | Prefix nomor telepon tidak valid |
| 6 | Panjang 10–13 digit | Panjang nomor telepon tidak valid (harus 10-13 digit) |
Pesan dari fungsi deteksi:
| Kondisi | Balikin |
| ---------------------- | ------------------------------ |
| Nomor invalid | Nomor telepon tidak valid |
| Prefix belum kedaftar | Operator tidak diketahui |
Ngurusin Error
Fungsi yang nggak error (balikin objek/string) — tinggal cek aja:
const r = validatePhone(input);
if (!r.valid) return showError(r.error);
const p = parsePhone(input);
if (!p.valid) return showError(p.error);
useOperator(p.operator);Fungsi yang bisa error (formatPhone, generatePhone) — bungkus try/catch:
try {
const e164 = formatPhone(userInput, "e164");
} catch (err) {
console.error((err as Error).message); // pesan bahasa Indonesia
}Fungsi deteksi balikin string error, bukan throw — cek pakai typeof:
const d = getProviderDetails(input);
if (typeof d === "string") {
showError(d);
} else {
useDetails(d);
}Operator & Prefix
Data per Mei 2025 (habis merger XL Axiata + Smartfren jadi XLSMART; Tri udah gabung Indosat sejak 2022).
| Operator | Prefix | Jumlah | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ | | Telkomsel | 0811, 0812, 0813, 0821, 0822, 0823, 0851, 0852, 0853 | 9 | | Indosat Ooredoo Hutchison | 0814, 0815, 0816, 0855, 0856, 0857, 0858, 0895, 0896, 0897, 0898, 0899 | 12 | | XLSMART | 0817, 0818, 0819, 0831, 0832, 0833, 0838, 0859, 0877, 0878, 0879, 0881, 0882, 0883, 0884, 0885, 0886, 0887, 0888, 0889 | 20 | | PSN (satelit) | 0868 | 1 | | Total | | 42 |
Brand tiap prefix (ringkas): Telkomsel → kartuHALO/simPATI/Kartu As · Indosat → IM3/Tri · XLSMART → XL/Axis/Smartfren · PSN → Byru/PASTI.
Import Hemat (Tree-shaking)
Kalau cuma butuh satu fungsi, import-nya dari sub-path aja biar bundle-nya kecil:
import { validatePhone } from "era-phone-validator/validate";
import { parsePhone } from "era-phone-validator/parse";
import { formatPhone } from "era-phone-validator/format";
import { generatePhone } from "era-phone-validator/generate";
import { detectProvider, getProviderDetails } from "era-phone-validator/detect";
import { getOperator, getPrefixesByOperator } from "era-phone-validator/operators";
import type { PhoneResult, ValidationResult } from "era-phone-validator/types";| Sub-path | Isinya |
| ------------- | ------------------------------------------------------------------------------- |
| /validate | validatePhone, isValidPhone |
| /parse | parsePhone |
| /format | formatPhone |
| /generate | generatePhone |
| /detect | detectProvider, detectBrand, detectNetwork, detectLocation, getProviderDetails |
| /operators | OPERATOR_MAP, getOperator, getOperators, getPrefixesByOperator, getOperatorNames, isKnownPrefix |
| /types | Semua tipe |
Contoh di Next.js & Tempat Lain
Library ini aman buat Next.js (App Router / Pages Router), bisa dipakai di server component, client component, API route, maupun server action.
Next.js — Client Component (validasi form real-time)
"use client";
import { useState } from "react";
import { validatePhone, detectProvider } from "era-phone-validator";
export function PhoneInput() {
const [phone, setPhone] = useState("");
const result = validatePhone(phone);
const operator = result.valid ? detectProvider(phone) : null;
return (
<div>
<input value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="08xxxxxxxxxx" />
{phone && !result.valid && <p style={{ color: "red" }}>{result.error}</p>}
{operator && <p style={{ color: "green" }}>Operator: {operator}</p>}
</div>
);
}Next.js — API Route (App Router)
// app/api/check-phone/route.ts
import { NextRequest, NextResponse } from "next/server";
import { parsePhone } from "era-phone-validator";
export async function POST(req: NextRequest) {
const { phone } = await req.json();
const parsed = parsePhone(phone);
if (!parsed.valid) {
return NextResponse.json({ ok: false, error: parsed.error }, { status: 400 });
}
return NextResponse.json({
ok: true,
e164: parsed.e164, // simpan yang ini ke DB (bentuk kanonik)
operator: parsed.operator,
});
}Next.js — Server Action
"use server";
import { parsePhone } from "era-phone-validator";
export async function saveContact(formData: FormData) {
const raw = String(formData.get("phone"));
const parsed = parsePhone(raw);
if (!parsed.valid) throw new Error(parsed.error);
await db.contact.create({ data: { phone: parsed.e164 } });
}Normalisasi ke E.164 sebelum simpan DB
import { parsePhone } from "era-phone-validator";
function toE164(input: string): string | null {
const r = parsePhone(input);
return r.valid ? r.e164 : null;
}
toE164("0812 3456 7890"); // "+6281234567890"
toE164("bukan"); // nullBikin data dummy buat testing
import { generatePhone } from "era-phone-validator";
const dummyUsers = Array.from({ length: 100 }, () => ({
phone: generatePhone({ format: "e164" }),
}));Tanya Jawab (FAQ)
Bisa dipakai di banyak project Next.js sekaligus?
Bisa banget. Install era-phone-validator di tiap project, import fungsinya, kelar. Nggak ada config ribet.
Bisa tau kota asli pemilik nomor nggak? Nggak. Gara-gara MNP (nomor bisa pindah operator tanpa ganti nomor), lokasi nggak bisa ditebak dari prefix. Fungsi lokasi cuma kasih cakupan operator (nasional).
Kenapa Tri masuk Indosat, Axis & Smartfren masuk XLSMART? Ngikutin kondisi sekarang: Tri udah merger ke Indosat (2022), XL Axiata + Smartfren jadi XLSMART (2025). Prefix eks-Axis juga di bawah XLSMART.
Nomor telepon rumah (PSTN) didukung?
Nggak. Ini khusus nomor HP (08...).
Kalau prefix belum kedaftar gimana?
validatePhone/parsePhone tetep nganggep valid kalau formatnya bener; cuma operator/brand-nya jadi "Tidak diketahui". Fungsi deteksi balikin "Operator tidak diketahui".
Aman buat dipakai di browser? Aman. Zero dependency, nggak akses jaringan atau file, dan tree-shakeable.
Kompatibilitas
- Node.js ≥ 18
- Module ESM & CommonJS (dua-duanya)
- TypeScript ≥ 5 (types udah include)
- Framework Next.js, Nuxt, Remix, Express, dll — bebas
- Browser modern (lewat bundler apa pun)
Buat Ngoprek Sendiri
git clone <repo-url>
cd era-phone-validator
npm install
npm run typecheck # cek tipe TypeScript
npm run test # jalanin test
npm run test:coverage # test + laporan coverage
npm run build # build ESM + CJS + d.tsMau Nyumbang? (Kontribusi)
Boleh banget! Alurnya gampang:
- Fork, bikin branch (
feat/nama-fitur). - Tambahin kode + test-nya.
- Pastiin
npm run typecheck,npm run test, dannpm run buildlolos. - Bikin pull request, jelasin perubahannya.
Mau update data operator? Edit src/operators.ts, terus sesuaikan test di src/detect.test.ts.
Changelog
Lihat CHANGELOG.md buat riwayat perubahan.
Lisensi
MIT — pakai bebas, gratis.
