@altura_ma/onemcp 0.2.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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +176 -0
  3. package/dist/cache/index.d.ts +12 -0
  4. package/dist/cache/index.d.ts.map +1 -0
  5. package/dist/cache/index.js +44 -0
  6. package/dist/cache/index.js.map +1 -0
  7. package/dist/connectors/ban.d.ts +15 -0
  8. package/dist/connectors/ban.d.ts.map +1 -0
  9. package/dist/connectors/ban.js +46 -0
  10. package/dist/connectors/ban.js.map +1 -0
  11. package/dist/connectors/base.d.ts +18 -0
  12. package/dist/connectors/base.d.ts.map +1 -0
  13. package/dist/connectors/base.js +10 -0
  14. package/dist/connectors/base.js.map +1 -0
  15. package/dist/connectors/bodacc.d.ts +11 -0
  16. package/dist/connectors/bodacc.d.ts.map +1 -0
  17. package/dist/connectors/bodacc.js +47 -0
  18. package/dist/connectors/bodacc.js.map +1 -0
  19. package/dist/connectors/companies-house.d.ts +13 -0
  20. package/dist/connectors/companies-house.d.ts.map +1 -0
  21. package/dist/connectors/companies-house.js +104 -0
  22. package/dist/connectors/companies-house.js.map +1 -0
  23. package/dist/connectors/dvf.d.ts +13 -0
  24. package/dist/connectors/dvf.d.ts.map +1 -0
  25. package/dist/connectors/dvf.js +51 -0
  26. package/dist/connectors/dvf.js.map +1 -0
  27. package/dist/connectors/epo-ops.d.ts +37 -0
  28. package/dist/connectors/epo-ops.d.ts.map +1 -0
  29. package/dist/connectors/epo-ops.js +100 -0
  30. package/dist/connectors/epo-ops.js.map +1 -0
  31. package/dist/connectors/france-travail.d.ts +47 -0
  32. package/dist/connectors/france-travail.d.ts.map +1 -0
  33. package/dist/connectors/france-travail.js +89 -0
  34. package/dist/connectors/france-travail.js.map +1 -0
  35. package/dist/connectors/georisques.d.ts +7 -0
  36. package/dist/connectors/georisques.d.ts.map +1 -0
  37. package/dist/connectors/georisques.js +68 -0
  38. package/dist/connectors/georisques.js.map +1 -0
  39. package/dist/connectors/gleif.d.ts +9 -0
  40. package/dist/connectors/gleif.d.ts.map +1 -0
  41. package/dist/connectors/gleif.js +63 -0
  42. package/dist/connectors/gleif.js.map +1 -0
  43. package/dist/connectors/index.d.ts +29 -0
  44. package/dist/connectors/index.d.ts.map +1 -0
  45. package/dist/connectors/index.js +28 -0
  46. package/dist/connectors/index.js.map +1 -0
  47. package/dist/connectors/inpi-rne.d.ts +19 -0
  48. package/dist/connectors/inpi-rne.d.ts.map +1 -0
  49. package/dist/connectors/inpi-rne.js +107 -0
  50. package/dist/connectors/inpi-rne.js.map +1 -0
  51. package/dist/connectors/insee-sirene.d.ts +12 -0
  52. package/dist/connectors/insee-sirene.d.ts.map +1 -0
  53. package/dist/connectors/insee-sirene.js +104 -0
  54. package/dist/connectors/insee-sirene.js.map +1 -0
  55. package/dist/connectors/recherche-entreprises.d.ts +20 -0
  56. package/dist/connectors/recherche-entreprises.d.ts.map +1 -0
  57. package/dist/connectors/recherche-entreprises.js +135 -0
  58. package/dist/connectors/recherche-entreprises.js.map +1 -0
  59. package/dist/connectors/vies.d.ts +10 -0
  60. package/dist/connectors/vies.d.ts.map +1 -0
  61. package/dist/connectors/vies.js +39 -0
  62. package/dist/connectors/vies.js.map +1 -0
  63. package/dist/http.d.ts +3 -0
  64. package/dist/http.d.ts.map +1 -0
  65. package/dist/http.js +74 -0
  66. package/dist/http.js.map +1 -0
  67. package/dist/index.d.ts +3 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +16 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/schemas/canonical.d.ts +1545 -0
  72. package/dist/schemas/canonical.d.ts.map +1 -0
  73. package/dist/schemas/canonical.js +120 -0
  74. package/dist/schemas/canonical.js.map +1 -0
  75. package/dist/server.d.ts +6 -0
  76. package/dist/server.d.ts.map +1 -0
  77. package/dist/server.js +126 -0
  78. package/dist/server.js.map +1 -0
  79. package/dist/tools/company-layer2.d.ts +3 -0
  80. package/dist/tools/company-layer2.d.ts.map +1 -0
  81. package/dist/tools/company-layer2.js +84 -0
  82. package/dist/tools/company-layer2.js.map +1 -0
  83. package/dist/tools/company.d.ts +3 -0
  84. package/dist/tools/company.d.ts.map +1 -0
  85. package/dist/tools/company.js +119 -0
  86. package/dist/tools/company.js.map +1 -0
  87. package/dist/tools/geo.d.ts +3 -0
  88. package/dist/tools/geo.d.ts.map +1 -0
  89. package/dist/tools/geo.js +59 -0
  90. package/dist/tools/geo.js.map +1 -0
  91. package/dist/tools/identity.d.ts +3 -0
  92. package/dist/tools/identity.d.ts.map +1 -0
  93. package/dist/tools/identity.js +60 -0
  94. package/dist/tools/identity.js.map +1 -0
  95. package/dist/tools/index.d.ts +14 -0
  96. package/dist/tools/index.d.ts.map +1 -0
  97. package/dist/tools/index.js +22 -0
  98. package/dist/tools/index.js.map +1 -0
  99. package/dist/tools/jobs.d.ts +3 -0
  100. package/dist/tools/jobs.d.ts.map +1 -0
  101. package/dist/tools/jobs.js +63 -0
  102. package/dist/tools/jobs.js.map +1 -0
  103. package/dist/tools/legal.d.ts +3 -0
  104. package/dist/tools/legal.d.ts.map +1 -0
  105. package/dist/tools/legal.js +48 -0
  106. package/dist/tools/legal.js.map +1 -0
  107. package/dist/tools/patents.d.ts +3 -0
  108. package/dist/tools/patents.d.ts.map +1 -0
  109. package/dist/tools/patents.js +51 -0
  110. package/dist/tools/patents.js.map +1 -0
  111. package/dist/tools/realestate.d.ts +3 -0
  112. package/dist/tools/realestate.d.ts.map +1 -0
  113. package/dist/tools/realestate.js +30 -0
  114. package/dist/tools/realestate.js.map +1 -0
  115. package/dist/tools/sources.d.ts +3 -0
  116. package/dist/tools/sources.d.ts.map +1 -0
  117. package/dist/tools/sources.js +17 -0
  118. package/dist/tools/sources.js.map +1 -0
  119. package/dist/tools/types.d.ts +10 -0
  120. package/dist/tools/types.d.ts.map +1 -0
  121. package/dist/tools/types.js +4 -0
  122. package/dist/tools/types.js.map +1 -0
  123. package/dist/utils/env.d.ts +3 -0
  124. package/dist/utils/env.d.ts.map +1 -0
  125. package/dist/utils/env.js +14 -0
  126. package/dist/utils/env.js.map +1 -0
  127. package/dist/utils/http.d.ts +17 -0
  128. package/dist/utils/http.d.ts.map +1 -0
  129. package/dist/utils/http.js +62 -0
  130. package/dist/utils/http.js.map +1 -0
  131. package/dist/utils/oauth.d.ts +11 -0
  132. package/dist/utils/oauth.d.ts.map +1 -0
  133. package/dist/utils/oauth.js +31 -0
  134. package/dist/utils/oauth.js.map +1 -0
  135. package/dist/worker.d.ts +16 -0
  136. package/dist/worker.d.ts.map +1 -0
  137. package/dist/worker.js +185 -0
  138. package/dist/worker.js.map +1 -0
  139. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 money-maker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # OneMCP
2
+
3
+ > Serveur MCP unifié pour les données business publiques France & Europe.
4
+ > Un seul connecteur, des dizaines de sources officielles, agrégation gratuite (sources sans auth) ou avec vos clés.
5
+ > 🌐 [onemcp.fr](https://onemcp.fr)
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+ [![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)]()
9
+
10
+ ## Pourquoi
11
+
12
+ Les agents IA ont besoin de données business françaises fiables. Aujourd'hui :
13
+ - Pappers, SocieteInfo, Infonet sont **payants** et juste des wrappers de l'open data public.
14
+ - Les APIs officielles (INSEE, INPI, BODACC, BAN, etc.) sont **gratuites** mais éclatées, formats hétérogènes, OAuth différents.
15
+
16
+ **Ce serveur agrège tout ça en un seul connecteur MCP avec un schéma canonique unique.**
17
+
18
+ ## Sources couvertes (v0.1 — Layer 1, sans auth)
19
+
20
+ | Source | Type | Licence |
21
+ |---|---|---|
22
+ | **Recherche d'entreprises (DINUM)** | SIREN/SIRET, dirigeants, finances, BE | Licence Ouverte 2.0 |
23
+ | **BODACC** | Annonces légales, procédures collectives | Licence Ouverte 2.0 |
24
+ | **BAN** | Géocodage adresses françaises | Licence Ouverte 2.0 / ODbL |
25
+ | **Géorisques** | Risques naturels/technologiques par adresse | Licence Ouverte 2.0 |
26
+ | **DVF** | Transactions immobilières (5 ans) | Licence Ouverte 2.0 |
27
+ | **VIES (UE)** | Validation TVA intracommunautaire | Données publiques EU |
28
+ | **GLEIF** | Identifiants LEI mondiaux | CC0 1.0 |
29
+
30
+ ## Tools MCP exposés
31
+
32
+ Groupés par domaine (13 tools) :
33
+
34
+ **Entreprise**
35
+ - `company_search` — recherche full-text (nom, dirigeant, SIREN, NAF, dépt)
36
+ - `company_get` — fiche complète par SIREN/SIRET
37
+ - `company_enrich` — fiche + annonces légales + risques + LEI
38
+
39
+ **Légal**
40
+ - `legal_announcements_search` — annonces BODACC par SIREN ou nom
41
+ - `legal_procedures_check` — procédures collectives en cours
42
+
43
+ **Géo**
44
+ - `address_search` — géocodage texte → coordonnées
45
+ - `address_reverse` — coordonnées → adresse
46
+ - `address_risks` — risques majeurs à une adresse
47
+
48
+ **Immobilier**
49
+ - `realestate_transactions` — transactions DVF par commune ou code postal
50
+
51
+ **Identité**
52
+ - `vat_validate` — validation TVA UE (VIES)
53
+ - `lei_lookup` — fiche LEI par code
54
+ - `lei_search` — recherche LEI par nom
55
+
56
+ **Méta**
57
+ - `sources_list` — toutes les sources et leurs licences
58
+
59
+ ## Installation
60
+
61
+ ### Claude Desktop / Claude Code (stdio local)
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "business-fr": {
67
+ "command": "npx",
68
+ "args": ["-y", "@altura_ma/mcp-business-fr"]
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ Fichiers de config :
75
+ - macOS : `~/Library/Application Support/Claude/claude_desktop_config.json`
76
+ - Windows : `%APPDATA%\Claude\claude_desktop_config.json`
77
+ - Claude Code : `claude mcp add business-fr -- npx -y @altura_ma/mcp-business-fr`
78
+
79
+ ### Cursor
80
+
81
+ `.cursor/mcp.json` :
82
+
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "business-fr": {
87
+ "command": "npx",
88
+ "args": ["-y", "@altura_ma/mcp-business-fr"]
89
+ }
90
+ }
91
+ }
92
+ ```
93
+
94
+ ### Mode hébergé (Streamable HTTP)
95
+
96
+ ```json
97
+ {
98
+ "mcpServers": {
99
+ "business-fr": {
100
+ "url": "https://mcp.business-fr.dev/mcp",
101
+ "headers": {
102
+ "Authorization": "Bearer mk_xxx"
103
+ }
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## Développement
110
+
111
+ ```bash
112
+ git clone <repo>
113
+ cd money-maker
114
+ npm install
115
+ npm run build
116
+ npm test
117
+
118
+ # Local dev avec stdio
119
+ npm run dev
120
+
121
+ # HTTP mode (Streamable HTTP)
122
+ PORT=3000 npm run start:http
123
+
124
+ # Inspector officiel pour tester les tools
125
+ npm run inspector
126
+ ```
127
+
128
+ ## Schéma canonique
129
+
130
+ Toutes les réponses retournent un format normalisé avec champ `provenance` :
131
+
132
+ ```ts
133
+ {
134
+ siren: "552032534",
135
+ legal_name: "ANTHROPIC",
136
+ active: true,
137
+ headquarter: { siret, address: { ... } },
138
+ officers: [...],
139
+ financials: [...],
140
+ provenance: [
141
+ {
142
+ source: "recherche-entreprises",
143
+ source_url: "...",
144
+ fetched_at: "2026-05-06T22:00:00Z",
145
+ license: "Licence Ouverte 2.0 (Etalab)"
146
+ }
147
+ ],
148
+ _raw: { ... } // données brutes de la source
149
+ }
150
+ ```
151
+
152
+ ## Architecture
153
+
154
+ Voir [`docs/architecture.md`](docs/architecture.md).
155
+
156
+ ## Monétisation
157
+
158
+ Voir [`docs/monetization.md`](docs/monetization.md).
159
+
160
+ ## Conformité
161
+
162
+ - **RGPD** : ce serveur n'expose que des données publiques. Les données personnelles (dirigeants) sont systématiquement minimisées (date de naissance tronquée à `YYYY-MM`). Documenter votre base légale (intérêt légitime) et l'origine des données auprès des personnes concernées (RGPD Art. 14).
163
+ - **Licences sources** : préservées dans chaque réponse (champ `provenance.license`). Mention obligatoire dans toute réutilisation.
164
+
165
+ ## Roadmap
166
+
167
+ - [ ] **Layer 2** : connecteurs avec auth (INSEE Sirene, INPI RNE, PISTE/Légifrance, France Travail, Companies House UK, EPO Patents)
168
+ - [ ] **Layer 3** : registres EU (KBO Belgique, Handelsregister DE, KVK NL, BORME ES)
169
+ - [ ] **Mode hébergé multi-tenant** sur Cloudflare Workers + Durable Objects
170
+ - [ ] **Auth & billing** : API keys, Stripe metering
171
+ - [ ] **OAuth 2.1** pour clients enterprise
172
+ - [ ] **Distribution** : Smithery, mcp.so, PulseMCP, npm
173
+
174
+ ## Licence
175
+
176
+ MIT.
@@ -0,0 +1,12 @@
1
+ export declare class MemoryCache {
2
+ private readonly store;
3
+ private readonly maxEntries;
4
+ constructor(maxEntries?: number);
5
+ get<T>(key: string): T | undefined;
6
+ set<T>(key: string, value: T, ttlSeconds: number): void;
7
+ wrap<T>(key: string, ttlSeconds: number, fn: () => Promise<T>): Promise<T>;
8
+ clear(): void;
9
+ size(): number;
10
+ }
11
+ export declare const cache: MemoryCache;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAKA,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,UAAU,SAAO;IAI7B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAUlC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAWjD,IAAI,CAAC,CAAC,EACV,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC;IAQb,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,MAAM;CAGf;AAED,eAAO,MAAM,KAAK,aAAoB,CAAC"}
@@ -0,0 +1,44 @@
1
+ export class MemoryCache {
2
+ store = new Map();
3
+ maxEntries;
4
+ constructor(maxEntries = 5000) {
5
+ this.maxEntries = maxEntries;
6
+ }
7
+ get(key) {
8
+ const entry = this.store.get(key);
9
+ if (!entry)
10
+ return undefined;
11
+ if (entry.expiresAt < Date.now()) {
12
+ this.store.delete(key);
13
+ return undefined;
14
+ }
15
+ return entry.value;
16
+ }
17
+ set(key, value, ttlSeconds) {
18
+ if (this.store.size >= this.maxEntries) {
19
+ const oldest = this.store.keys().next().value;
20
+ if (oldest !== undefined)
21
+ this.store.delete(oldest);
22
+ }
23
+ this.store.set(key, {
24
+ value,
25
+ expiresAt: Date.now() + ttlSeconds * 1000,
26
+ });
27
+ }
28
+ async wrap(key, ttlSeconds, fn) {
29
+ const cached = this.get(key);
30
+ if (cached !== undefined)
31
+ return cached;
32
+ const value = await fn();
33
+ this.set(key, value, ttlSeconds);
34
+ return value;
35
+ }
36
+ clear() {
37
+ this.store.clear();
38
+ }
39
+ size() {
40
+ return this.store.size;
41
+ }
42
+ }
43
+ export const cache = new MemoryCache();
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,WAAW;IACL,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC/C,UAAU,CAAS;IAEpC,YAAY,UAAU,GAAG,IAAI;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAU,CAAC;IAC1B,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,KAAQ,EAAE,UAAkB;QAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC9C,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CACR,GAAW,EACX,UAAkB,EAClB,EAAoB;QAEpB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAI,GAAG,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Address, Provenance } from "../schemas/canonical.js";
2
+ import { Connector, type ConnectorMetadata } from "./base.js";
3
+ export interface BanResult extends Address {
4
+ score: number;
5
+ label: string;
6
+ type?: string;
7
+ provenance: Provenance[];
8
+ }
9
+ export declare class BanConnector extends Connector {
10
+ readonly metadata: ConnectorMetadata;
11
+ search(query: string, limit?: number): Promise<BanResult[]>;
12
+ reverse(latitude: number, longitude: number): Promise<BanResult[]>;
13
+ private normalize;
14
+ }
15
+ //# sourceMappingURL=ban.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ban.d.ts","sourceRoot":"","sources":["../../src/connectors/ban.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAwB9D,MAAM,WAAW,SAAU,SAAQ,OAAO;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B;AAED,qBAAa,YAAa,SAAQ,SAAS;IACzC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAQlC;IAEI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMtD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMxE,OAAO,CAAC,SAAS;CAsBlB"}
@@ -0,0 +1,46 @@
1
+ import { Connector } from "./base.js";
2
+ const BASE_URL = "https://api-adresse.data.gouv.fr";
3
+ export class BanConnector extends Connector {
4
+ metadata = {
5
+ id: "ban",
6
+ name: "Base Adresse Nationale (BAN)",
7
+ description: "Géocodage et recherche d'adresses françaises (référentiel officiel).",
8
+ source: "https://adresse.data.gouv.fr",
9
+ license: "Licence Ouverte 2.0 (Etalab) / ODbL",
10
+ authRequired: false,
11
+ defaultTtlSeconds: 86400 * 7,
12
+ };
13
+ async search(query, limit = 5) {
14
+ const url = `${BASE_URL}/search/?q=${encodeURIComponent(query)}&limit=${limit}`;
15
+ const data = await this.getJson(url);
16
+ return data.features.map((f) => this.normalize(f, url));
17
+ }
18
+ async reverse(latitude, longitude) {
19
+ const url = `${BASE_URL}/reverse/?lat=${latitude}&lon=${longitude}`;
20
+ const data = await this.getJson(url);
21
+ return data.features.map((f) => this.normalize(f, url));
22
+ }
23
+ normalize(f, url) {
24
+ const provenance = {
25
+ source: this.metadata.id,
26
+ source_url: url,
27
+ fetched_at: new Date().toISOString(),
28
+ license: this.metadata.license,
29
+ };
30
+ return {
31
+ label: f.properties.label,
32
+ score: f.properties.score,
33
+ type: f.properties.type,
34
+ full: f.properties.label,
35
+ street: [f.properties.housenumber, f.properties.street].filter(Boolean).join(" ") || undefined,
36
+ postal_code: f.properties.postcode,
37
+ city: f.properties.city,
38
+ insee_code: f.properties.citycode,
39
+ country: "FR",
40
+ latitude: f.geometry.coordinates[1],
41
+ longitude: f.geometry.coordinates[0],
42
+ provenance: [provenance],
43
+ };
44
+ }
45
+ }
46
+ //# sourceMappingURL=ban.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ban.js","sourceRoot":"","sources":["../../src/connectors/ban.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAA0B,MAAM,WAAW,CAAC;AAE9D,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AA6BpD,MAAM,OAAO,YAAa,SAAQ,SAAS;IAChC,QAAQ,GAAsB;QACrC,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,8BAA8B;QACpC,WAAW,EAAE,sEAAsE;QACnF,MAAM,EAAE,8BAA8B;QACtC,OAAO,EAAE,qCAAqC;QAC9C,YAAY,EAAE,KAAK;QACnB,iBAAiB,EAAE,KAAK,GAAG,CAAC;KAC7B,CAAC;IAEF,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,KAAK,GAAG,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,QAAQ,cAAc,kBAAkB,CAAC,KAAK,CAAC,UAAU,KAAK,EAAE,CAAC;QAChF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAiB,GAAG,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,SAAiB;QAC/C,MAAM,GAAG,GAAG,GAAG,QAAQ,iBAAiB,QAAQ,QAAQ,SAAS,EAAE,CAAC;QACpE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAiB,GAAG,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAEO,SAAS,CAAC,CAAa,EAAE,GAAW;QAC1C,MAAM,UAAU,GAAe;YAC7B,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;YACxB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;SAC/B,CAAC;QACF,OAAO;YACL,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK;YACzB,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK;YACzB,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI;YACvB,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK;YACxB,MAAM,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS;YAC9F,WAAW,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ;YAClC,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI;YACvB,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ;YACjC,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;YACnC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;YACpC,UAAU,EAAE,CAAC,UAAU,CAAC;SACzB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ export interface ConnectorMetadata {
2
+ readonly id: string;
3
+ readonly name: string;
4
+ readonly description: string;
5
+ readonly source: string;
6
+ readonly license: string;
7
+ readonly authRequired: boolean;
8
+ readonly defaultTtlSeconds: number;
9
+ }
10
+ export declare abstract class Connector {
11
+ abstract readonly metadata: ConnectorMetadata;
12
+ protected getJson<T>(url: string, options?: {
13
+ headers?: Record<string, string>;
14
+ ttlSeconds?: number;
15
+ cacheKey?: string;
16
+ }): Promise<T>;
17
+ }
18
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/connectors/base.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED,8BAAsB,SAAS;IAC7B,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;cAE9B,OAAO,CAAC,CAAC,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACd,GACL,OAAO,CAAC,CAAC,CAAC;CAOd"}
@@ -0,0 +1,10 @@
1
+ import { cache } from "../cache/index.js";
2
+ import { fetchJson } from "../utils/http.js";
3
+ export class Connector {
4
+ async getJson(url, options = {}) {
5
+ const ttl = options.ttlSeconds ?? this.metadata.defaultTtlSeconds;
6
+ const key = options.cacheKey ?? `${this.metadata.id}:${url}`;
7
+ return cache.wrap(key, ttl, () => fetchJson(url, { headers: options.headers }));
8
+ }
9
+ }
10
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/connectors/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAY7C,MAAM,OAAgB,SAAS;IAGnB,KAAK,CAAC,OAAO,CACrB,GAAW,EACX,UAII,EAAE;QAEN,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClE,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,EAAE,CAAC;QAC7D,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAC/B,SAAS,CAAI,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAChD,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import type { LegalAnnouncement } from "../schemas/canonical.js";
2
+ import { Connector, type ConnectorMetadata } from "./base.js";
3
+ export declare class BodaccConnector extends Connector {
4
+ readonly metadata: ConnectorMetadata;
5
+ searchBySiren(siren: string, limit?: number): Promise<LegalAnnouncement[]>;
6
+ searchByCompanyName(name: string, limit?: number): Promise<LegalAnnouncement[]>;
7
+ searchProcedures(siren: string, limit?: number): Promise<LegalAnnouncement[]>;
8
+ private searchRaw;
9
+ private normalize;
10
+ }
11
+ //# sourceMappingURL=bodacc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodacc.d.ts","sourceRoot":"","sources":["../../src/connectors/bodacc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAwB9D,qBAAa,eAAgB,SAAQ,SAAS;IAC5C,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CASlC;IAEI,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAKtE,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAK3E,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAKjE,SAAS;IAMvB,OAAO,CAAC,SAAS;CAgBlB"}
@@ -0,0 +1,47 @@
1
+ import { Connector } from "./base.js";
2
+ const BASE_URL = "https://bodacc-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/annonces-commerciales/records";
3
+ export class BodaccConnector extends Connector {
4
+ metadata = {
5
+ id: "bodacc",
6
+ name: "BODACC (Bulletin Officiel des Annonces Civiles et Commerciales)",
7
+ description: "Annonces légales : créations, ventes, procédures collectives, comptes annuels, modifications.",
8
+ source: "https://bodacc-datadila.opendatasoft.com",
9
+ license: "Licence Ouverte 2.0 (Etalab)",
10
+ authRequired: false,
11
+ defaultTtlSeconds: 86400,
12
+ };
13
+ async searchBySiren(siren, limit = 20) {
14
+ const where = `registre LIKE "%${siren}%"`;
15
+ return this.searchRaw(where, limit);
16
+ }
17
+ async searchByCompanyName(name, limit = 20) {
18
+ const where = `commercant LIKE "%${name.replace(/"/g, "")}%"`;
19
+ return this.searchRaw(where, limit);
20
+ }
21
+ async searchProcedures(siren, limit = 20) {
22
+ const where = `registre LIKE "%${siren}%" AND familleavis_lib LIKE "%procédure%"`;
23
+ return this.searchRaw(where, limit);
24
+ }
25
+ async searchRaw(where, limit) {
26
+ const url = `${BASE_URL}?where=${encodeURIComponent(where)}&limit=${limit}&order_by=dateparution DESC`;
27
+ const data = await this.getJson(url);
28
+ return (data.results ?? []).map((r) => this.normalize(r));
29
+ }
30
+ normalize(r) {
31
+ const sirenMatch = Array.isArray(r.registre)
32
+ ? r.registre.find((x) => /\d{9}/.test(x))
33
+ : typeof r.registre === "string"
34
+ ? r.registre.match(/\d{9}/)?.[0]
35
+ : undefined;
36
+ return {
37
+ id: r.id ?? r.numeroannonce ?? `${r.dateparution}-${r.commercant}`,
38
+ type: r.familleavis_lib ?? "Annonce",
39
+ published_at: r.dateparution ?? "",
40
+ company_siren: sirenMatch?.match(/\d{9}/)?.[0],
41
+ company_name: r.commercant,
42
+ content: r.jugement ?? r.listepersonnes,
43
+ source_url: r.url_complete,
44
+ };
45
+ }
46
+ }
47
+ //# sourceMappingURL=bodacc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodacc.js","sourceRoot":"","sources":["../../src/connectors/bodacc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAA0B,MAAM,WAAW,CAAC;AAE9D,MAAM,QAAQ,GAAG,0GAA0G,CAAC;AAsB5H,MAAM,OAAO,eAAgB,SAAQ,SAAS;IACnC,QAAQ,GAAsB;QACrC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,iEAAiE;QACvE,WAAW,EACT,+FAA+F;QACjG,MAAM,EAAE,0CAA0C;QAClD,OAAO,EAAE,8BAA8B;QACvC,YAAY,EAAE,KAAK;QACnB,iBAAiB,EAAE,KAAK;KACzB,CAAC;IAEF,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,KAAK,GAAG,EAAE;QAC3C,MAAM,KAAK,GAAG,mBAAmB,KAAK,IAAI,CAAC;QAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,IAAY,EAAE,KAAK,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,qBAAqB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;QAC9D,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,KAAa,EAAE,KAAK,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,mBAAmB,KAAK,2CAA2C,CAAC;QAClF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,KAAa,EAAE,KAAa;QAClD,MAAM,GAAG,GAAG,GAAG,QAAQ,UAAU,kBAAkB,CAAC,KAAK,CAAC,UAAU,KAAK,6BAA6B,CAAC;QACvG,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAc,GAAG,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;IAEO,SAAS,CAAC,CAAY;QAC5B,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC1C,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;gBAC9B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChC,CAAC,CAAC,SAAS,CAAC;QAChB,OAAO;YACL,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,aAAa,IAAI,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,UAAU,EAAE;YAClE,IAAI,EAAE,CAAC,CAAC,eAAe,IAAI,SAAS;YACpC,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,EAAE;YAClC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC9C,YAAY,EAAE,CAAC,CAAC,UAAU;YAC1B,OAAO,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,cAAc;YACvC,UAAU,EAAE,CAAC,CAAC,YAAY;SAC3B,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { Company, SearchResult } from "../schemas/canonical.js";
2
+ import { Connector, type ConnectorMetadata } from "./base.js";
3
+ export declare class CompaniesHouseConnector extends Connector {
4
+ readonly metadata: ConnectorMetadata;
5
+ private get authHeader();
6
+ search(query: string, itemsPerPage?: number): Promise<SearchResult>;
7
+ getByNumber(companyNumber: string): Promise<Company | null>;
8
+ private normalizeSummary;
9
+ private normalizeProfile;
10
+ private normalizeAddress;
11
+ private makeProvenance;
12
+ }
13
+ //# sourceMappingURL=companies-house.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"companies-house.d.ts","sourceRoot":"","sources":["../../src/connectors/companies-house.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,OAAO,EAAuB,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEnG,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AA8D9D,qBAAa,uBAAwB,SAAQ,SAAS;IACpD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CASlC;IAEF,OAAO,KAAK,UAAU,GAIrB;IAEK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,SAAK,GAAG,OAAO,CAAC,YAAY,CAAC;IAc/D,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAYjE,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;IAkCxB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,cAAc;CAQvB"}
@@ -0,0 +1,104 @@
1
+ import { requireEnv } from "../utils/oauth.js";
2
+ import { Connector } from "./base.js";
3
+ const BASE_URL = "https://api.company-information.service.gov.uk";
4
+ export class CompaniesHouseConnector extends Connector {
5
+ metadata = {
6
+ id: "companies-house-uk",
7
+ name: "Companies House UK",
8
+ description: "Registre officiel des sociétés britanniques (Companies House). Recherche et fiche par numéro Companies House. Couvre England, Wales, Scotland, Northern Ireland.",
9
+ source: "https://developer.company-information.service.gov.uk",
10
+ license: "Open Government Licence v3.0",
11
+ authRequired: true,
12
+ defaultTtlSeconds: 86400,
13
+ };
14
+ get authHeader() {
15
+ const key = requireEnv("COMPANIES_HOUSE_API_KEY");
16
+ const credentials = Buffer.from(`${key}:`).toString("base64");
17
+ return { Authorization: `Basic ${credentials}` };
18
+ }
19
+ async search(query, itemsPerPage = 10) {
20
+ const url = `${BASE_URL}/search/companies?q=${encodeURIComponent(query)}&items_per_page=${itemsPerPage}`;
21
+ const data = await this.getJson(url, { headers: this.authHeader });
22
+ return {
23
+ query,
24
+ total: data.total_results ?? 0,
25
+ page: data.page_number ?? 1,
26
+ per_page: data.items_per_page ?? itemsPerPage,
27
+ results: (data.items ?? []).map((item) => this.normalizeSummary(item)),
28
+ provenance: [this.makeProvenance(url)],
29
+ };
30
+ }
31
+ async getByNumber(companyNumber) {
32
+ const profileUrl = `${BASE_URL}/company/${companyNumber}`;
33
+ const officersUrl = `${BASE_URL}/company/${companyNumber}/officers`;
34
+ const [profile, officersData] = await Promise.all([
35
+ this.getJson(profileUrl, { headers: this.authHeader }),
36
+ this.getJson(officersUrl, { headers: this.authHeader }).catch(() => null),
37
+ ]);
38
+ return this.normalizeProfile(profile, officersData);
39
+ }
40
+ normalizeSummary(item) {
41
+ return {
42
+ siren: item.company_number,
43
+ legal_name: item.title,
44
+ active: item.company_status === "active",
45
+ created_at: item.date_of_creation,
46
+ closed_at: item.date_of_cessation,
47
+ naf_code: item.sic_codes?.[0],
48
+ registered_address: item.registered_office_address
49
+ ? this.normalizeAddress(item.registered_office_address)
50
+ : undefined,
51
+ provenance: [this.makeProvenance(`${BASE_URL}/company/${item.company_number}`)],
52
+ _raw: item,
53
+ };
54
+ }
55
+ normalizeProfile(profile, officersData) {
56
+ const officers = (officersData?.items ?? [])
57
+ .filter((o) => !o.resigned_on)
58
+ .map((o) => {
59
+ const dob = o.date_of_birth;
60
+ const birth_date_partial = dob?.year && dob?.month
61
+ ? `${dob.year}-${String(dob.month).padStart(2, "0")}`
62
+ : undefined;
63
+ return {
64
+ name: o.name ?? "Unknown",
65
+ role: o.officer_role,
66
+ type: "person",
67
+ birth_date_partial,
68
+ nationality: o.nationality,
69
+ };
70
+ });
71
+ const url = `${BASE_URL}/company/${profile.company_number}`;
72
+ return {
73
+ siren: profile.company_number,
74
+ legal_name: profile.company_name,
75
+ active: profile.company_status === "active",
76
+ created_at: profile.date_of_creation,
77
+ closed_at: profile.date_of_cessation,
78
+ naf_code: profile.sic_codes?.[0],
79
+ registered_address: profile.registered_office_address
80
+ ? this.normalizeAddress(profile.registered_office_address)
81
+ : undefined,
82
+ officers,
83
+ provenance: [this.makeProvenance(url)],
84
+ _raw: profile,
85
+ };
86
+ }
87
+ normalizeAddress(addr) {
88
+ return {
89
+ street: [addr.address_line_1, addr.address_line_2].filter(Boolean).join(", ") || undefined,
90
+ city: addr.locality,
91
+ postal_code: addr.postal_code,
92
+ country: addr.country ?? "GB",
93
+ };
94
+ }
95
+ makeProvenance(url) {
96
+ return {
97
+ source: this.metadata.id,
98
+ source_url: url,
99
+ fetched_at: new Date().toISOString(),
100
+ license: this.metadata.license,
101
+ };
102
+ }
103
+ }
104
+ //# sourceMappingURL=companies-house.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"companies-house.js","sourceRoot":"","sources":["../../src/connectors/companies-house.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { RealEstateTransaction } from "../schemas/canonical.js";
2
+ import { Connector, type ConnectorMetadata } from "./base.js";
3
+ export declare class DvfConnector extends Connector {
4
+ readonly metadata: ConnectorMetadata;
5
+ /**
6
+ * Recherche les mutations sur une commune (code INSEE).
7
+ * Endpoint stable alternatif via api.cquest.org/dvf si CEREMA indisponible.
8
+ */
9
+ searchByCommune(codeInsee: string, limit?: number): Promise<RealEstateTransaction[]>;
10
+ searchByPostalCode(postalCode: string, limit?: number): Promise<RealEstateTransaction[]>;
11
+ private normalize;
12
+ }
13
+ //# sourceMappingURL=dvf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dvf.d.ts","sourceRoot":"","sources":["../../src/connectors/dvf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AA2B9D,qBAAa,YAAa,SAAQ,SAAS;IACzC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAQlC;IAEF;;;OAGG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAMhF,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAM1F,OAAO,CAAC,SAAS;CAuBlB"}
@@ -0,0 +1,51 @@
1
+ import { Connector } from "./base.js";
2
+ const BASE_URL = "https://apidf-preprod.cerema.fr/dvf_opendata/mutations";
3
+ export class DvfConnector extends Connector {
4
+ metadata = {
5
+ id: "dvf",
6
+ name: "DVF (Demandes de Valeurs Foncières)",
7
+ description: "Transactions immobilières en France sur les 5 dernières années.",
8
+ source: "https://app.dvf.etalab.gouv.fr",
9
+ license: "Licence Ouverte 2.0 (Etalab)",
10
+ authRequired: false,
11
+ defaultTtlSeconds: 86400 * 30,
12
+ };
13
+ /**
14
+ * Recherche les mutations sur une commune (code INSEE).
15
+ * Endpoint stable alternatif via api.cquest.org/dvf si CEREMA indisponible.
16
+ */
17
+ async searchByCommune(codeInsee, limit = 50) {
18
+ const url = `https://api.cquest.org/dvf?code_commune=${encodeURIComponent(codeInsee)}`;
19
+ const data = await this.getJson(url);
20
+ return (data.resultats ?? []).slice(0, limit).map((r) => this.normalize(r));
21
+ }
22
+ async searchByPostalCode(postalCode, limit = 50) {
23
+ const url = `https://api.cquest.org/dvf?code_postal=${encodeURIComponent(postalCode)}`;
24
+ const data = await this.getJson(url);
25
+ return (data.resultats ?? []).slice(0, limit).map((r) => this.normalize(r));
26
+ }
27
+ normalize(r) {
28
+ const address = {
29
+ street: [r.adresse_numero, r.adresse_suffixe, r.adresse_nom_voie]
30
+ .filter(Boolean)
31
+ .join(" ") || undefined,
32
+ postal_code: r.code_postal,
33
+ city: r.nom_commune,
34
+ insee_code: r.code_commune,
35
+ latitude: r.latitude,
36
+ longitude: r.longitude,
37
+ country: "FR",
38
+ };
39
+ return {
40
+ date: r.date_mutation,
41
+ type: r.nature_mutation,
42
+ price_eur: r.valeur_fonciere,
43
+ surface_built_m2: r.surface_reelle_bati,
44
+ surface_land_m2: r.surface_terrain,
45
+ rooms: r.nombre_pieces_principales,
46
+ property_type: r.type_local,
47
+ address,
48
+ };
49
+ }
50
+ }
51
+ //# sourceMappingURL=dvf.js.map