n8n-nodes-geomelon 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.
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# n8n-nodes-geomelon
|
|
2
|
+
|
|
3
|
+
[n8n](https://n8n.io) community node for the **[Geomelon](https://geomelon.dev) geographic API** — search cities, look up countries and regions, compute distances, and resolve coordinates, all with multilingual name support.
|
|
4
|
+
|
|
5
|
+
Looking for other ways to integrate? See all official libraries at [geomelon.dev/libraries](https://geomelon.dev/libraries/).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
In your n8n instance: **Settings → Community Nodes → Install** → enter `n8n-nodes-geomelon`.
|
|
10
|
+
|
|
11
|
+
Requires n8n v1.0+ and Node.js 18+.
|
|
12
|
+
|
|
13
|
+
## Credentials
|
|
14
|
+
|
|
15
|
+
The node uses a **Geomelon API (RapidAPI)** credential. You need a RapidAPI key subscribed to the [Geomelon API](https://rapidapi.com/hom3chuk/api/geomelon).
|
|
16
|
+
|
|
17
|
+
1. Create a credential of type **Geomelon API (RapidAPI)**
|
|
18
|
+
2. Paste your RapidAPI key into the **RapidAPI Key** field
|
|
19
|
+
|
|
20
|
+
## Resources and Operations
|
|
21
|
+
|
|
22
|
+
### City
|
|
23
|
+
|
|
24
|
+
| Operation | Description |
|
|
25
|
+
|---|---|
|
|
26
|
+
| **Search** | Search cities by name prefix, country code, region, population range, with sort and pagination |
|
|
27
|
+
| **Get** | Get full details for a city by UUID |
|
|
28
|
+
| **Get Translations** | Get all available name translations for a city |
|
|
29
|
+
| **Get Settlement Types** | Get settlement-type classifications (city, town, village, …) |
|
|
30
|
+
| **Distance** | Calculate the distance in kilometres between two cities |
|
|
31
|
+
| **By Coordinates (Closest)** | Find cities nearest to a lat/lon point, ordered by distance |
|
|
32
|
+
| **By Coordinates (Largest)** | Find the largest cities near a lat/lon point, ordered by population |
|
|
33
|
+
|
|
34
|
+
### Country
|
|
35
|
+
|
|
36
|
+
| Operation | Description |
|
|
37
|
+
|---|---|
|
|
38
|
+
| **List** | List countries with optional name, telephone code, and language filters |
|
|
39
|
+
| **Get** | Get full details (including regions and translations) for a country by UUID |
|
|
40
|
+
| **Get Translations** | Get name translations for a country |
|
|
41
|
+
| **Get Regions** | Get all administrative regions belonging to a country |
|
|
42
|
+
|
|
43
|
+
### Region
|
|
44
|
+
|
|
45
|
+
| Operation | Description |
|
|
46
|
+
|---|---|
|
|
47
|
+
| **List** | List regions, optionally filtered by country UUID |
|
|
48
|
+
| **Get** | Get full details for a region by UUID |
|
|
49
|
+
| **Get Translations** | Get name translations for a region |
|
|
50
|
+
|
|
51
|
+
### Language
|
|
52
|
+
|
|
53
|
+
| Operation | Description |
|
|
54
|
+
|---|---|
|
|
55
|
+
| **List** | List languages available in the Geomelon database |
|
|
56
|
+
| **Get** | Get details for a language by UUID |
|
|
57
|
+
|
|
58
|
+
## Output
|
|
59
|
+
|
|
60
|
+
- **List / Search** operations output one item per result, so downstream nodes can iterate naturally.
|
|
61
|
+
- **Get** and single-result operations output one item.
|
|
62
|
+
- The **Distance** operation outputs `{ distanceKm: number }`.
|
|
63
|
+
|
|
64
|
+
## Example Workflows
|
|
65
|
+
|
|
66
|
+
**Find the 10 largest cities in France with French names**
|
|
67
|
+
1. Geomelon → City: Search → `countryCode = FR`, `preferredLanguages = fr`, `sort = population_desc`, `limit = 10`
|
|
68
|
+
|
|
69
|
+
**Look up a city by coordinates**
|
|
70
|
+
1. Geomelon → City: By Coordinates (Closest) → `lat = 48.8566`, `lon = 2.3522`
|
|
71
|
+
|
|
72
|
+
**Get all regions of Germany**
|
|
73
|
+
1. Geomelon → Country: List → `name = Germany`, `limit = 1`
|
|
74
|
+
2. Geomelon → Country: Get Regions → `countryId = {{ $json.id }}`
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class GeomelonApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
test: ICredentialTestRequest;
|
|
8
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GeomelonApi = void 0;
|
|
4
|
+
class GeomelonApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'geomelonApi';
|
|
7
|
+
this.displayName = 'Geomelon API (RapidAPI)';
|
|
8
|
+
this.documentationUrl = 'https://rapidapi.com/hom3chuk/api/geomelon';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'RapidAPI Key',
|
|
12
|
+
name: 'apiKey',
|
|
13
|
+
type: 'string',
|
|
14
|
+
typeOptions: { password: true },
|
|
15
|
+
default: '',
|
|
16
|
+
required: true,
|
|
17
|
+
description: 'Your RapidAPI key for the Geomelon API',
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
this.test = {
|
|
21
|
+
request: {
|
|
22
|
+
baseURL: 'https://geomelon.p.rapidapi.com',
|
|
23
|
+
url: '/countries',
|
|
24
|
+
qs: { limit: 1 },
|
|
25
|
+
headers: {
|
|
26
|
+
'x-rapidapi-key': '={{$credentials.apiKey}}',
|
|
27
|
+
'x-rapidapi-host': 'geomelon.p.rapidapi.com',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.GeomelonApi = GeomelonApi;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class Geomelon implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Geomelon = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const geomelon_1 = require("geomelon");
|
|
6
|
+
class Geomelon {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.description = {
|
|
9
|
+
displayName: 'Geomelon',
|
|
10
|
+
name: 'geomelon',
|
|
11
|
+
icon: 'file:geomelon.svg',
|
|
12
|
+
group: ['transform'],
|
|
13
|
+
version: 1,
|
|
14
|
+
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
|
|
15
|
+
description: 'Geographic data — cities, countries, regions, and languages via the Geomelon API',
|
|
16
|
+
defaults: { name: 'Geomelon' },
|
|
17
|
+
inputs: ['main'],
|
|
18
|
+
outputs: ['main'],
|
|
19
|
+
credentials: [{ name: 'geomelonApi', required: true }],
|
|
20
|
+
properties: [
|
|
21
|
+
// ── Resource ──────────────────────────────────────────────────────────
|
|
22
|
+
{
|
|
23
|
+
displayName: 'Resource',
|
|
24
|
+
name: 'resource',
|
|
25
|
+
type: 'options',
|
|
26
|
+
noDataExpression: true,
|
|
27
|
+
options: [
|
|
28
|
+
{ name: 'City', value: 'city' },
|
|
29
|
+
{ name: 'Country', value: 'country' },
|
|
30
|
+
{ name: 'Language', value: 'language' },
|
|
31
|
+
{ name: 'Region', value: 'region' },
|
|
32
|
+
],
|
|
33
|
+
default: 'city',
|
|
34
|
+
},
|
|
35
|
+
// ── City operations ───────────────────────────────────────────────────
|
|
36
|
+
{
|
|
37
|
+
displayName: 'Operation',
|
|
38
|
+
name: 'operation',
|
|
39
|
+
type: 'options',
|
|
40
|
+
noDataExpression: true,
|
|
41
|
+
displayOptions: { show: { resource: ['city'] } },
|
|
42
|
+
options: [
|
|
43
|
+
{
|
|
44
|
+
name: 'Search',
|
|
45
|
+
value: 'search',
|
|
46
|
+
description: 'Search cities by name, country, population range, and more',
|
|
47
|
+
action: 'Search cities',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Get',
|
|
51
|
+
value: 'get',
|
|
52
|
+
description: 'Get full details for a city by UUID',
|
|
53
|
+
action: 'Get a city',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'Get Translations',
|
|
57
|
+
value: 'getTranslations',
|
|
58
|
+
description: 'Get all name translations for a city',
|
|
59
|
+
action: 'Get city translations',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'Get Settlement Types',
|
|
63
|
+
value: 'getSettlementTypes',
|
|
64
|
+
description: 'Get settlement-type classifications for a city',
|
|
65
|
+
action: 'Get city settlement types',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'Distance',
|
|
69
|
+
value: 'distance',
|
|
70
|
+
description: 'Calculate the distance in kilometres between two cities',
|
|
71
|
+
action: 'Get distance between two cities',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'By Coordinates (Closest)',
|
|
75
|
+
value: 'byCoordinatesClosest',
|
|
76
|
+
description: 'Find cities nearest to given coordinates, ordered by distance',
|
|
77
|
+
action: 'Find closest cities by coordinates',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'By Coordinates (Largest)',
|
|
81
|
+
value: 'byCoordinatesLargest',
|
|
82
|
+
description: 'Find the largest cities near given coordinates, ordered by population',
|
|
83
|
+
action: 'Find largest cities by coordinates',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
default: 'search',
|
|
87
|
+
},
|
|
88
|
+
// ── Country operations ────────────────────────────────────────────────
|
|
89
|
+
{
|
|
90
|
+
displayName: 'Operation',
|
|
91
|
+
name: 'operation',
|
|
92
|
+
type: 'options',
|
|
93
|
+
noDataExpression: true,
|
|
94
|
+
displayOptions: { show: { resource: ['country'] } },
|
|
95
|
+
options: [
|
|
96
|
+
{
|
|
97
|
+
name: 'List',
|
|
98
|
+
value: 'list',
|
|
99
|
+
description: 'List countries with optional filtering',
|
|
100
|
+
action: 'List countries',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'Get',
|
|
104
|
+
value: 'get',
|
|
105
|
+
description: 'Get full details for a country by UUID',
|
|
106
|
+
action: 'Get a country',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'Get Translations',
|
|
110
|
+
value: 'getTranslations',
|
|
111
|
+
description: 'Get name translations for a country',
|
|
112
|
+
action: 'Get country translations',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'Get Regions',
|
|
116
|
+
value: 'getRegions',
|
|
117
|
+
description: 'Get all administrative regions belonging to a country',
|
|
118
|
+
action: 'Get country regions',
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
default: 'list',
|
|
122
|
+
},
|
|
123
|
+
// ── Region operations ─────────────────────────────────────────────────
|
|
124
|
+
{
|
|
125
|
+
displayName: 'Operation',
|
|
126
|
+
name: 'operation',
|
|
127
|
+
type: 'options',
|
|
128
|
+
noDataExpression: true,
|
|
129
|
+
displayOptions: { show: { resource: ['region'] } },
|
|
130
|
+
options: [
|
|
131
|
+
{
|
|
132
|
+
name: 'List',
|
|
133
|
+
value: 'list',
|
|
134
|
+
description: 'List administrative regions, optionally filtered by country',
|
|
135
|
+
action: 'List regions',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'Get',
|
|
139
|
+
value: 'get',
|
|
140
|
+
description: 'Get full details for a region by UUID',
|
|
141
|
+
action: 'Get a region',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'Get Translations',
|
|
145
|
+
value: 'getTranslations',
|
|
146
|
+
description: 'Get name translations for a region',
|
|
147
|
+
action: 'Get region translations',
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
default: 'list',
|
|
151
|
+
},
|
|
152
|
+
// ── Language operations ───────────────────────────────────────────────
|
|
153
|
+
{
|
|
154
|
+
displayName: 'Operation',
|
|
155
|
+
name: 'operation',
|
|
156
|
+
type: 'options',
|
|
157
|
+
noDataExpression: true,
|
|
158
|
+
displayOptions: { show: { resource: ['language'] } },
|
|
159
|
+
options: [
|
|
160
|
+
{
|
|
161
|
+
name: 'List',
|
|
162
|
+
value: 'list',
|
|
163
|
+
description: 'List languages available in Geomelon',
|
|
164
|
+
action: 'List languages',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'Get',
|
|
168
|
+
value: 'get',
|
|
169
|
+
description: 'Get details for a language by UUID',
|
|
170
|
+
action: 'Get a language',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
default: 'list',
|
|
174
|
+
},
|
|
175
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
176
|
+
// Fields — City
|
|
177
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
178
|
+
// City: Search
|
|
179
|
+
{
|
|
180
|
+
displayName: 'Name',
|
|
181
|
+
name: 'name',
|
|
182
|
+
type: 'string',
|
|
183
|
+
default: '',
|
|
184
|
+
description: 'City name prefix to search for',
|
|
185
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
displayName: 'Country Code',
|
|
189
|
+
name: 'countryCode',
|
|
190
|
+
type: 'string',
|
|
191
|
+
default: '',
|
|
192
|
+
placeholder: 'US',
|
|
193
|
+
description: 'ISO 3166-1 alpha-2 country code',
|
|
194
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
displayName: 'Region ID',
|
|
198
|
+
name: 'regionId',
|
|
199
|
+
type: 'string',
|
|
200
|
+
default: '',
|
|
201
|
+
description: 'Filter by region UUID',
|
|
202
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
displayName: 'Min Population',
|
|
206
|
+
name: 'minPopulation',
|
|
207
|
+
type: 'number',
|
|
208
|
+
default: 0,
|
|
209
|
+
description: 'Minimum population filter (leave 0 to skip)',
|
|
210
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
displayName: 'Max Population',
|
|
214
|
+
name: 'maxPopulation',
|
|
215
|
+
type: 'number',
|
|
216
|
+
default: 0,
|
|
217
|
+
description: 'Maximum population filter (leave 0 to skip)',
|
|
218
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
displayName: 'Sort',
|
|
222
|
+
name: 'sort',
|
|
223
|
+
type: 'options',
|
|
224
|
+
options: [
|
|
225
|
+
{ name: 'Population Descending', value: 'population_desc' },
|
|
226
|
+
{ name: 'Population Ascending', value: 'population_asc' },
|
|
227
|
+
{ name: 'Name A → Z', value: 'name_asc' },
|
|
228
|
+
{ name: 'Name Z → A', value: 'name_desc' },
|
|
229
|
+
],
|
|
230
|
+
default: 'population_desc',
|
|
231
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
displayName: 'Preferred Languages',
|
|
235
|
+
name: 'preferredLanguages',
|
|
236
|
+
type: 'string',
|
|
237
|
+
default: '',
|
|
238
|
+
placeholder: 'fr,en',
|
|
239
|
+
description: 'Comma-separated BCP 47 language tags for localized names',
|
|
240
|
+
displayOptions: {
|
|
241
|
+
show: {
|
|
242
|
+
resource: ['city'],
|
|
243
|
+
operation: ['search', 'byCoordinatesClosest', 'byCoordinatesLargest'],
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
displayName: 'Limit',
|
|
249
|
+
name: 'limit',
|
|
250
|
+
type: 'number',
|
|
251
|
+
typeOptions: { minValue: 1, maxValue: 100 },
|
|
252
|
+
default: 20,
|
|
253
|
+
description: 'Max number of results to return',
|
|
254
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
displayName: 'Offset',
|
|
258
|
+
name: 'offset',
|
|
259
|
+
type: 'number',
|
|
260
|
+
typeOptions: { minValue: 0 },
|
|
261
|
+
default: 0,
|
|
262
|
+
description: 'Pagination offset',
|
|
263
|
+
displayOptions: { show: { resource: ['city'], operation: ['search'] } },
|
|
264
|
+
},
|
|
265
|
+
// City: Get / Get Translations / Get Settlement Types
|
|
266
|
+
{
|
|
267
|
+
displayName: 'City ID',
|
|
268
|
+
name: 'cityId',
|
|
269
|
+
type: 'string',
|
|
270
|
+
default: '',
|
|
271
|
+
required: true,
|
|
272
|
+
description: 'UUID of the city',
|
|
273
|
+
displayOptions: {
|
|
274
|
+
show: {
|
|
275
|
+
resource: ['city'],
|
|
276
|
+
operation: ['get', 'getTranslations', 'getSettlementTypes'],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
// City: Distance
|
|
281
|
+
{
|
|
282
|
+
displayName: 'City 1 ID',
|
|
283
|
+
name: 'city1',
|
|
284
|
+
type: 'string',
|
|
285
|
+
default: '',
|
|
286
|
+
required: true,
|
|
287
|
+
description: 'UUID of the first city',
|
|
288
|
+
displayOptions: { show: { resource: ['city'], operation: ['distance'] } },
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
displayName: 'City 2 ID',
|
|
292
|
+
name: 'city2',
|
|
293
|
+
type: 'string',
|
|
294
|
+
default: '',
|
|
295
|
+
required: true,
|
|
296
|
+
description: 'UUID of the second city',
|
|
297
|
+
displayOptions: { show: { resource: ['city'], operation: ['distance'] } },
|
|
298
|
+
},
|
|
299
|
+
// City: By Coordinates
|
|
300
|
+
{
|
|
301
|
+
displayName: 'Latitude',
|
|
302
|
+
name: 'lat',
|
|
303
|
+
type: 'number',
|
|
304
|
+
default: 0,
|
|
305
|
+
required: true,
|
|
306
|
+
description: 'Latitude of the reference point',
|
|
307
|
+
displayOptions: {
|
|
308
|
+
show: {
|
|
309
|
+
resource: ['city'],
|
|
310
|
+
operation: ['byCoordinatesClosest', 'byCoordinatesLargest'],
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
displayName: 'Longitude',
|
|
316
|
+
name: 'lon',
|
|
317
|
+
type: 'number',
|
|
318
|
+
default: 0,
|
|
319
|
+
required: true,
|
|
320
|
+
description: 'Longitude of the reference point',
|
|
321
|
+
displayOptions: {
|
|
322
|
+
show: {
|
|
323
|
+
resource: ['city'],
|
|
324
|
+
operation: ['byCoordinatesClosest', 'byCoordinatesLargest'],
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
329
|
+
// Fields — Country
|
|
330
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
331
|
+
// Country: List
|
|
332
|
+
{
|
|
333
|
+
displayName: 'Name',
|
|
334
|
+
name: 'name',
|
|
335
|
+
type: 'string',
|
|
336
|
+
default: '',
|
|
337
|
+
description: 'Country name prefix to filter by',
|
|
338
|
+
displayOptions: { show: { resource: ['country'], operation: ['list'] } },
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
displayName: 'Telephone Code',
|
|
342
|
+
name: 'telephoneCode',
|
|
343
|
+
type: 'string',
|
|
344
|
+
default: '',
|
|
345
|
+
placeholder: '+1',
|
|
346
|
+
description: 'Filter by dialing code',
|
|
347
|
+
displayOptions: { show: { resource: ['country'], operation: ['list'] } },
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
displayName: 'Preferred Languages',
|
|
351
|
+
name: 'preferredLanguages',
|
|
352
|
+
type: 'string',
|
|
353
|
+
default: '',
|
|
354
|
+
placeholder: 'fr,es,en',
|
|
355
|
+
description: 'Comma-separated BCP 47 language tags for localized names',
|
|
356
|
+
displayOptions: {
|
|
357
|
+
show: {
|
|
358
|
+
resource: ['country'],
|
|
359
|
+
operation: ['list', 'getTranslations'],
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
displayName: 'Limit',
|
|
365
|
+
name: 'limit',
|
|
366
|
+
type: 'number',
|
|
367
|
+
typeOptions: { minValue: 1, maxValue: 500 },
|
|
368
|
+
default: 50,
|
|
369
|
+
description: 'Max number of results to return',
|
|
370
|
+
displayOptions: { show: { resource: ['country'], operation: ['list'] } },
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
displayName: 'Offset',
|
|
374
|
+
name: 'offset',
|
|
375
|
+
type: 'number',
|
|
376
|
+
typeOptions: { minValue: 0 },
|
|
377
|
+
default: 0,
|
|
378
|
+
description: 'Pagination offset',
|
|
379
|
+
displayOptions: { show: { resource: ['country'], operation: ['list'] } },
|
|
380
|
+
},
|
|
381
|
+
// Country: Get / Get Translations / Get Regions
|
|
382
|
+
{
|
|
383
|
+
displayName: 'Country ID',
|
|
384
|
+
name: 'countryId',
|
|
385
|
+
type: 'string',
|
|
386
|
+
default: '',
|
|
387
|
+
required: true,
|
|
388
|
+
description: 'UUID of the country',
|
|
389
|
+
displayOptions: {
|
|
390
|
+
show: {
|
|
391
|
+
resource: ['country'],
|
|
392
|
+
operation: ['get', 'getTranslations', 'getRegions'],
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
397
|
+
// Fields — Region
|
|
398
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
399
|
+
// Region: List
|
|
400
|
+
{
|
|
401
|
+
displayName: 'Country ID',
|
|
402
|
+
name: 'countryId',
|
|
403
|
+
type: 'string',
|
|
404
|
+
default: '',
|
|
405
|
+
description: 'Filter regions by country UUID',
|
|
406
|
+
displayOptions: { show: { resource: ['region'], operation: ['list'] } },
|
|
407
|
+
},
|
|
408
|
+
// Region: Get / Get Translations
|
|
409
|
+
{
|
|
410
|
+
displayName: 'Region ID',
|
|
411
|
+
name: 'regionId',
|
|
412
|
+
type: 'string',
|
|
413
|
+
default: '',
|
|
414
|
+
required: true,
|
|
415
|
+
description: 'UUID of the region',
|
|
416
|
+
displayOptions: {
|
|
417
|
+
show: {
|
|
418
|
+
resource: ['region'],
|
|
419
|
+
operation: ['get', 'getTranslations'],
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
displayName: 'Preferred Languages',
|
|
425
|
+
name: 'preferredLanguages',
|
|
426
|
+
type: 'string',
|
|
427
|
+
default: '',
|
|
428
|
+
placeholder: 'fr,es,en',
|
|
429
|
+
description: 'Comma-separated BCP 47 language tags',
|
|
430
|
+
displayOptions: {
|
|
431
|
+
show: {
|
|
432
|
+
resource: ['region'],
|
|
433
|
+
operation: ['getTranslations'],
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
438
|
+
// Fields — Language
|
|
439
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
440
|
+
// Language: List
|
|
441
|
+
{
|
|
442
|
+
displayName: 'Limit',
|
|
443
|
+
name: 'limit',
|
|
444
|
+
type: 'number',
|
|
445
|
+
typeOptions: { minValue: 1, maxValue: 500 },
|
|
446
|
+
default: 50,
|
|
447
|
+
description: 'Max number of results to return',
|
|
448
|
+
displayOptions: { show: { resource: ['language'], operation: ['list'] } },
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
displayName: 'Offset',
|
|
452
|
+
name: 'offset',
|
|
453
|
+
type: 'number',
|
|
454
|
+
typeOptions: { minValue: 0 },
|
|
455
|
+
default: 0,
|
|
456
|
+
description: 'Pagination offset',
|
|
457
|
+
displayOptions: { show: { resource: ['language'], operation: ['list'] } },
|
|
458
|
+
},
|
|
459
|
+
// Language: Get
|
|
460
|
+
{
|
|
461
|
+
displayName: 'Language ID',
|
|
462
|
+
name: 'languageId',
|
|
463
|
+
type: 'string',
|
|
464
|
+
default: '',
|
|
465
|
+
required: true,
|
|
466
|
+
description: 'UUID of the language',
|
|
467
|
+
displayOptions: { show: { resource: ['language'], operation: ['get'] } },
|
|
468
|
+
},
|
|
469
|
+
],
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
async execute() {
|
|
473
|
+
const credentials = await this.getCredentials('geomelonApi');
|
|
474
|
+
const client = new geomelon_1.GeomelonClient({ apiKey: credentials.apiKey });
|
|
475
|
+
const items = this.getInputData();
|
|
476
|
+
const returnData = [];
|
|
477
|
+
for (let i = 0; i < items.length; i++) {
|
|
478
|
+
const resource = this.getNodeParameter('resource', i);
|
|
479
|
+
const operation = this.getNodeParameter('operation', i);
|
|
480
|
+
try {
|
|
481
|
+
let result;
|
|
482
|
+
if (resource === 'city') {
|
|
483
|
+
if (operation === 'search') {
|
|
484
|
+
const params = {};
|
|
485
|
+
const name = this.getNodeParameter('name', i, '');
|
|
486
|
+
const countryCode = this.getNodeParameter('countryCode', i, '');
|
|
487
|
+
const regionId = this.getNodeParameter('regionId', i, '');
|
|
488
|
+
const minPopulation = this.getNodeParameter('minPopulation', i, 0);
|
|
489
|
+
const maxPopulation = this.getNodeParameter('maxPopulation', i, 0);
|
|
490
|
+
const sort = this.getNodeParameter('sort', i);
|
|
491
|
+
const preferredLanguages = this.getNodeParameter('preferredLanguages', i, '');
|
|
492
|
+
const limit = this.getNodeParameter('limit', i);
|
|
493
|
+
const offset = this.getNodeParameter('offset', i);
|
|
494
|
+
if (name)
|
|
495
|
+
params.name = name;
|
|
496
|
+
if (countryCode)
|
|
497
|
+
params.countryCode = countryCode;
|
|
498
|
+
if (regionId)
|
|
499
|
+
params.regionId = regionId;
|
|
500
|
+
if (minPopulation > 0)
|
|
501
|
+
params.minPopulation = minPopulation;
|
|
502
|
+
if (maxPopulation > 0)
|
|
503
|
+
params.maxPopulation = maxPopulation;
|
|
504
|
+
if (sort)
|
|
505
|
+
params.sort = sort;
|
|
506
|
+
if (preferredLanguages)
|
|
507
|
+
params.preferredLanguages = preferredLanguages;
|
|
508
|
+
params.limit = limit;
|
|
509
|
+
params.offset = offset;
|
|
510
|
+
result = await client.cities.search(params);
|
|
511
|
+
}
|
|
512
|
+
else if (operation === 'get') {
|
|
513
|
+
const id = this.getNodeParameter('cityId', i);
|
|
514
|
+
result = await client.cities.get(id);
|
|
515
|
+
}
|
|
516
|
+
else if (operation === 'getTranslations') {
|
|
517
|
+
const id = this.getNodeParameter('cityId', i);
|
|
518
|
+
result = await client.cities.translations(id);
|
|
519
|
+
}
|
|
520
|
+
else if (operation === 'getSettlementTypes') {
|
|
521
|
+
const id = this.getNodeParameter('cityId', i);
|
|
522
|
+
result = await client.cities.settlementTypes(id);
|
|
523
|
+
}
|
|
524
|
+
else if (operation === 'distance') {
|
|
525
|
+
const city1 = this.getNodeParameter('city1', i);
|
|
526
|
+
const city2 = this.getNodeParameter('city2', i);
|
|
527
|
+
result = await client.cities.distance(city1, city2);
|
|
528
|
+
}
|
|
529
|
+
else if (operation === 'byCoordinatesClosest') {
|
|
530
|
+
const lat = this.getNodeParameter('lat', i);
|
|
531
|
+
const lon = this.getNodeParameter('lon', i);
|
|
532
|
+
const preferredLanguages = this.getNodeParameter('preferredLanguages', i, '');
|
|
533
|
+
const params = { lat, lon, ...(preferredLanguages ? { preferredLanguages } : {}) };
|
|
534
|
+
result = await client.cities.byCoordinatesClosest(params);
|
|
535
|
+
}
|
|
536
|
+
else if (operation === 'byCoordinatesLargest') {
|
|
537
|
+
const lat = this.getNodeParameter('lat', i);
|
|
538
|
+
const lon = this.getNodeParameter('lon', i);
|
|
539
|
+
const preferredLanguages = this.getNodeParameter('preferredLanguages', i, '');
|
|
540
|
+
const params = { lat, lon, ...(preferredLanguages ? { preferredLanguages } : {}) };
|
|
541
|
+
result = await client.cities.byCoordinatesLargest(params);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
else if (resource === 'country') {
|
|
545
|
+
if (operation === 'list') {
|
|
546
|
+
const params = {};
|
|
547
|
+
const name = this.getNodeParameter('name', i, '');
|
|
548
|
+
const telephoneCode = this.getNodeParameter('telephoneCode', i, '');
|
|
549
|
+
const preferredLanguages = this.getNodeParameter('preferredLanguages', i, '');
|
|
550
|
+
const limit = this.getNodeParameter('limit', i);
|
|
551
|
+
const offset = this.getNodeParameter('offset', i);
|
|
552
|
+
if (name)
|
|
553
|
+
params.name = name;
|
|
554
|
+
if (telephoneCode)
|
|
555
|
+
params.telephoneCode = telephoneCode;
|
|
556
|
+
if (preferredLanguages)
|
|
557
|
+
params.preferredLanguages = preferredLanguages;
|
|
558
|
+
params.limit = limit;
|
|
559
|
+
params.offset = offset;
|
|
560
|
+
result = await client.countries.list(params);
|
|
561
|
+
}
|
|
562
|
+
else if (operation === 'get') {
|
|
563
|
+
const id = this.getNodeParameter('countryId', i);
|
|
564
|
+
result = await client.countries.get(id);
|
|
565
|
+
}
|
|
566
|
+
else if (operation === 'getTranslations') {
|
|
567
|
+
const id = this.getNodeParameter('countryId', i);
|
|
568
|
+
const preferredLanguages = this.getNodeParameter('preferredLanguages', i, '');
|
|
569
|
+
result = await client.countries.translations(id, preferredLanguages ? { preferredLanguages } : undefined);
|
|
570
|
+
}
|
|
571
|
+
else if (operation === 'getRegions') {
|
|
572
|
+
const id = this.getNodeParameter('countryId', i);
|
|
573
|
+
result = await client.countries.regions(id);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
else if (resource === 'region') {
|
|
577
|
+
if (operation === 'list') {
|
|
578
|
+
const countryId = this.getNodeParameter('countryId', i, '');
|
|
579
|
+
result = await client.regions.list(countryId ? { countryId } : undefined);
|
|
580
|
+
}
|
|
581
|
+
else if (operation === 'get') {
|
|
582
|
+
const id = this.getNodeParameter('regionId', i);
|
|
583
|
+
result = await client.regions.get(id);
|
|
584
|
+
}
|
|
585
|
+
else if (operation === 'getTranslations') {
|
|
586
|
+
const id = this.getNodeParameter('regionId', i);
|
|
587
|
+
const preferredLanguages = this.getNodeParameter('preferredLanguages', i, '');
|
|
588
|
+
result = await client.regions.translations(id, preferredLanguages ? { preferredLanguages } : undefined);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
else if (resource === 'language') {
|
|
592
|
+
if (operation === 'list') {
|
|
593
|
+
const limit = this.getNodeParameter('limit', i);
|
|
594
|
+
const offset = this.getNodeParameter('offset', i);
|
|
595
|
+
result = await client.languages.list({ limit, offset });
|
|
596
|
+
}
|
|
597
|
+
else if (operation === 'get') {
|
|
598
|
+
const id = this.getNodeParameter('languageId', i);
|
|
599
|
+
result = await client.languages.get(id);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (result === undefined) {
|
|
603
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation "${operation}" for resource "${resource}"`, { itemIndex: i });
|
|
604
|
+
}
|
|
605
|
+
const items = Array.isArray(result) ? result : [result];
|
|
606
|
+
for (const item of items) {
|
|
607
|
+
returnData.push({ json: item, pairedItem: { item: i } });
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
catch (error) {
|
|
611
|
+
if (this.continueOnFail()) {
|
|
612
|
+
returnData.push({
|
|
613
|
+
json: { error: error.message },
|
|
614
|
+
pairedItem: { item: i },
|
|
615
|
+
});
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
throw error;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return [returnData];
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
exports.Geomelon = Geomelon;
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-geomelon",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n community node for the Geomelon geographic API — cities, countries, regions, and languages with multilingual support",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"geomelon",
|
|
8
|
+
"geography",
|
|
9
|
+
"cities",
|
|
10
|
+
"countries",
|
|
11
|
+
"geocoding"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"homepage": "https://geomelon.dev",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/930m310n/n8n-nodes-geomelon.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/930m310n/n8n-nodes-geomelon/issues"
|
|
21
|
+
},
|
|
22
|
+
"author": {
|
|
23
|
+
"name": "Geomelon"
|
|
24
|
+
},
|
|
25
|
+
"n8n": {
|
|
26
|
+
"n8nNodesApiVersion": 1,
|
|
27
|
+
"credentials": [
|
|
28
|
+
"dist/credentials/GeomelonApi.credentials.js"
|
|
29
|
+
],
|
|
30
|
+
"nodes": [
|
|
31
|
+
"dist/nodes/Geomelon/Geomelon.node.js"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"main": "index.js",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc --project tsconfig.json",
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"geomelon": "^1.0.7"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"n8n-workflow": "*"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^20.0.0",
|
|
51
|
+
"n8n-workflow": "^1.120.0",
|
|
52
|
+
"typescript": "^5.4.0"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18"
|
|
56
|
+
}
|
|
57
|
+
}
|