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

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.

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 version license types node

npm install era-phone-validator

Nggak perlu database, nggak perlu API call, nggak perlu file aneh-aneh. Install, import, langsung gas.


Daftar Isi


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-validator

Pakai 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: true kok. Cuma operator/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 prefix dan operator dikasih dua-duanya, yang dipakai prefix.


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"); // true

Tipe 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");          // null

Bikin 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.ts

Mau Nyumbang? (Kontribusi)

Boleh banget! Alurnya gampang:

  1. Fork, bikin branch (feat/nama-fitur).
  2. Tambahin kode + test-nya.
  3. Pastiin npm run typecheck, npm run test, dan npm run build lolos.
  4. 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.