@centia-io/mcp-server 1.0.15 → 1.0.17

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.
@@ -0,0 +1,224 @@
1
+ ---
2
+ name: danish-search
3
+ description: Danish address and cadastral (matrikel) search component for Centia apps. Covers installation, initialization, option configuration, result handling, and integration with Centia SDK for spatial queries.
4
+ ---
5
+
6
+ # Danish Search Component — `@centia-io/danish-search`
7
+
8
+ Use this skill when building Centia.io apps that need Danish address or cadastral search.
9
+
10
+ ## What it does
11
+
12
+ The component searches DAR (adgangsadresser) and Matriklen (jordstykke) via
13
+ GC2 Elasticsearch. It provides typeahead autocomplete with intelligent
14
+ cascading: street → address, ejerlav → jordstykke.
15
+
16
+ ## Package
17
+
18
+ | | |
19
+ |---|---|
20
+ | **npm** | `@centia-io/danish-search` |
21
+ | **Entry (ESM)** | `dist/danish-search.mjs` |
22
+ | **Entry (CJS)** | `dist/danish-search.cjs` |
23
+ | **Stylesheet** | `dist/style.css` |
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pnpm add @centia-io/danish-search
29
+ ```
30
+
31
+ ## Source files (development)
32
+
33
+ | File | Purpose |
34
+ |---|---|
35
+ | `src/danish.js` | Search logic, Elasticsearch DSL, result handling |
36
+ | `src/autocomplete.js` | Generic typeahead/autocomplete UI class |
37
+ | `src/style.css` | Standalone styling (no framework dependencies) |
38
+ | `src/main.js` | Demo entry point (not published) |
39
+
40
+ ## Hard rules
41
+
42
+ - Do not add jQuery, Bootstrap, or other framework dependencies.
43
+ - Do not perform spatial/SQL queries inside the component — emit data and let the consuming app query Centia.io.
44
+ - Do not hardcode host or database — always pass via options.
45
+
46
+ ## Initialization
47
+
48
+ ```js
49
+ import danish from "@centia-io/danish-search";
50
+ import "@centia-io/danish-search/style.css";
51
+
52
+ const inputEl = danish({
53
+ el: ".custom-search", // CSS selector for input element (default: ".custom-search")
54
+ host: "https://dk.gc2.io", // GC2 host (default)
55
+ db: "dk", // GC2 database (default)
56
+ onlyAddress: false, // true = hide matrikel results
57
+ komKode: "*", // municipality filter: "*", "101", or ["101","147"]
58
+ size: 20, // max results per query
59
+ onSelect({ type, gid, value, searchType }) {
60
+ // Called when a final result is selected
61
+ }
62
+ });
63
+ ```
64
+
65
+ Returns the input `HTMLElement`.
66
+
67
+ ## Options reference
68
+
69
+ | Option | Type | Default | Description |
70
+ |---|---|---|---|
71
+ | `el` | `string` | `".custom-search"` | CSS selector for the search input |
72
+ | `host` | `string` | `"https://dk.gc2.io"` | GC2 Elasticsearch host |
73
+ | `db` | `string` | `"dk"` | GC2 database name |
74
+ | `onlyAddress` | `boolean` | `false` | Suppress matrikel results |
75
+ | `komKode` | `string \| string[]` | `"*"` | Municipality code(s), `"*"` = all |
76
+ | `size` | `number` | `20` | Max suggestions per category |
77
+ | `onSelect` | `function` | — | Callback on final selection |
78
+
79
+ ## Result object (`onSelect` / `search:select` event detail)
80
+
81
+ ```ts
82
+ {
83
+ type: "adresse" | "matrikel", // Which dataset the result came from
84
+ gid: string, // Unique ID (DAR id or matrikel gid)
85
+ value: string, // Display string shown to user
86
+ searchType: string, // Internal search phase (adresse, jordstykke, etc.)
87
+ feature: GeoJSON.Feature // The full GeoJSON feature of a adresse or matrikel
88
+ }
89
+ ```
90
+
91
+ ## Listening via event instead of callback
92
+
93
+ ```js
94
+ import danish from "@centia-io/danish-search";
95
+
96
+ const inputEl = danish({ el: "#my-input" });
97
+
98
+ inputEl.addEventListener("search:select", (e) => {
99
+ const { type, gid, value } = e.detail;
100
+ // handle result
101
+ });
102
+ ```
103
+
104
+ ## Integrating with Centia SDK
105
+
106
+ The `feature` in the callback is a full GeoJSON Feature (EPSG:4326) with the
107
+ geometry of the selected address or matrikel parcel. Use it directly for spatial
108
+ queries against your own data via `ST_Intersects`.
109
+
110
+ ### Find rows in your own table that intersect the selected feature
111
+
112
+ ```js
113
+ import danish from "@centia-io/danish-search";
114
+ import { Sql } from "@centia-io/sdk";
115
+
116
+ const sql = new Sql();
117
+
118
+ danish({
119
+ onSelect: async ({ feature }) => {
120
+ const res = await sql.exec({
121
+ q: `SELECT *
122
+ FROM my_schema.my_table
123
+ WHERE ST_Intersects(
124
+ the_geom,
125
+ ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(:geojson), 4326), 25832)
126
+ )`,
127
+ params: [{"geojson": feature.geometry}]
128
+ });
129
+ console.log(res.data);
130
+ }
131
+ });
132
+ ```
133
+
134
+ ### Zoom a map to the selected feature
135
+
136
+ ```js
137
+ danish({
138
+ onSelect: ({ feature }) => {
139
+ // Works with any map library that accepts GeoJSON (Leaflet, MapLibre, OpenLayers, etc.)
140
+ map.fitBounds(L.geoJSON(feature).getBounds());
141
+ }
142
+ });
143
+ ```
144
+
145
+ ### Aggregate your data within a selected matrikel parcel
146
+
147
+ ```js
148
+ danish({
149
+ onSelect: async ({ type, feature }) => {
150
+ if (type === "matrikel") {
151
+ const geojson = JSON.stringify(feature.geometry);
152
+ const res = await Sql.exec(`
153
+ SELECT count(*) AS cnt, sum(areal) AS total_areal
154
+ FROM my_schema.bygninger
155
+ WHERE ST_Intersects(
156
+ the_geom,
157
+ ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON('${geojson}'), 4326), 25832)
158
+ )
159
+ `);
160
+ console.log(res.data);
161
+ }
162
+ }
163
+ });
164
+ ```
165
+
166
+ ### Use the feature properties directly
167
+
168
+ The `feature.properties` object contains all attributes from the source dataset
169
+ (DAR or matrikel). No extra query is needed for basic attribute display:
170
+
171
+ ```js
172
+ danish({
173
+ onSelect: ({ type, feature }) => {
174
+ if (type === "adresse") {
175
+ const { postnr, postnrnavn, kommunekode } = feature.properties;
176
+ console.log(`${postnr} ${postnrnavn}, kommune ${kommunekode}`);
177
+ }
178
+ if (type === "matrikel") {
179
+ const { matrikelnummer, ejerlavsnavn } = feature.properties;
180
+ console.log(`${ejerlavsnavn} ${matrikelnummer}`);
181
+ }
182
+ }
183
+ });
184
+ ```
185
+
186
+ ## Search cascade behavior
187
+
188
+ The component auto-narrows results:
189
+
190
+ 1. **No digits, no comma, no spaces** → searches street names and city names separately
191
+ 2. **No digits, no comma, with spaces** → searches combined street + city
192
+ 3. **Contains comma or digits** → searches full addresses directly
193
+ 4. **Comma with house number after city** → auto-normalizes query (e.g. `"Vej, By 35"` → `"Vej 35, By"`)
194
+ 5. **Single result at street/city level** → auto-cascades to full address search
195
+
196
+ Matrikel follows the same pattern:
197
+ 1. **No digits** → ejerlav (estate name) aggregation
198
+ 2. **Contains digits** → jordstykke (parcel) hits
199
+ 3. **Single ejerlav** → auto-cascades to jordstykke
200
+
201
+ Intermediate selections (street name, city, ejerlav) are injected back into the
202
+ input to narrow the search — `onSelect` only fires for final results with a GID.
203
+
204
+ ## Required HTML
205
+
206
+ The component needs an `<input>` element matching the `el` selector:
207
+
208
+ ```html
209
+ <input class="custom-search" type="text" placeholder="Søg adresse eller matrikel...">
210
+ ```
211
+
212
+ Import `@centia-io/danish-search/style.css` for dropdown styling, or provide your own styles for these classes:
213
+
214
+ - `.tt-dropdown-menu` — dropdown container
215
+ - `.tt-suggestions` — suggestions wrapper
216
+ - `.tt-suggestion` — individual suggestion
217
+ - `.tt-suggestion.tt-cursor` — highlighted suggestion
218
+ - `.typeahead-heading` — category header (Adresser / Matrikel)
219
+
220
+ ## Security notes
221
+
222
+ - GID values come from Elasticsearch and are used in SQL queries — always use parameterized queries or validate GIDs when building SQL for Centia.
223
+ - DAR `id` values are UUIDs. Matrikel `gid` values are integers.
224
+ - Do not expose the GC2 Elasticsearch endpoint to user-controlled input beyond the search query itself.