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

phone-blocks

v1.0.4

Published

French phone number block resolution library (data.gouv.fr)

Readme

phone-blocks

French phone number block resolution library powered by ARCEP open data (the French telecom regulator).

Look up any French phone number to find its assigned operator, territory, and attribution date — using official government datasets.

Installation

npm install phone-blocks
# or
bun add phone-blocks

Quick start

import { PhoneBlockRegistry } from "phone-blocks";

// Zero-config — uses bundled ARCEP data
const registry = PhoneBlockRegistry.fromDataDir();

const { block } = registry.lookup("0612345678");
console.log(block?.operatorName); // "Orange"

CLI lookup

bun src/lookup.ts 0612345678

Returns a JSON object with the block info (operator, territory, attribution date, range) and portability data if the block has been ported.

Supported datasets

The library supports all ARCEP CSV datasets published on data.gouv.fr:

| File | Description | Required | |---|---|---| | MAJNUM.csv | Number block ranges and their assignees | Yes | | MAJRIO.csv | Operator identity table | Yes | | MAJNFB.csv | Short/special numbers (emergency, services) | No | | MAJMNC.csv | Mobile Network Codes (MCC-MNC) | No | | MAJPORTA.csv | Number portability reassignments | No | | MAJCPSN.csv | Additional operator table (CPSN) | No | | MAJCPSI.csv | Additional operator table (CPSI) | No | | MAJR1R2.csv | Additional operator table (R1/R2) | No | | MAJSDT.csv | Additional operator table (SDT) | No | | GELNUM.csv | Frozen number blocks open for attribution | No |

Loading all datasets

The simplest way is fromDataDir(), which loads all 10 bundled CSV files at once:

const registry = PhoneBlockRegistry.fromDataDir();

You can also point to a custom directory:

const registry = PhoneBlockRegistry.fromDataDir("/path/to/my/data");

Or load files individually with fromFiles():

const registry = PhoneBlockRegistry.fromFiles(
  "./data/MAJNUM.csv",
  "./data/MAJRIO.csv",
  {
    majnfbPath: "./data/MAJNFB.csv",
    majmncPath: "./data/MAJMNC.csv",
    majportaPath: "./data/MAJPORTA.csv",
    gelnumPath: "./data/GELNUM.csv",
    extraOperatorPaths: [
      "./data/MAJCPSN.csv",
      "./data/MAJCPSI.csv",
      "./data/MAJR1R2.csv",
      "./data/MAJSDT.csv",
    ],
  },
);

API reference

PhoneBlockRegistry

Static factories

fromDataDir(dataDir?)

Loads all 10 ARCEP CSV files from a directory. Defaults to the bundled data/ directory shipped with the package.

// Bundled data (zero-config)
const registry = PhoneBlockRegistry.fromDataDir();

// Custom directory
const registry = PhoneBlockRegistry.fromDataDir("/path/to/data");
fromFiles(majnumPath, majrioPath, options?)

Creates a registry by reading CSV files from disk. Files are parsed as Latin-1 (ISO-8859-1) with ; as separator.

const registry = PhoneBlockRegistry.fromFiles("./data/MAJNUM.csv", "./data/MAJRIO.csv");

Options:

| Property | Type | Description | |---|---|---| | majnfbPath | string | Path to MAJNFB.csv (short numbers) | | majmncPath | string | Path to MAJMNC.csv (MCC-MNC) | | majportaPath | string | Path to MAJPORTA.csv (portability) | | gelnumPath | string | Path to GELNUM.csv (frozen blocks) | | extraOperatorPaths | string[] | Paths to extra operator tables (MAJCPSN, MAJCPSI, MAJR1R2, MAJSDT) |

fromRaw(rawBlocks, rawOperators, options?)

Creates a registry from pre-parsed data arrays. Useful for tests or environments without filesystem access.

const registry = PhoneBlockRegistry.fromRaw(rawBlocks, rawOperators, {
  rawShortNumbers: [...],
  rawMnc: [...],
  rawPortability: [...],
  rawFrozen: [...],
  extraOperators: [...],
});

Phone number lookup

lookup(phoneNumber): LookupResult

Finds the number block a phone number belongs to, using binary search (O(log n)).

Accepted formats: "0612345678", "+33612345678", "+33 6 12 34 56 78", "06-12-34-56-78", "612345678".

const { normalizedNumber, block } = registry.lookup("0612345678");

if (block) {
  console.log(block.operatorCode);  // "FRTE"
  console.log(block.operatorName);  // "Orange"
  console.log(block.territoire);    // "Métropole"
  console.log(block.rangeStart);    // 600000000
  console.log(block.rangeEnd);      // 609999999
  console.log(block.attributedAt);  // Date object
}

Returns { block: null } if the number doesn't belong to any known range.

Short number lookup

lookupShortNumber(shortNumber): ShortNumberLookupResult

Looks up a short/special number (e.g. "15", "112", "3008"). Requires MAJNFB data.

const { block } = registry.lookupShortNumber("15");
console.log(block?.operatorName); // "Orange"

Mobile Network Codes

lookupMobileNetworkCode(mccMnc): MobileNetworkCode | null

Looks up a Mobile Network Code by its MCC-MNC identifier. Requires MAJMNC data.

const mnc = registry.lookupMobileNetworkCode("20801");
console.log(mnc?.operatorName); // "Orange France"
console.log(mnc?.decision);     // "2000-0001"
getMobileNetworkCodes(): MobileNetworkCode[]

Returns all MCC-MNC entries, sorted by identifier.

Number portability

lookupPortability(blockId): PortabilityEntry | null

Looks up the current operator for a block after number portability. Requires MAJPORTA data.

const entry = registry.lookupPortability("6000");
console.log(entry?.operatorCode); // "SFR0"
console.log(entry?.operatorName); // "Société française du radiotéléphone"

Frozen blocks

lookupFrozenBlock(blockId): FrozenBlock | null

Looks up a frozen number block by its EZABPQM identifier. Requires GELNUM data.

const frozen = registry.lookupFrozenBlock("08359");
console.log(frozen?.type);              // "Code point sémaphore national"
console.log(frozen?.interestOpensAt);   // Date object
console.log(frozen?.attributionOpensAt); // Date object
getFrozenBlocks(): FrozenBlock[]

Returns all frozen number blocks.

Operators & statistics

getBlocksByOperator(operatorCode): PhoneBlock[]

Returns all blocks assigned to a given operator (case-insensitive).

const blocks = registry.getBlocksByOperator("FRTE");
console.log(blocks.length); // number of Orange blocks
getOperators(): Array<{ code: string; name: string }>

Lists all operators from the MAJRIO table, sorted alphabetically by code.

getStats()

Returns aggregate statistics about the loaded registry.

const stats = registry.getStats();
// { totalBlocks, totalOperators, totalNumbers, blocksWithUnknownOperator }
size: number

Total number of loaded number blocks (getter).

parseCsv(filePath)

Low-level CSV parser. Reads a Latin-1 encoded CSV file with ; separator and returns an array of row objects.

import { parseCsv } from "phone-blocks";

const rows = parseCsv("./data/MAJNUM.csv");

Types

All types are exported for use in your own code:

import type {
  PhoneBlock,
  LookupResult,
  ShortNumberLookupResult,
  MobileNetworkCode,
  PortabilityEntry,
  FrozenBlock,
  Territoire,
  // Raw types (as parsed from CSV)
  RawNumBlock,
  RawOperator,
  RawMobileNetworkCode,
  RawPortability,
  RawFrozenBlock,
} from "phone-blocks";

Development

# Install dependencies
bun install

# Build
bun run build

# Type-check
bun run typecheck

# Lint & format (Biome)
bun run check
bun run lint
bun run format

# Run tests
bun run test

# Publish
bun run publish-package

License

MIT