csv2geo-sdk 1.1.0 → 1.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/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://api.csv2geo.com/v1', // optional
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.1.0",
4
- "description": "Node.js SDK for CSV2GEO Geocoding API — 461M+ addresses, 39 countries, 42 endpoints. Forward, reverse, batch, places, divisions (incl. postcode → boundary), coverage, autocomplete. 3,000 free requests/day.",
3
+ "version": "1.2.0",
4
+ "description": "Node.js SDK for CSV2GEO Geocoding API — 461M+ addresses, 39 countries, 42+ endpoints. Forward, reverse, batch, places, divisions (incl. postcode → boundary), 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://api.csv2geo.com/v1) */
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://api.csv2geo.com/v1';
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.0.0',
78
+ 'User-Agent': 'csv2geo-node/1.2.0',
79
79
  },
80
80
  signal: controller.signal,
81
81
  };
@@ -563,6 +563,56 @@ class Client {
563
563
  },
564
564
  };
565
565
  }
566
+
567
+ // ─────────────────────────────────────────────────────────
568
+ // IP geolocation (Sprint 2.7)
569
+ //
570
+ // MaxMind GeoLite2 .mmdb lookup with our county overlay.
571
+ // Bundled into every plan (including Free); no separate billing.
572
+ // ─────────────────────────────────────────────────────────
573
+
574
+ /**
575
+ * IP → geolocation. Returns country, region, city, postcode, location,
576
+ * timezone, ISP, and (for residential IPs) county + locality + confidence.
577
+ *
578
+ * @param {string} ip - IPv4 or IPv6 address (e.g. "8.8.8.8")
579
+ * @returns {Promise<Object>} canonical /v1/ip response shape
580
+ * @example
581
+ * const r = await client.ip('8.8.8.8');
582
+ * console.log(r.country.code, r.county?.name, r.confidence);
583
+ */
584
+ async ip(ip) {
585
+ if (!ip || typeof ip !== 'string') {
586
+ throw new InvalidRequestError('ip must be a non-empty string');
587
+ }
588
+ return this._request('GET', '/ip', { ip });
589
+ }
590
+
591
+ /**
592
+ * Like {@link ip}, but uses the requester's IP (the one Laravel sees).
593
+ * Useful from browser/server contexts where you want "where is the caller".
594
+ *
595
+ * @returns {Promise<Object>} canonical /v1/ip response shape
596
+ */
597
+ async ipMe() {
598
+ return this._request('GET', '/ip/me');
599
+ }
600
+
601
+ /**
602
+ * Batch IP lookup. Up to 1000 IPs per call.
603
+ *
604
+ * @param {string[]} ips - array of IPs
605
+ * @returns {Promise<{results: Object[]}>}
606
+ */
607
+ async ipBatch(ips) {
608
+ if (!Array.isArray(ips) || ips.length === 0) {
609
+ throw new InvalidRequestError('ips must be a non-empty array');
610
+ }
611
+ if (ips.length > 1000) {
612
+ throw new InvalidRequestError('ipBatch supports at most 1000 IPs per call');
613
+ }
614
+ return this._request('POST', '/ip/batch', {}, { ips });
615
+ }
566
616
  }
567
617
 
568
618
  module.exports = {