georeference 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/CONTRIBUTING.fr.md +44 -0
  3. package/CONTRIBUTING.md +44 -0
  4. package/LICENSE +21 -0
  5. package/README.fr.md +84 -0
  6. package/README.md +83 -2
  7. package/SECURITY.fr.md +9 -0
  8. package/SECURITY.md +9 -0
  9. package/dist/adapters/common.d.ts +5 -0
  10. package/dist/adapters/common.js +37 -0
  11. package/dist/adapters/common.js.map +1 -0
  12. package/dist/adapters/csv.d.ts +2 -0
  13. package/dist/adapters/csv.js +32 -0
  14. package/dist/adapters/csv.js.map +1 -0
  15. package/dist/adapters/geojson.d.ts +2 -0
  16. package/dist/adapters/geojson.js +36 -0
  17. package/dist/adapters/geojson.js.map +1 -0
  18. package/dist/adapters/index.d.ts +3 -0
  19. package/dist/adapters/index.js +10 -0
  20. package/dist/adapters/index.js.map +1 -0
  21. package/dist/adapters/json.d.ts +3 -0
  22. package/dist/adapters/json.js +48 -0
  23. package/dist/adapters/json.js.map +1 -0
  24. package/dist/adapters/postgres.d.ts +3 -0
  25. package/dist/adapters/postgres.js +59 -0
  26. package/dist/adapters/postgres.js.map +1 -0
  27. package/dist/adapters/sqlite.d.ts +2 -0
  28. package/dist/adapters/sqlite.js +49 -0
  29. package/dist/adapters/sqlite.js.map +1 -0
  30. package/dist/cli.d.ts +2 -0
  31. package/dist/cli.js +219 -0
  32. package/dist/cli.js.map +1 -0
  33. package/dist/client.d.ts +9 -0
  34. package/dist/client.js +24 -0
  35. package/dist/client.js.map +1 -0
  36. package/dist/export.d.ts +6 -0
  37. package/dist/export.js +127 -0
  38. package/dist/export.js.map +1 -0
  39. package/dist/files.d.ts +6 -0
  40. package/dist/files.js +28 -0
  41. package/dist/files.js.map +1 -0
  42. package/dist/generate.d.ts +10 -0
  43. package/dist/generate.js +102 -0
  44. package/dist/generate.js.map +1 -0
  45. package/dist/graph.d.ts +3 -0
  46. package/dist/graph.js +31 -0
  47. package/dist/graph.js.map +1 -0
  48. package/dist/index.d.ts +7 -0
  49. package/dist/index.js +6 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/package.d.ts +6 -0
  52. package/dist/package.js +133 -0
  53. package/dist/package.js.map +1 -0
  54. package/dist/seeding/index.d.ts +6 -0
  55. package/dist/seeding/index.js +80 -0
  56. package/dist/seeding/index.js.map +1 -0
  57. package/dist/seeding/ledger.d.ts +12 -0
  58. package/dist/seeding/ledger.js +54 -0
  59. package/dist/seeding/ledger.js.map +1 -0
  60. package/dist/seeding/mapping.d.ts +31 -0
  61. package/dist/seeding/mapping.js +54 -0
  62. package/dist/seeding/mapping.js.map +1 -0
  63. package/dist/seeding/preflight.d.ts +10 -0
  64. package/dist/seeding/preflight.js +149 -0
  65. package/dist/seeding/preflight.js.map +1 -0
  66. package/dist/seeding/retained.d.ts +5 -0
  67. package/dist/seeding/retained.js +32 -0
  68. package/dist/seeding/retained.js.map +1 -0
  69. package/dist/seeding/types.d.ts +41 -0
  70. package/dist/seeding/types.js +2 -0
  71. package/dist/seeding/types.js.map +1 -0
  72. package/dist/seeding/write.d.ts +4 -0
  73. package/dist/seeding/write.js +31 -0
  74. package/dist/seeding/write.js.map +1 -0
  75. package/dist/snapshot.d.ts +14 -0
  76. package/dist/snapshot.js +154 -0
  77. package/dist/snapshot.js.map +1 -0
  78. package/dist/sources/geonames.d.ts +14 -0
  79. package/dist/sources/geonames.js +118 -0
  80. package/dist/sources/geonames.js.map +1 -0
  81. package/dist/types.d.ts +113 -0
  82. package/dist/types.js +2 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/validation.d.ts +4 -0
  85. package/dist/validation.js +91 -0
  86. package/dist/validation.js.map +1 -0
  87. package/docs/architecture.fr.md +105 -0
  88. package/docs/architecture.md +105 -0
  89. package/docs/data-sources.fr.md +39 -0
  90. package/docs/data-sources.md +39 -0
  91. package/docs/format-decisions.fr.md +54 -0
  92. package/docs/format-decisions.md +54 -0
  93. package/docs/formats.fr.md +34 -0
  94. package/docs/formats.md +34 -0
  95. package/docs/generation.fr.md +29 -0
  96. package/docs/generation.md +29 -0
  97. package/docs/getting-started.fr.md +79 -0
  98. package/docs/getting-started.md +79 -0
  99. package/docs/seeding.fr.md +71 -0
  100. package/docs/seeding.md +71 -0
  101. package/examples/README.md +7 -0
  102. package/examples/metadata.json +13 -0
  103. package/examples/sample.ndjson +4 -0
  104. package/package.json +64 -4
@@ -0,0 +1,79 @@
1
+ # Prise en main
2
+
3
+ [English](getting-started.md) · [Accueil](../README.fr.md)
4
+
5
+ ## Générer directement les fichiers
6
+
7
+ Commencez par [la génération en une commande](generation.fr.md) : `npx georeference` génère les fichiers de pays sans ajouter de dépendance au projet. Le SDK est optionnel. Le guide explique aussi comment utiliser une version locale. Les sections suivantes couvrent la préparation avancée des sources, les exports et l'amorçage en base.
8
+
9
+ ## Construire et créer un instantané
10
+
11
+ Prérequis : Node.js 24.18.x, npm et assez d'espace disque pour les instantanés/exports. PostgreSQL n'est nécessaire que pour l'amorçage d'une base PostgreSQL. SQLite utilise le module `node:sqlite` intégré à Node.
12
+
13
+ ```sh
14
+ npm ci
15
+ npm run build
16
+ node dist/cli.js --help
17
+ node dist/cli.js snapshot --input examples/sample.ndjson --metadata examples/metadata.json --output data/example.sqlite
18
+ node dist/cli.js inspect --snapshot data/example.sqlite
19
+ ```
20
+
21
+ Les entités fournies sont fictives. Le fichier de métadonnées contient `contractVersion`, `datasetVersion` et `sources` ; chaque source déclare `name`, `url`, `license`, `attribution` et `revision`. Les entités ont les champs stables `id`, `entityType`, `name`, `countryId` et `parentId`. Les champs facultatifs sont `codes`, les `names` localisés, le `level` administratif, les `coordinates` et la `boundary` Polygon/MultiPolygon.
22
+
23
+ Un pays se référence lui-même dans `countryId` et possède `parentId: null`. Tout autre parent doit exister dans l'instantané. Les objets de coordonnées utilisent les champs nommés `longitude` et `latitude` ; les positions GeoJSON suivent `[longitude, latitude]`. La création valide le graphe et les géométries. Utilisez un nouveau chemin de sortie plutôt que d'écraser un instantané existant.
24
+
25
+ ## Sélectionner et exporter
26
+
27
+ ```sh
28
+ node dist/cli.js export --snapshot data/example.sqlite --country XZ --types locality --coordinates --format ndjson --compression gzip --output exports/localities
29
+ node dist/cli.js verify --package exports/localities
30
+ node dist/cli.js export --snapshot data/example.sqlite --subdivision example:region --format json --layout hierarchical --output exports/region-tree
31
+ node dist/cli.js export --snapshot data/example.sqlite --format geojson --coordinates --boundaries --output exports/map-layers
32
+ ```
33
+
34
+ Les filtres de pays acceptent les IDs stables ou les codes pays. Plusieurs IDs/types se séparent par des virgules. Le filtre de subdivision inclut ses descendants administratifs ; il n'effectue pas d'intersection spatiale. Les ancêtres nécessaires sont ajoutés par défaut et signalés comme contexte. `--no-ancestors` rend explicites les références externes à la sélection ; un importeur doit les résoudre en cible.
35
+
36
+ Coordonnées et frontières sont exclues tant qu'elles ne sont pas demandées. Une géométrie absente reste absente ; le manifeste indique la couverture. La combinaison format/organisation doit être prise en charge ; consulter [les formats](formats.fr.md).
37
+
38
+ Les paquets contiennent `manifest.json` et les fichiers de données. La vérification contrôle leur intégrité. Conservez le manifeste avec les fichiers partagés. Gzip compresse chaque fichier dans le répertoire ; le lecteur le décompresse. Avec ZIP, la sortie contient un manifeste externe et `package.zip` ; l'archive contient les fichiers et un manifeste interne. Vérifiez le répertoire initial pour l'intégrité de l'archive, puis extrayez `package.zip` dans un **nouveau répertoire** et vérifiez/importez ce répertoire extrait. La compression constitue un transport, pas un nouveau contrat de données.
39
+
40
+ ## Utiliser des fichiers GeoNames réels
41
+
42
+ Téléchargez les fichiers souhaités depuis [les exports GeoNames](https://download.geonames.org/export/dump/), conservez leur licence et extrayez vous-même les archives ZIP. Importez ensuite les fichiers texte locaux :
43
+
44
+ ```sh
45
+ node dist/cli.js geonames --countries data/countryInfo.txt --admin1 data/admin1CodesASCII.txt --admin2 data/admin2Codes.txt --places data/cities1000.txt --version geonames-2026-11-11 --output data/geonames.sqlite
46
+ ```
47
+
48
+ Seuls `--countries`, `--version` et `--output` sont obligatoires. L'importeur ne télécharge rien sur le réseau. Il accepte les lieux habités GeoNames, et non toutes les classes de points géographiques. Chaque fichier reçoit une révision de provenance SHA-256. Voir [la couverture et les limites](data-sources.fr.md).
49
+
50
+ ## Amorcer PostgreSQL
51
+
52
+ Exportez du JSON, NDJSON ou CSV normalisé, puis examinez l'aperçu avant l'application :
53
+
54
+ ```sh
55
+ node dist/cli.js export --snapshot data/example.sqlite --format ndjson --coordinates --output exports/seed
56
+ node dist/cli.js seed --package exports/seed --create-schema
57
+ node dist/cli.js seed --package exports/seed --create-schema --apply
58
+ ```
59
+
60
+ Définissez `DATABASE_URL` dans votre terminal ou gestionnaire de secrets avant ces commandes. N'enregistrez pas les identifiants de connexion dans des fichiers suivis ou dans les paquets exportés. Les commandes ci-dessus ciblent le schéma standard ; les tables applicatives existantes nécessitent un mapping explicite. Voir [l'amorçage](seeding.fr.md) pour l'ordre des révisions, les champs gérés et la reprise.
61
+
62
+ ## SDK optionnel
63
+
64
+ Seules les applications qui souhaitent consulter un instantané via l'API locale doivent installer la bibliothèque avec `npm install georeference`. Vous pouvez aussi construire et installer une archive locale avec `npm pack` puis `npm install /chemin/vers/georeference-1.0.0.tgz`. La génération de fichiers n'en a pas besoin.
65
+
66
+ ```ts
67
+ import { Snapshot, createClient } from 'georeference';
68
+
69
+ const snapshot = Snapshot.open('data/example.sqlite');
70
+ try {
71
+ const client = createClient(snapshot);
72
+ console.log(client.getEntity('example:locality'));
73
+ console.log(client.getCountry('example:country'));
74
+ } finally {
75
+ snapshot.close();
76
+ }
77
+ ```
78
+
79
+ Le SDK lit l'instantané local ; il ne synchronise pas une base applicative. Gardez l'instantané ouvert pendant les itérations et fermez-le après usage. Installez le paquet compilé avec `npm install georeference`, ou construisez/installez-le depuis ce dépôt.
@@ -0,0 +1,79 @@
1
+ # Getting started
2
+
3
+ [Français](getting-started.fr.md) · [Home](../README.md)
4
+
5
+ ## Generate files directly
6
+
7
+ Start with [one-shot generation](generation.md): `npx georeference` generates country files without adding a dependency to your project. The SDK is optional. The guide also explains how to run a local build. The following sections cover advanced source preparation, exports and database seeding.
8
+
9
+ ## Build and create a snapshot
10
+
11
+ Requirements: Node.js 24.18.x, npm, and disk space for snapshots/exports. PostgreSQL is needed only for seeding into PostgreSQL. SQLite support comes from Node's built-in `node:sqlite` module.
12
+
13
+ ```sh
14
+ npm ci
15
+ npm run build
16
+ node dist/cli.js --help
17
+ node dist/cli.js snapshot --input examples/sample.ndjson --metadata examples/metadata.json --output data/example.sqlite
18
+ node dist/cli.js inspect --snapshot data/example.sqlite
19
+ ```
20
+
21
+ The included entities are fictional. The metadata file specifies `contractVersion`, `datasetVersion`, and `sources`; each source declares `name`, `url`, `license`, `attribution`, and `revision`. Input entities have stable `id`, `entityType`, `name`, `countryId`, and `parentId`. Optional fields are `codes`, localized `names`, administrative `level`, `coordinates`, and Polygon/MultiPolygon `boundary`.
22
+
23
+ Countries refer to themselves through `countryId` and have `parentId: null`. Every other parent must exist in the snapshot. Coordinate objects use named `longitude` and `latitude`; GeoJSON positions use `[longitude, latitude]`. Creating a snapshot validates the graph and geometry. Supply a new output path rather than overwriting an existing snapshot.
24
+
25
+ ## Select and export
26
+
27
+ ```sh
28
+ node dist/cli.js export --snapshot data/example.sqlite --country XZ --types locality --coordinates --format ndjson --compression gzip --output exports/localities
29
+ node dist/cli.js verify --package exports/localities
30
+ node dist/cli.js export --snapshot data/example.sqlite --subdivision example:region --format json --layout hierarchical --output exports/region-tree
31
+ node dist/cli.js export --snapshot data/example.sqlite --format geojson --coordinates --boundaries --output exports/map-layers
32
+ ```
33
+
34
+ Country filters accept stable IDs or country codes. Multiple IDs/types use comma-separated values. Subdivision filters include descendants by administrative membership; they do not perform spatial intersection. Required ancestors are added by default and reported as context. `--no-ancestors` makes references outside the selection explicit; an importer must resolve them in the target.
35
+
36
+ Coordinates and boundaries are excluded unless requested. Missing geometry stays missing; the manifest reports coverage. A requested format/layout combination must be supported; consult [formats](formats.md).
37
+
38
+ Export packages contain `manifest.json` and data files. Verification checks file integrity. Preserve the manifest when sharing files. Gzip compresses each payload inside the directory; the package reader decompresses it. With ZIP, the output directory contains an outer manifest and `package.zip`; the archive contains the payload files and an inner manifest. Verify the original directory for archive integrity, then extract `package.zip` to a **new directory** and verify/seed that extracted directory. Compression is transport packaging, not a new data contract.
39
+
40
+ ## Use real GeoNames inputs
41
+
42
+ Download the desired files from [GeoNames exports](https://download.geonames.org/export/dump/), retain their license, and extract any ZIP archives yourself. Then ingest local text files:
43
+
44
+ ```sh
45
+ node dist/cli.js geonames --countries data/countryInfo.txt --admin1 data/admin1CodesASCII.txt --admin2 data/admin2Codes.txt --places data/cities1000.txt --version geonames-2026-11-11 --output data/geonames.sqlite
46
+ ```
47
+
48
+ Only `--countries`, `--version`, and `--output` are mandatory. The importer does not fetch data from the network. It accepts GeoNames populated-place records, not every feature class. Each supplied file receives a SHA-256 provenance revision. See [source coverage and limitations](data-sources.md).
49
+
50
+ ## Seed PostgreSQL
51
+
52
+ Export normalized JSON, NDJSON, or CSV, then preview before applying:
53
+
54
+ ```sh
55
+ node dist/cli.js export --snapshot data/example.sqlite --format ndjson --coordinates --output exports/seed
56
+ node dist/cli.js seed --package exports/seed --create-schema
57
+ node dist/cli.js seed --package exports/seed --create-schema --apply
58
+ ```
59
+
60
+ Set `DATABASE_URL` in your shell or secret manager before running the seed commands. Do not put credentials in tracked files or exported packages. The commands above target the standard schema; existing application tables require an explicit mapping. See [seeding](seeding.md) for revision ordering, field ownership, and recovery.
61
+
62
+ ## Optional SDK
63
+
64
+ Only applications that want the local snapshot query API need to install the library with `npm install georeference`. You can also build and install a local archive with `npm pack` and `npm install /path/to/georeference-1.0.0.tgz`. File generation needs no such installation.
65
+
66
+ ```ts
67
+ import { Snapshot, createClient } from 'georeference';
68
+
69
+ const snapshot = Snapshot.open('data/example.sqlite');
70
+ try {
71
+ const client = createClient(snapshot);
72
+ console.log(client.getEntity('example:locality'));
73
+ console.log(client.getCountry('example:country'));
74
+ } finally {
75
+ snapshot.close();
76
+ }
77
+ ```
78
+
79
+ The SDK reads the local snapshot and does not synchronize an application database. Keep the snapshot open while iterating and close it when finished. Install the compiled package with `npm install georeference`, or build/install it from this repository.
@@ -0,0 +1,71 @@
1
+ # Import et amorçage PostgreSQL
2
+
3
+ [English](seeding.md) · [Accueil](../README.fr.md)
4
+
5
+ ## Aperçu puis application
6
+
7
+ Le seeder lit des paquets GeoReference normalisés et vérifiés, pas du SQL téléchargé arbitrairement. Utilisez JSON, NDJSON ou le profil machine CSV. Le CSV transformé pour tableur, les couches GeoJSON, les scripts SQL et les fichiers SQLite exportés ne constituent pas des entrées interchangeables pour le seeder. Les imports V1 sont bornés à 128 Mio décompressés et 500 000 entités ; scindez les plus grands jeux en paquets géographiques mesurés. Gzip est lu directement ; ZIP doit être extrait avec son manifeste interne dans un nouveau répertoire.
8
+
9
+ Définissez `DATABASE_URL` hors des fichiers suivis. Pour la table GeoReference standard :
10
+
11
+ ```sh
12
+ node dist/cli.js seed --package exports/seed --create-schema
13
+ node dist/cli.js seed --package exports/seed --create-schema --apply
14
+ ```
15
+
16
+ Sans `--apply`, la commande produit un plan en lecture seule. `--create-schema` permet de créer les objets standards lors de l'application ; cela n'autorise pas à modifier arbitrairement les schémas existants. La cible par défaut est `public.georeference_entities`.
17
+
18
+ ## Mises à jour et identité stable
19
+
20
+ - `--mode upsert`, par défaut, crée les lignes manquantes et actualise les champs gérés réellement présents. La source est prioritaire pour ces champs ; examinez cette politique si vous avez modifié localement le référentiel.
21
+ - Les champs facultatifs absents sont préservés. Coordonnées/frontières ne sont gérées que si le paquet les demandait. Un null explicite n'a pas le même sens qu'un champ absent.
22
+ - `--mode insert-only` ajoute les nouvelles entités, ignore les modifications des lignes existantes et signale les conflits. Aucun de ces modes ne supprime une entité absente du paquet.
23
+ - Rejouer le même contenu laisse les lignes inchangées intactes, sans doublons ni mises à jour artificielles simplement parce qu'un nouvel import est lancé.
24
+ - Les relations se résolvent par identité stable ; les parents nécessaires doivent être présents dans le paquet ou dans la cible. Un parent externe doit être un pays/une subdivision compatible, jamais une localité. Un export géographique partiel ne prouve jamais qu'une entité absente doit être supprimée.
25
+ - En insert-only, les nouveaux enfants sont validés contre les parents réellement conservés en cible lorsque leurs mises à jour sont ignorées. Un UPSERT partiel ne peut déplacer un parent vers un autre pays ou changer son type si des enfants conservés deviennent incohérents ; incluez le sous-arbre concerné dans la mise à jour.
26
+
27
+ Le seeder applique la priorité à la source pour les champs gérés. Fusion automatique des modifications locales, migrations, synchronisation destructive et mappings universels d'ORM restent hors V1.
28
+
29
+ ## Ordonner explicitement les nouvelles révisions
30
+
31
+ Les versions de données sont opaques : `release-b` ne se compare pas de façon fiable à `2026.11`. Le premier import utilise la révision `0` par défaut. Un jeu/paquet modifié exige une révision entière explicite strictement supérieure :
32
+
33
+ ```sh
34
+ node dist/cli.js seed --package exports/updated-seed --revision 1 --apply
35
+ ```
36
+
37
+ Les révisions inférieures/égales en conflit sont refusées. `--allow-downgrade` constitue une dérogation explicite, pas une reprise par défaut. Conservez la même révision pour reprendre le même import interrompu.
38
+
39
+ ## Préserver les clés applicatives existantes
40
+
41
+ Utilisez `--mapping path/to/mapping.json` pour mapper les champs canoniques vers les colonnes prises en charge de votre table. Exemple :
42
+
43
+ ```json
44
+ {
45
+ "schema": "public",
46
+ "table": "places",
47
+ "localIdColumn": "id",
48
+ "columns": {
49
+ "id": "georeference_id",
50
+ "entityType": "entity_type",
51
+ "countryId": "country_id",
52
+ "parentId": "parent_id"
53
+ }
54
+ }
55
+ ```
56
+
57
+ Ici, `id` est une clé primaire entière serial/identity existante, et `georeference_id` l'identifiant stable sous forme de chaîne. Son unicité doit être imposée par une vraie clé primaire ou contrainte/index UNIQUE non partiel à une seule colonne ; une déclaration de mapping ou une clé unique composite ne suffit pas. Le seeder préserve les IDs locaux et les utilise pour les relations ; il ne remplace pas les clés de l'application. Les autres colonnes gérées doivent avoir des noms/types compatibles ou un mapping explicite. Préservez les champs métier et fournissez leurs valeurs par défaut obligatoires. Le mapping V1 couvre les clés entières serial/identity, pas tous les schémas personnalisés/composites.
58
+
59
+ ## Transactions, reprise et visibilité
60
+
61
+ `--batch-size` borne chaque lot (`500` par défaut). Un lot et son curseur de reprise sont commités ensemble. Une erreur ultérieure peut laisser visibles des lots précédents ; l'import entier ne constitue pas une publication atomique. Relancez le même paquet avec les mêmes mapping, mode, révision et taille de lot pour reprendre. Un import terminé rejoué compare à nouveau les lignes et préserve les valeurs inchangées.
62
+
63
+ Un import interrompu doit se terminer avec les mêmes paquet, mapping, mode et taille de lot avant qu'un autre import commence sur cette cible. Ne changez pas de paquet ou de mapping pour contourner un curseur de reprise en attente.
64
+
65
+ Un verrou consultatif sérialise les imports vers la même cible. Les utilisateurs de la bibliothèque doivent fournir une **connexion/session dédiée**, pas un pool susceptible de changer de session entre les requêtes. La CLI ouvre un client PostgreSQL dédié. Un point de reprise n'est valable qu'après commit de sa transaction.
66
+
67
+ Manifestes et empreintes détectent corruption et fichiers manquants ; ils ne constituent pas une signature garantissant l'identité de l'émetteur. Examinez provenance et mapping, puis utilisez l'aperçu avant d'appliquer un paquet à une base existante.
68
+
69
+ ## Périmètre de validation
70
+
71
+ Les tests exercent la sémantique PostgreSQL via PGlite et comprennent un test d'intégration `pg` activé par `DATABASE_URL`. La CI fournit un service PostgreSQL pour ce parcours. Un test de service sauté/non exécuté ne prouve pas la compatibilité d'une version serveur ; consultez le résultat CI exact de la révision utilisée.
@@ -0,0 +1,71 @@
1
+ # PostgreSQL import and seeding
2
+
3
+ [Français](seeding.fr.md) · [Home](../README.md)
4
+
5
+ ## Preview, then apply
6
+
7
+ The seeder reads verified, normalized GeoReference packages, not arbitrary downloaded SQL. Use JSON, NDJSON, or the machine-profile CSV. Spreadsheet-transformed CSV, GeoJSON layers, SQL scripts, and SQLite export files are not interchangeable seeder inputs. V1 package imports are bounded to 128 MiB of uncompressed data and 500,000 records; split larger imports into measured geographic packages. Gzip is read directly; ZIP must first be extracted with its inner manifest into a new directory.
8
+
9
+ Set `DATABASE_URL` outside tracked files. For the standard GeoReference table:
10
+
11
+ ```sh
12
+ node dist/cli.js seed --package exports/seed --create-schema
13
+ node dist/cli.js seed --package exports/seed --create-schema --apply
14
+ ```
15
+
16
+ Without `--apply`, the command produces a read-only plan. `--create-schema` allows creation of the standard objects when applying; it is not permission to alter arbitrary existing application schemas. The default target is `public.georeference_entities`.
17
+
18
+ ## Updates and stable identity
19
+
20
+ - Default `--mode upsert` creates missing records and updates source-managed fields that are actually present. Source values win for those fields; review this policy before importing locally edited reference fields.
21
+ - Optional fields absent from input are preserved. Coordinates/boundaries are managed only when the package requested them. An explicit null and an absent field have different meanings.
22
+ - `--mode insert-only` creates new records, skips changes to existing records, and reports conflicts. Neither mode deletes entities absent from the package.
23
+ - Replaying identical content leaves unchanged rows unchanged. It must not produce duplicates or artificial updates merely because a new import run occurred.
24
+ - Foreign keys are resolved through stable identities; required parents must be in the package or already present in the target. An external parent must be a compatible country/subdivision, never a locality. A partial geographic export is never evidence that absent entities should be removed.
25
+ - Insert-only validates new children against the existing parents actually retained when incoming parent updates are skipped. A partial UPSERT cannot move a parent to another country or change its type if retained target children would become inconsistent; include the affected subtree in the update.
26
+
27
+ The seeder uses **source-wins** for managed fields. Automatic merging of local edits, migrations, destructive synchronization, and universal ORM mappings are outside V1.
28
+
29
+ ## Order new dataset revisions explicitly
30
+
31
+ Dataset version labels are opaque: `release-b` cannot be reliably compared with `2026.11`. The first import defaults to revision `0`. A changed dataset/package requires a strictly higher explicit integer revision:
32
+
33
+ ```sh
34
+ node dist/cli.js seed --package exports/updated-seed --revision 1 --apply
35
+ ```
36
+
37
+ Older/equal conflicting revisions are rejected. `--allow-downgrade` is an explicit override, not a default recovery mechanism. Preserve the same revision when resuming the same interrupted import.
38
+
39
+ ## Existing application keys
40
+
41
+ Use `--mapping path/to/mapping.json` for a supported mapping of canonical fields to your existing columns. For example:
42
+
43
+ ```json
44
+ {
45
+ "schema": "public",
46
+ "table": "places",
47
+ "localIdColumn": "id",
48
+ "columns": {
49
+ "id": "georeference_id",
50
+ "entityType": "entity_type",
51
+ "countryId": "country_id",
52
+ "parentId": "parent_id"
53
+ }
54
+ }
55
+ ```
56
+
57
+ Here `id` is an existing integer serial/identity primary key, while `georeference_id` is the stable string identifier. Its uniqueness must be enforced by a real, non-partial, single-column PRIMARY KEY or UNIQUE constraint/index; a mapping declaration or a composite unique key does not suffice. The seeder preserves local IDs and maps relationships to them; it does not replace the application's primary keys. Other managed columns must have compatible names/types or explicit mappings. Preserve unrelated business columns and supply their required defaults yourself. V1's local-key mapping supports integer serial/identity keys, not every custom/composite key design.
58
+
59
+ ## Transactions, recovery, and visibility
60
+
61
+ `--batch-size` bounds each batch (default `500`). Each batch and its recovery cursor commit together. A later failure may leave earlier batches visible; the entire import is not one atomic publication. Rerun the same package, mapping, mode, revision, and batch size to resume. A completed replay performs comparisons again so unchanged records remain unchanged.
62
+
63
+ An interrupted import must finish with the same package, mapping, mode, and batch size before a different import can start on that target. Do not switch packages or mappings to bypass a pending recovery cursor.
64
+
65
+ An advisory lock serializes imports for the same target. Library callers must supply a **dedicated connection/session**, not a pool that can switch sessions between queries. The CLI opens a dedicated PostgreSQL client. A checkpoint is useful only after its transaction has committed.
66
+
67
+ Manifests and checksums detect corruption and missing files; they are not a signature proving the sender's identity. Review provenance and mappings, and use the dry-run before applying a package to an existing application.
68
+
69
+ ## Validation scope
70
+
71
+ The test suite exercises PostgreSQL semantics using PGlite and includes a `pg` integration test selected by `DATABASE_URL`. CI provisions a PostgreSQL service for that integration path. An unexecuted/skipped service test is not a tested server-version claim; consult the actual CI result for the revision being used.
@@ -0,0 +1,7 @@
1
+ # Synthetic example / Exemple fictif
2
+
3
+ `sample.ndjson` and `metadata.json` describe a fictional country, two administrative levels, and one locality. Names, codes, coordinates, and the square boundary are test/demo values; they are not a real geographic reference. Both files are licensed under the repository's MIT license.
4
+
5
+ `sample.ndjson` et `metadata.json` décrivent un pays fictif, deux niveaux administratifs et une localité. Les noms, codes, coordonnées et la frontière carrée servent à la démonstration ; ils ne constituent pas un référentiel géographique réel. Ces deux fichiers sont distribués sous la licence MIT du dépôt.
6
+
7
+ Run the commands in the [English guide](../docs/getting-started.md) or [guide français](../docs/getting-started.fr.md). Generated snapshots and export directories are intentionally ignored by Git.
@@ -0,0 +1,13 @@
1
+ {
2
+ "contractVersion": "1.0",
3
+ "datasetVersion": "example-1",
4
+ "sources": [
5
+ {
6
+ "name": "GeoReference synthetic example",
7
+ "url": "https://example.invalid/georeference-fixture",
8
+ "license": "MIT",
9
+ "attribution": "Synthetic example by GeoReference contributors; not real geographic data.",
10
+ "revision": "fixture-1"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,4 @@
1
+ {"id":"example:country","entityType":"country","name":"Example Republic","countryId":"example:country","parentId":null,"codes":{"iso2":"XZ","iso3":"XZZ"},"names":{"en":"Example Republic","fr":"République exemple"},"boundary":{"type":"Polygon","coordinates":[[[10,0],[12,0],[12,2],[10,2],[10,0]]]}}
2
+ {"id":"example:region","entityType":"subdivision","name":"Northern Region","countryId":"example:country","parentId":"example:country","level":1,"names":{"en":"Northern Region","fr":"Région du Nord"}}
3
+ {"id":"example:district","entityType":"subdivision","name":"River District","countryId":"example:country","parentId":"example:region","level":2}
4
+ {"id":"example:locality","entityType":"locality","name":"Harbor d'Été","countryId":"example:country","parentId":"example:district","coordinates":{"longitude":11,"latitude":1}}
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "georeference",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "Versioned geographic datasets, portable exports and repeatable database seeding.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "registry": "https://registry.npmjs.org/"
10
+ },
11
+ "author": "Osiris Balonga",
12
+ "engines": {
13
+ "node": ">=24.18.0 <25"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": "./dist/index.js",
19
+ "./seeding": "./dist/seeding/index.js"
20
+ },
21
+ "bin": {
22
+ "georeference": "./dist/cli.js"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "README.fr.md",
28
+ "CONTRIBUTING.md",
29
+ "CONTRIBUTING.fr.md",
30
+ "SECURITY.md",
31
+ "SECURITY.fr.md",
32
+ "CHANGELOG.md",
33
+ "LICENSE",
34
+ "docs",
35
+ "examples"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.json",
39
+ "typecheck": "tsc --noEmit -p tsconfig.json",
40
+ "test": "node --test tests/*.test.ts",
41
+ "test:postgres": "node --test tests/postgres.integration.test.ts",
42
+ "check": "npm run typecheck && npm test && npm run build",
43
+ "prepack": "npm run build"
44
+ },
45
+ "dependencies": {
46
+ "csv-parse": "^7.0.3",
47
+ "csv-stringify": "^6.6.0",
48
+ "pg": "^8.16.3",
49
+ "yazl": "^3.3.1"
50
+ },
51
+ "devDependencies": {
52
+ "@electric-sql/pglite": "^0.3.14",
53
+ "@types/node": "^24.10.0",
54
+ "@types/pg": "^8.15.6",
55
+ "@types/yazl": "^3.3.0",
56
+ "typescript": "^5.9.3"
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/Osiris-Balonga/georeference.git"
61
+ },
62
+ "bugs": {
63
+ "url": "https://github.com/Osiris-Balonga/georeference/issues"
64
+ },
65
+ "homepage": "https://github.com/Osiris-Balonga/georeference#readme"
66
+ }