csv2geo-sdk 1.1.0 → 1.3.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 +6 -1
- package/package.json +2 -2
- package/src/index.d.ts +39 -1
- package/src/index.js +126 -3
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ if (result) {
|
|
|
51
51
|
const { Client } = require('csv2geo-sdk');
|
|
52
52
|
|
|
53
53
|
const client = new Client('your_api_key', {
|
|
54
|
-
baseUrl: 'https://
|
|
54
|
+
baseUrl: 'https://csv2geo.com/api/v1', // optional
|
|
55
55
|
timeout: 30000, // optional, milliseconds
|
|
56
56
|
autoRetry: true, // optional, retry on rate limit
|
|
57
57
|
});
|
|
@@ -203,6 +203,11 @@ Sign up at [csv2geo.com](https://csv2geo.com) to get your API key.
|
|
|
203
203
|
- [API Documentation](https://acenji.github.io/csv2geo-api/docs/)
|
|
204
204
|
- [OpenAPI Specification](https://github.com/acenji/csv2geo-api/blob/main/openapi.yaml)
|
|
205
205
|
|
|
206
|
+
## Community & Support
|
|
207
|
+
|
|
208
|
+
- **Questions & feature requests:** [GitHub Discussions](https://github.com/acenji/csv2geo-api/discussions)
|
|
209
|
+
- **Bug reports:** [GitHub Issues](https://github.com/acenji/csv2geo-api/issues)
|
|
210
|
+
|
|
206
211
|
## License
|
|
207
212
|
|
|
208
213
|
MIT License - see [LICENSE](https://github.com/acenji/csv2geo-api/blob/main/LICENSE) for details.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "csv2geo-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Node.js SDK for CSV2GEO Geocoding API — 461M+ addresses, 39 countries,
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Node.js SDK for CSV2GEO Geocoding API — 461M+ addresses, 39 countries, 45+ endpoints. Forward, reverse, batch, places, boundaries (postcode → polygon, ancestors walk-up, children walk-down, consolidated cities), IP geolocation with county overlay, coverage, autocomplete. 3,000 free requests/day.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
7
7
|
"files": [
|
package/src/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export interface ClientOptions {
|
|
6
|
-
/** API base URL (default: https://
|
|
6
|
+
/** API base URL (default: https://csv2geo.com/api/v1) */
|
|
7
7
|
baseUrl?: string;
|
|
8
8
|
/** Request timeout in milliseconds (default: 30000) */
|
|
9
9
|
timeout?: number;
|
|
@@ -105,6 +105,44 @@ export class Client {
|
|
|
105
105
|
* @returns Array of responses
|
|
106
106
|
*/
|
|
107
107
|
reverseBatch(coordinates: Coordinate[]): Promise<GeocodeResponse[]>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* IP geolocation. Returns country/region/city/postcode/location/timezone/ISP,
|
|
111
|
+
* plus county + locality + confidence for residential IPs (Sprint 2.7).
|
|
112
|
+
* @param ip IPv4 or IPv6 string
|
|
113
|
+
*/
|
|
114
|
+
ip(ip: string): Promise<IPGeoResponse>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Like {@link ip}, but uses the requester's IP.
|
|
118
|
+
*/
|
|
119
|
+
ipMe(): Promise<IPGeoResponse>;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Batch IP lookup. Up to 1000 IPs per call.
|
|
123
|
+
*/
|
|
124
|
+
ipBatch(ips: string[]): Promise<{ results: IPGeoResponse[] }>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface IPGeoResponse {
|
|
128
|
+
ip: string;
|
|
129
|
+
country?: { code: string; name?: string; wikidata?: string };
|
|
130
|
+
region?: { code?: string; name?: string };
|
|
131
|
+
city?: { name: string };
|
|
132
|
+
postcode?: string;
|
|
133
|
+
location?: {
|
|
134
|
+
latitude: number;
|
|
135
|
+
longitude: number;
|
|
136
|
+
accuracy_radius_km: number;
|
|
137
|
+
};
|
|
138
|
+
timezone?: string;
|
|
139
|
+
isp?: { asn?: number; name?: string };
|
|
140
|
+
county?: { name: string; subtype?: string; wikidata?: string };
|
|
141
|
+
locality?: { name: string; subtype?: string; wikidata?: string };
|
|
142
|
+
confidence?: 'high' | 'medium' | 'low';
|
|
143
|
+
accuracy_disclaimer?: string;
|
|
144
|
+
source: string;
|
|
145
|
+
db_build_at?: string;
|
|
108
146
|
}
|
|
109
147
|
|
|
110
148
|
export class CSV2GEOError extends Error {
|
package/src/index.js
CHANGED
|
@@ -20,7 +20,7 @@ const {
|
|
|
20
20
|
APIError,
|
|
21
21
|
} = require('./errors');
|
|
22
22
|
|
|
23
|
-
const DEFAULT_BASE_URL = 'https://
|
|
23
|
+
const DEFAULT_BASE_URL = 'https://csv2geo.com/api/v1';
|
|
24
24
|
const DEFAULT_TIMEOUT = 30000;
|
|
25
25
|
const MAX_RETRIES = 3;
|
|
26
26
|
|
|
@@ -75,7 +75,7 @@ class Client {
|
|
|
75
75
|
headers: {
|
|
76
76
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
77
77
|
'Content-Type': 'application/json',
|
|
78
|
-
'User-Agent': 'csv2geo-node/1.
|
|
78
|
+
'User-Agent': 'csv2geo-node/1.3.0',
|
|
79
79
|
},
|
|
80
80
|
signal: controller.signal,
|
|
81
81
|
};
|
|
@@ -497,7 +497,12 @@ class Client {
|
|
|
497
497
|
return this._request('GET', '/divisions/random', params);
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
/**
|
|
500
|
+
/**
|
|
501
|
+
* Children of a division (immediate sub-divisions). GET /divisions/hierarchy/{id}
|
|
502
|
+
*
|
|
503
|
+
* Note: returns CHILDREN, not ancestors. For walk-UP "part-of" chain, use
|
|
504
|
+
* `divisionAncestors()`. Kept under the original name for backward compatibility.
|
|
505
|
+
*/
|
|
501
506
|
async divisionHierarchy(divisionId) {
|
|
502
507
|
return this._request('GET', `/divisions/hierarchy/${encodeURIComponent(divisionId)}`);
|
|
503
508
|
}
|
|
@@ -507,6 +512,74 @@ class Client {
|
|
|
507
512
|
return this._request('GET', `/divisions/${encodeURIComponent(divisionId)}`);
|
|
508
513
|
}
|
|
509
514
|
|
|
515
|
+
// ─────────────────────────────────────────────────────────
|
|
516
|
+
// Boundaries (Sprint 1.8)
|
|
517
|
+
// ─────────────────────────────────────────────────────────
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Walk-up "part-of" chain: input → parent → root.
|
|
521
|
+
* GET /divisions/ancestors/{id}
|
|
522
|
+
*
|
|
523
|
+
* @param {string} divisionId - Overture ID of the leaf division.
|
|
524
|
+
* @param {object} [options]
|
|
525
|
+
* @param {string} [options.include] - "geometry" to include each level's polygon.
|
|
526
|
+
* @param {string} [options.precision] - "low" | "med" (default) | "full".
|
|
527
|
+
* @param {number} [options.maxDepth] - Hard cap (default 8, max 12).
|
|
528
|
+
* @returns {Promise<{id: string, depth: number, results: object[]}>}
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* const chain = await client.divisionAncestors(beverlyHillsId, { include: 'geometry' });
|
|
532
|
+
* chain.results.forEach(level => console.log(level.subtype, level.name));
|
|
533
|
+
*/
|
|
534
|
+
async divisionAncestors(divisionId, options = {}) {
|
|
535
|
+
const params = {};
|
|
536
|
+
if (options.include) params.include = options.include;
|
|
537
|
+
if (options.precision) params.precision = options.precision;
|
|
538
|
+
if (options.maxDepth) params.max_depth = options.maxDepth;
|
|
539
|
+
return this._request('GET', `/divisions/ancestors/${encodeURIComponent(divisionId)}`, params);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Immediate sub-divisions of a division (clearer-named alias of
|
|
544
|
+
* divisionHierarchy plus optional polygon enrichment).
|
|
545
|
+
* GET /divisions/children/{id}
|
|
546
|
+
*
|
|
547
|
+
* @param {string} divisionId
|
|
548
|
+
* @param {object} [options]
|
|
549
|
+
* @param {string} [options.include] - "geometry" to include polygons.
|
|
550
|
+
* @param {string} [options.precision] - "low" | "med" (default) | "full".
|
|
551
|
+
* @param {string} [options.subtype] - Filter by admin subtype.
|
|
552
|
+
* @param {number} [options.limit] - Max children (default 100, max 500).
|
|
553
|
+
*/
|
|
554
|
+
async divisionChildren(divisionId, options = {}) {
|
|
555
|
+
const params = {};
|
|
556
|
+
if (options.include) params.include = options.include;
|
|
557
|
+
if (options.precision) params.precision = options.precision;
|
|
558
|
+
if (options.subtype) params.subtype = options.subtype;
|
|
559
|
+
if (options.limit) params.limit = options.limit;
|
|
560
|
+
return this._request('GET', `/divisions/children/${encodeURIComponent(divisionId)}`, params);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Consolidated entity lookup. Resolves canonical OR member id — e.g. any of
|
|
565
|
+
* NYC's 5 borough ids returns the canonical "New York City" record + members.
|
|
566
|
+
* GET /divisions/consolidated/{id}
|
|
567
|
+
*
|
|
568
|
+
* @param {string} divisionId
|
|
569
|
+
* @param {object} [options]
|
|
570
|
+
* @param {string} [options.include] - "geometry" for canonical's outline.
|
|
571
|
+
* @param {string} [options.precision] - "low" | "med" (default) | "full".
|
|
572
|
+
* @returns {Promise<{canonical: object, members: object[], matched_as: string, source: string}>}
|
|
573
|
+
*
|
|
574
|
+
* @throws ApiError(404) when the id is not part of any consolidated entity.
|
|
575
|
+
*/
|
|
576
|
+
async divisionConsolidated(divisionId, options = {}) {
|
|
577
|
+
const params = {};
|
|
578
|
+
if (options.include) params.include = options.include;
|
|
579
|
+
if (options.precision) params.precision = options.precision;
|
|
580
|
+
return this._request('GET', `/divisions/consolidated/${encodeURIComponent(divisionId)}`, params);
|
|
581
|
+
}
|
|
582
|
+
|
|
510
583
|
// ─────────────────────────────────────────────────────────
|
|
511
584
|
// Coverage
|
|
512
585
|
// ─────────────────────────────────────────────────────────
|
|
@@ -563,6 +636,56 @@ class Client {
|
|
|
563
636
|
},
|
|
564
637
|
};
|
|
565
638
|
}
|
|
639
|
+
|
|
640
|
+
// ─────────────────────────────────────────────────────────
|
|
641
|
+
// IP geolocation (Sprint 2.7)
|
|
642
|
+
//
|
|
643
|
+
// MaxMind GeoLite2 .mmdb lookup with our county overlay.
|
|
644
|
+
// Bundled into every plan (including Free); no separate billing.
|
|
645
|
+
// ─────────────────────────────────────────────────────────
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* IP → geolocation. Returns country, region, city, postcode, location,
|
|
649
|
+
* timezone, ISP, and (for residential IPs) county + locality + confidence.
|
|
650
|
+
*
|
|
651
|
+
* @param {string} ip - IPv4 or IPv6 address (e.g. "8.8.8.8")
|
|
652
|
+
* @returns {Promise<Object>} canonical /v1/ip response shape
|
|
653
|
+
* @example
|
|
654
|
+
* const r = await client.ip('8.8.8.8');
|
|
655
|
+
* console.log(r.country.code, r.county?.name, r.confidence);
|
|
656
|
+
*/
|
|
657
|
+
async ip(ip) {
|
|
658
|
+
if (!ip || typeof ip !== 'string') {
|
|
659
|
+
throw new InvalidRequestError('ip must be a non-empty string');
|
|
660
|
+
}
|
|
661
|
+
return this._request('GET', '/ip', { ip });
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Like {@link ip}, but uses the requester's IP (the one Laravel sees).
|
|
666
|
+
* Useful from browser/server contexts where you want "where is the caller".
|
|
667
|
+
*
|
|
668
|
+
* @returns {Promise<Object>} canonical /v1/ip response shape
|
|
669
|
+
*/
|
|
670
|
+
async ipMe() {
|
|
671
|
+
return this._request('GET', '/ip/me');
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Batch IP lookup. Up to 1000 IPs per call.
|
|
676
|
+
*
|
|
677
|
+
* @param {string[]} ips - array of IPs
|
|
678
|
+
* @returns {Promise<{results: Object[]}>}
|
|
679
|
+
*/
|
|
680
|
+
async ipBatch(ips) {
|
|
681
|
+
if (!Array.isArray(ips) || ips.length === 0) {
|
|
682
|
+
throw new InvalidRequestError('ips must be a non-empty array');
|
|
683
|
+
}
|
|
684
|
+
if (ips.length > 1000) {
|
|
685
|
+
throw new InvalidRequestError('ipBatch supports at most 1000 IPs per call');
|
|
686
|
+
}
|
|
687
|
+
return this._request('POST', '/ip/batch', {}, { ips });
|
|
688
|
+
}
|
|
566
689
|
}
|
|
567
690
|
|
|
568
691
|
module.exports = {
|