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

oglap-ggp-node-js

v1.0.1

Published

OGLAP — Offline Grid Location Addressing Protocol. Node.js implementation of the Global Grid Protocol (GGP) for Guinea (GN).

Readme

oglap-ggp-node-js

Implémentation Node.js du protocole OGLAP (Offline Grid Location Addressing Protocol) — un système d'adressage déterministe basé sur une grille, conçu pour les régions où les adresses postales formelles sont inexistantes ou peu fiables.

OGLAP génère des codes LAP compacts et lisibles (ex. GN-CKY-QKAR-B4A4-2798) qui identifient de façon unique n'importe quelle coordonnée à l'intérieur d'un pays configuré, hors ligne et sans API externe.


Fonctionnalités

  • Coordonnées → code LAP — encoder toute position GPS en adresse LAP structurée
  • Code LAP → coordonnées — décoder un code LAP vers son centre géographique
  • Geocodage inversé — trouver la région administrative, zone et lieu contenant une coordonnée
  • Parsing & validation de code LAP — analyser des codes partiels ou complets, valider le format et le contenu
  • Boîte englobante et centroïde — calculer bbox et centre à partir de géométries GeoJSON
  • Entièrement hors ligne — aucune connexion requise une fois les données chargées

Format du code LAP

Un code LAP encode une localisation à quatre niveaux hiérarchiques :

Grille locale (5 segments)

GN  - CKY  - QKAR - B4A4 - 2798
│      │      │      │      └─ Microspot   — 4 chiffres, offset métrique (XX = est, YY = nord)
│      │      │      └─────── Macrobloc   — 4 chars [A-J][0-9][A-J][0-9], blocs ~100 m dans la zone
│      │      └────────────── Zone        — 4 chars, dérivé du nom de lieu local
│      └───────────────────── Région      — 3 chars, code de région administrative
└──────────────────────────── Pays        — code ISO alpha-2 du pays

Grille nationale (4 segments)

Utilisée quand une coordonnée se situe en dehors des limites administratives de niveau 8 et au-dessus :

GN  - CKY  - AABCDE - 4250
│      │      │        └─ Microspot   — 4 chiffres
│      │      └────────── Macrobloc   — 6 lettres, grille kilométrique nationale
│      └──────────────── Région
└─────────────────────── Pays

Démarrage

1. Ajouter la dépendance

npm install oglap-ggp-node-js

2. Préparer les données

Le package nécessite trois fichiers JSON :

| Fichier | Description | |---|---| | {country_code}_oglap_country_profile.json | Paramètres de grille, codes admin, règles de nommage | | {country_code}_localities_naming.json | Géométries GeoJSON des lieux (régions, zones, localités) | | {country_code}_full.json | Correspondances place-ID → code OGLAP |

3. Initialiser avant toute utilisation

Appeler initOglap une seule fois au démarrage de l'application, avant toute autre fonction :

Mode téléchargement (recommandé) — les données sont téléchargées et mises en cache localement :

import { initOglap } from 'oglap-ggp-node-js';

const report = await initOglap({
  version: 'latest',
  dataDir: 'oglap-data',      // dossier de cache local
  forceDownload: false,
  onProgress({ label, status, percent, step, totalSteps }) {
    if (status === 'downloading') process.stdout.write(`\r↓ [${step}/${totalSteps}] ${label}: ${percent}%`);
    if (status === 'cached')      console.log(`⚡ [${step}/${totalSteps}] ${label}: depuis le cache`);
    if (status === 'done')        console.log(`\r✓ [${step}/${totalSteps}] ${label}: terminé`);
    if (status === 'error')       console.log(`✗ [${step}/${totalSteps}] ${label}: erreur`);
  }
});

if (!report.ok) throw new Error(report.error);

Mode direct — pour les environnements sans accès disque (serverless, edge) :

import { initOglap, loadOglap } from 'oglap-ggp-node-js';

const profile    = await fetch('/data/country_profile.json').then(r => r.json());
const localities = await fetch('/data/localities_naming.json').then(r => r.json());
const places     = await fetch('/data/oglap_data.json').then(r => r.json());

const report = await initOglap(profile, localities);
if (!report.ok) throw new Error(report.error);

const loaded = loadOglap(places);
console.log(`${loaded.count} lieux chargés`);

Utilisation

Encoder des coordonnées en code LAP

import { coordinatesToLap } from 'oglap-ggp-node-js';

const result = coordinatesToLap(9.5370, -13.6773); // lat, lon — Conakry, Guinée

console.log(result.lapCode);        // GN-CKY-QKAR-B4A4-2798
console.log(result.humanAddress);   // Quartier Almamya, Conakry, Kindia, Guinée
console.log(result.admin_level_2);  // CKY  (code de région)
console.log(result.admin_level_3);  // QKAR (code de zone)
console.log(result.macroblock);     // B4A4
console.log(result.microspot);      // 2798
console.log(result.isNationalGrid); // false
console.log(result.originLat);      // latitude d'origine de la bbox
console.log(result.originLon);      // longitude d'origine de la bbox

Retourne null si les coordonnées sont hors du territoire.

Décoder un code LAP en coordonnées

import { lapToCoordinates } from 'oglap-ggp-node-js';

const coords = lapToCoordinates('GN-CKY-QKAR-B4A4-2798');

if (coords) {
  console.log(`lat: ${coords.lat}, lon: ${coords.lon}`);
  // lat: 9.5370..., lon: -13.6773...
}

// Le préfixe pays est optionnel
const coords2 = lapToCoordinates('CKY-QKAR-B4A4-2798');

Parser et valider un code LAP

import { validateLapCode, parseLapCode } from 'oglap-ggp-node-js';

// Valider — retourne un message d'erreur, ou null si valide
const error = validateLapCode('GN-CKY-QKAR-B4A4-2798');
if (error) {
  console.log('Invalide :', error);
} else {
  console.log('Code valide');
}

// Parser en composants
const parsed = parseLapCode('GN-CKY-QKAR-B4A4-2798');
if (parsed) {
  console.log(parsed.admin_level_2_Iso);  // code ISO de la région
  console.log(parsed.admin_level_3_code); // code de zone : QKAR
  console.log(parsed.macroblock);         // B4A4
  console.log(parsed.microspot);          // 2798
  console.log(parsed.isNationalGrid);     // false
}

// Les codes partiels sont aussi supportés
parseLapCode('GN-CKY-QKAR'); // région + zone seulement
parseLapCode('QKAR');         // zone seulement

Résoudre un code LAP vers un lieu

import { getPlaceByLapCode } from 'oglap-ggp-node-js';

const resolved = getPlaceByLapCode('GN-CKY-QKAR-B4A4-2798');

if (resolved) {
  console.log(resolved.originLat); // latitude d'origine de la bbox
  console.log(resolved.originLon); // longitude d'origine de la bbox

  if (resolved.place) {
    const addr = resolved.place.address;
    const name = addr?.village ?? addr?.town ?? addr?.city ?? resolved.place.display_name;
    console.log(name); // nom du lieu lisible
  }

  // Accéder aux composants parsés
  console.log(resolved.parsed.macroblock); // B4A4
  console.log(resolved.parsed.microspot);  // 2798
}

Boîte englobante et centroïde

import { bboxFromGeometry, centroidFromBbox } from 'oglap-ggp-node-js';

const geometry = {
  type: 'Polygon',
  coordinates: [[
    [-13.70, 9.50],
    [-13.65, 9.50],
    [-13.65, 9.55],
    [-13.70, 9.55],
    [-13.70, 9.50],
  ]]
};

const bbox = bboxFromGeometry(geometry);
// [minLat, maxLat, minLon, maxLon]

if (bbox) {
  const center = centroidFromBbox(bbox);
  // [lat, lon] du point central de la bbox
  console.log(`Centre : ${center[0]}, ${center[1]}`);
}

Accéder aux métadonnées du pays

import { getCountryCode, getCountrySW, getOglapPrefectures } from 'oglap-ggp-node-js';

console.log(getCountryCode()); // "GN"
console.log(getCountrySW());   // [lat, lon] du coin sud-ouest

const prefectures = getOglapPrefectures();
// { [isoCode]: prefectureOglapCode, ... }

Modèles de données

Résultat de coordinatesToLap

| Champ | Type | Description | |---|---|---| | lapCode | string | Code LAP complet, ex. GN-CKY-QKAR-B4A4-2798 | | country | string | Code pays, ex. GN | | admin_level_2 | string | Code de région, ex. CKY | | admin_level_3 | string\|null | Code de zone, ex. QKAR | | macroblock | string | Composant macrobloc | | microspot | string | Composant microspot | | isNationalGrid | boolean | true si grille nationale utilisée | | displayName | string | Nom du lieu issu du geocodage inversé | | humanAddress | string | Adresse complète lisible | | address | object | Composants d'adresse structurés | | originLat | number | Latitude d'origine de la bbox | | originLon | number | Longitude d'origine de la bbox | | pcode | string[] | P-codes UNOCHA pour la localisation |

Résultat de parseLapCode

| Champ | Type | Description | |---|---|---| | admin_level_2_Iso | string\|undefined | Code ISO de la région | | admin_level_3_code | string\|undefined | Code de zone | | macroblock | string\|undefined | Composant macrobloc | | microspot | string\|undefined | Composant microspot | | isNationalGrid | boolean | true si grille nationale |

Résultat de getPlaceByLapCode

| Champ | Type | Description | |---|---|---| | place | object\|null | Données OSM du lieu | | parsed | object | Composants LAP parsés | | originLat | number\|undefined | Latitude d'origine de la bbox | | originLon | number\|undefined | Longitude d'origine de la bbox |

Rapport de initOglap

| Champ | Type | Description | |---|---|---| | ok | boolean | Initialisation réussie | | countryCode | string\|null | Ex. GN | | countryName | string\|null | Ex. Guinée | | bounds | number[][]\|null | [[swLat, swLon], [neLat, neLon]] | | checks | Array | Résultats de validation (pass, warn, fail) | | error | string\|null | Message d'erreur si !ok | | dataDir | string\|undefined | Dossier de cache local | | dataLoaded | object\|undefined | Résultat du chargement des lieux |


Exemple complet de bout en bout

import {
  initOglap,
  checkOglap,
  coordinatesToLap,
  lapToCoordinates,
  getPlaceByLapCode,
  validateLapCode,
  parseLapCode,
} from 'oglap-ggp-node-js';

class LocationService {
  static #initialized = false;

  static async init() {
    if (this.#initialized) return;

    const report = await initOglap({
      onProgress({ label, status, percent, step, totalSteps }) {
        if (status === 'downloading') process.stdout.write(`\r↓ [${step}/${totalSteps}] ${label}: ${percent}%`);
        if (status === 'cached')      console.log(`⚡ [${step}/${totalSteps}] ${label}: depuis le cache`);
        if (status === 'done')        console.log(`\r✓ [${step}/${totalSteps}] ${label}: terminé`);
        if (status === 'error')       console.log(`✗ [${step}/${totalSteps}] ${label}: erreur`);
      }
    });

    if (!report.ok) throw new Error(`Initialisation OGLAP échouée : ${report.error}`);
    this.#initialized = true;
  }

  /** Encoder la position GPS de l'utilisateur */
  static encodePosition(lat, lon) {
    const result = coordinatesToLap(lat, lon);
    return result?.lapCode ?? null;
  }

  /** Partager une localisation : retourne le code LAP et l'adresse lisible */
  static shareLocation(lat, lon) {
    const result = coordinatesToLap(lat, lon);
    if (!result) return null;
    return {
      code:  result.lapCode,
      label: result.humanAddress,
    };
  }

  /** Naviguer vers un code LAP en le convertissant en coordonnées */
  static decodeToCoords(lapCode) {
    return lapToCoordinates(lapCode); // { lat, lon } ou null
  }

  /** Valider la saisie d'un code LAP par l'utilisateur */
  static validateInput(input) {
    return validateLapCode(input); // null = valide, string = message d'erreur
  }

  /** Résoudre un code LAP vers les détails du lieu */
  static resolvePlace(lapCode) {
    const resolved = getPlaceByLapCode(lapCode);
    if (!resolved?.place) return null;

    const addr = resolved.place.address ?? {};
    return {
      name:      addr.village ?? addr.town ?? addr.city ?? resolved.place.display_name,
      adminCode: resolved.parsed.admin_level_3_code,
      originLat: resolved.originLat,
      originLon: resolved.originLon,
    };
  }
}

// Utilisation
await LocationService.init();

// Encoder le centre de Conakry
const code = LocationService.encodePosition(9.5370, -13.6773);
console.log(code); // GN-CKY-QKAR-B4A4-2798

// Décoder
const coords = LocationService.decodeToCoords(code);
console.log(coords); // { lat: 9.537..., lon: -13.677... }

// Partager
const share = LocationService.shareLocation(9.5370, -13.6773);
console.log(share.label); // Quartier Almamya, Conakry, Kindia, Guinée

// Valider la saisie utilisateur
const err = LocationService.validateInput('GN-CKY-QKAR-B4A4-2798');
console.log(err); // null (valide)

// Résoudre un lieu
const place = LocationService.resolvePlace('GN-CKY-QKAR-B4A4-2798');
console.log(place.name); // Quartier Almamya

Exécuter les tests

node test.js

Informations complémentaires

  • Protocole : OGLAP est conçu pour la Guinée (GN) mais configurable pour tout pays via le fichier profil JSON.
  • Offline-first : tout l'encodage et décodage est effectué localement avec les données chargées — aucun réseau requis.
  • Déterministe : les mêmes coordonnées produisent toujours le même code LAP, à données identiques.
  • Bugs : signaler les problèmes dans le dépôt principal Kiraa.