@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.
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/dist/cache/index.d.ts +12 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +44 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/connectors/ban.d.ts +15 -0
- package/dist/connectors/ban.d.ts.map +1 -0
- package/dist/connectors/ban.js +46 -0
- package/dist/connectors/ban.js.map +1 -0
- package/dist/connectors/base.d.ts +18 -0
- package/dist/connectors/base.d.ts.map +1 -0
- package/dist/connectors/base.js +10 -0
- package/dist/connectors/base.js.map +1 -0
- package/dist/connectors/bodacc.d.ts +11 -0
- package/dist/connectors/bodacc.d.ts.map +1 -0
- package/dist/connectors/bodacc.js +47 -0
- package/dist/connectors/bodacc.js.map +1 -0
- package/dist/connectors/companies-house.d.ts +13 -0
- package/dist/connectors/companies-house.d.ts.map +1 -0
- package/dist/connectors/companies-house.js +104 -0
- package/dist/connectors/companies-house.js.map +1 -0
- package/dist/connectors/dvf.d.ts +13 -0
- package/dist/connectors/dvf.d.ts.map +1 -0
- package/dist/connectors/dvf.js +51 -0
- package/dist/connectors/dvf.js.map +1 -0
- package/dist/connectors/epo-ops.d.ts +37 -0
- package/dist/connectors/epo-ops.d.ts.map +1 -0
- package/dist/connectors/epo-ops.js +100 -0
- package/dist/connectors/epo-ops.js.map +1 -0
- package/dist/connectors/france-travail.d.ts +47 -0
- package/dist/connectors/france-travail.d.ts.map +1 -0
- package/dist/connectors/france-travail.js +89 -0
- package/dist/connectors/france-travail.js.map +1 -0
- package/dist/connectors/georisques.d.ts +7 -0
- package/dist/connectors/georisques.d.ts.map +1 -0
- package/dist/connectors/georisques.js +68 -0
- package/dist/connectors/georisques.js.map +1 -0
- package/dist/connectors/gleif.d.ts +9 -0
- package/dist/connectors/gleif.d.ts.map +1 -0
- package/dist/connectors/gleif.js +63 -0
- package/dist/connectors/gleif.js.map +1 -0
- package/dist/connectors/index.d.ts +29 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +28 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/inpi-rne.d.ts +19 -0
- package/dist/connectors/inpi-rne.d.ts.map +1 -0
- package/dist/connectors/inpi-rne.js +107 -0
- package/dist/connectors/inpi-rne.js.map +1 -0
- package/dist/connectors/insee-sirene.d.ts +12 -0
- package/dist/connectors/insee-sirene.d.ts.map +1 -0
- package/dist/connectors/insee-sirene.js +104 -0
- package/dist/connectors/insee-sirene.js.map +1 -0
- package/dist/connectors/recherche-entreprises.d.ts +20 -0
- package/dist/connectors/recherche-entreprises.d.ts.map +1 -0
- package/dist/connectors/recherche-entreprises.js +135 -0
- package/dist/connectors/recherche-entreprises.js.map +1 -0
- package/dist/connectors/vies.d.ts +10 -0
- package/dist/connectors/vies.d.ts.map +1 -0
- package/dist/connectors/vies.js +39 -0
- package/dist/connectors/vies.js.map +1 -0
- package/dist/http.d.ts +3 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +74 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/canonical.d.ts +1545 -0
- package/dist/schemas/canonical.d.ts.map +1 -0
- package/dist/schemas/canonical.js +120 -0
- package/dist/schemas/canonical.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +126 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/company-layer2.d.ts +3 -0
- package/dist/tools/company-layer2.d.ts.map +1 -0
- package/dist/tools/company-layer2.js +84 -0
- package/dist/tools/company-layer2.js.map +1 -0
- package/dist/tools/company.d.ts +3 -0
- package/dist/tools/company.d.ts.map +1 -0
- package/dist/tools/company.js +119 -0
- package/dist/tools/company.js.map +1 -0
- package/dist/tools/geo.d.ts +3 -0
- package/dist/tools/geo.d.ts.map +1 -0
- package/dist/tools/geo.js +59 -0
- package/dist/tools/geo.js.map +1 -0
- package/dist/tools/identity.d.ts +3 -0
- package/dist/tools/identity.d.ts.map +1 -0
- package/dist/tools/identity.js +60 -0
- package/dist/tools/identity.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +22 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/jobs.d.ts +3 -0
- package/dist/tools/jobs.d.ts.map +1 -0
- package/dist/tools/jobs.js +63 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/legal.d.ts +3 -0
- package/dist/tools/legal.d.ts.map +1 -0
- package/dist/tools/legal.js +48 -0
- package/dist/tools/legal.js.map +1 -0
- package/dist/tools/patents.d.ts +3 -0
- package/dist/tools/patents.d.ts.map +1 -0
- package/dist/tools/patents.js +51 -0
- package/dist/tools/patents.js.map +1 -0
- package/dist/tools/realestate.d.ts +3 -0
- package/dist/tools/realestate.d.ts.map +1 -0
- package/dist/tools/realestate.js +30 -0
- package/dist/tools/realestate.js.map +1 -0
- package/dist/tools/sources.d.ts +3 -0
- package/dist/tools/sources.d.ts.map +1 -0
- package/dist/tools/sources.js +17 -0
- package/dist/tools/sources.js.map +1 -0
- package/dist/tools/types.d.ts +10 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/env.d.ts +3 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +14 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/http.d.ts +17 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +62 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/oauth.d.ts +11 -0
- package/dist/utils/oauth.d.ts.map +1 -0
- package/dist/utils/oauth.js +31 -0
- package/dist/utils/oauth.js.map +1 -0
- package/dist/worker.d.ts +16 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +185 -0
- package/dist/worker.js.map +1 -0
- 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)
|
|
8
|
+
[]()
|
|
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
|