@liftitinc/geocoding 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/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # @liftit/geocoding
2
+
3
+ ![npm version](https://img.shields.io/npm/v/@liftit/geocoding.svg)
4
+ ![License](https://img.shields.io/npm/l/@liftit/geocoding.svg)
5
+ ![Node version](https://img.shields.io/node/v/@liftit/geocoding.svg)
6
+
7
+ JavaScript/TypeScript SDK for the Liftit Geocoding API.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @liftit/geocoding
13
+ # or
14
+ pnpm add @liftit/geocoding
15
+ # or
16
+ yarn add @liftit/geocoding
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```typescript
22
+ import { GeocodingClient } from '@liftit/geocoding';
23
+
24
+ const client = new GeocodingClient({
25
+ apiKey: 'your-api-key',
26
+ // Optional configuration:
27
+ // baseUrl: 'https://geocoding.liftit.co',
28
+ // timeout: 10000,
29
+ // maxRetries: 3,
30
+ });
31
+
32
+ // Forward geocoding - convert address to coordinates
33
+ const result = await client.geocode({
34
+ country: 'co',
35
+ city: 'Bogota',
36
+ address: 'Calle 100 # 19-61',
37
+ // Optional parameters:
38
+ // region: 'Cundinamarca',
39
+ // custom_zone: true,
40
+ });
41
+
42
+ console.log(result.location); // { lat: 4.6097, lng: -74.0817 }
43
+ console.log(result.geocode.formatted_address);
44
+
45
+ // Reverse geocoding - convert coordinates to address
46
+ const address = await client.reverseGeocode({
47
+ lat: 4.6097,
48
+ lng: -74.0817,
49
+ });
50
+
51
+ console.log(address.geocode.formatted_address);
52
+ console.log(address.address_components?.city);
53
+ ```
54
+
55
+ ## Features
56
+
57
+ - **TypeScript Support**: Full type definitions with comprehensive type safety
58
+ - **Zero Dependencies**: Uses native `fetch` API (Node.js 18+ required)
59
+ - **Automatic Retry**: Exponential backoff with full jitter for transient errors
60
+ - **Rate Limit Handling**: Respects `Retry-After` headers automatically
61
+ - **Error Hierarchy**: Typed error classes for precise error handling
62
+ - **Zod Schemas**: Exported schemas for request/response validation
63
+
64
+ ## Configuration
65
+
66
+ | Parameter | Type | Default | Description |
67
+ |-----------|------|---------|-------------|
68
+ | `apiKey` | `string` | Required | Your Liftit Geocoding API key |
69
+ | `baseUrl` | `string` | `"https://geocoding.liftit.co"` | API base URL |
70
+ | `timeout` | `number` | `10000` | Request timeout in milliseconds |
71
+ | `maxRetries` | `number` | `3` | Maximum retry attempts for transient errors |
72
+ | `baseDelay` | `number` | `1000` | Initial retry delay in milliseconds |
73
+ | `maxDelay` | `number` | `30000` | Maximum retry delay cap in milliseconds |
74
+
75
+ **Example:**
76
+
77
+ ```typescript
78
+ const client = new GeocodingClient({
79
+ apiKey: 'your-api-key',
80
+ timeout: 15000,
81
+ maxRetries: 5,
82
+ baseDelay: 2000,
83
+ maxDelay: 60000,
84
+ });
85
+ ```
86
+
87
+ ## Retry Behavior
88
+
89
+ The SDK automatically retries requests for transient errors:
90
+
91
+ | Error Type | Retryable | Strategy |
92
+ |------------|-----------|----------|
93
+ | Rate limit (429) | Yes | Uses `Retry-After` header if present |
94
+ | Server error (500, 502, 503, 504) | Yes | Exponential backoff with full jitter |
95
+ | Timeout | Yes | Exponential backoff with full jitter |
96
+ | Network errors | Yes | Exponential backoff with full jitter |
97
+ | Validation (400) | No | Fails immediately |
98
+ | Authentication (401) | No | Fails immediately |
99
+ | User abort | No | Fails immediately |
100
+
101
+ ### Retry Timing
102
+
103
+ - **Initial delay**: 1 second (configurable via `baseDelay`)
104
+ - **Maximum delay**: 30 seconds (configurable via `maxDelay`)
105
+ - **Multiplier**: 2x exponential growth
106
+ - **Jitter**: Full random jitter (0 to calculated delay)
107
+ - **Default attempts**: 3 retries (configurable via `maxRetries`)
108
+
109
+ **Formula:** `delay = min(baseDelay * 2^attempt * random(), maxDelay)`
110
+
111
+ ### Disabling Retries
112
+
113
+ ```typescript
114
+ // Disable retries for testing or special cases
115
+ const client = new GeocodingClient({
116
+ apiKey: 'your-api-key',
117
+ maxRetries: 0,
118
+ });
119
+ ```
120
+
121
+ ## Error Handling
122
+
123
+ The SDK provides a comprehensive error hierarchy:
124
+
125
+ ```typescript
126
+ import {
127
+ GeocodingClient,
128
+ GeocodeError,
129
+ ValidationError,
130
+ AuthenticationError,
131
+ RateLimitError,
132
+ UpstreamError,
133
+ } from '@liftit/geocoding';
134
+
135
+ const client = new GeocodingClient({ apiKey: 'your-api-key' });
136
+
137
+ try {
138
+ const result = await client.geocode({
139
+ country: 'co',
140
+ city: 'Bogota',
141
+ address: 'Calle 100 # 19-61',
142
+ });
143
+ } catch (error) {
144
+ if (error instanceof ValidationError) {
145
+ // Invalid request parameters (400)
146
+ console.error(`Validation error: ${error.message}`);
147
+ console.error(`Request ID: ${error.requestId}`);
148
+ } else if (error instanceof AuthenticationError) {
149
+ // Invalid API key (401)
150
+ console.error(`Authentication failed: ${error.message}`);
151
+ } else if (error instanceof RateLimitError) {
152
+ // Rate limit exceeded (429)
153
+ console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
154
+ console.error(`Limit: ${error.limit}, Remaining: ${error.remaining}`);
155
+
156
+ // Calculate optimal retry delay
157
+ const delayMs = error.getRetryDelay();
158
+ await new Promise(resolve => setTimeout(resolve, delayMs));
159
+ // Retry request...
160
+ } else if (error instanceof UpstreamError) {
161
+ // API server error (500-599)
162
+ console.error(`Upstream error: ${error.message}`);
163
+ console.error(`Status code: ${error.statusCode}`);
164
+ } else if (error instanceof GeocodeError) {
165
+ // Base class catches all SDK errors
166
+ console.error(`Geocoding error [${error.code}]: ${error.message}`);
167
+ }
168
+ }
169
+ ```
170
+
171
+ **Error Properties:**
172
+
173
+ | Error Class | Properties |
174
+ |-------------|------------|
175
+ | `GeocodeError` | `message`, `code`, `requestId` |
176
+ | `ValidationError` | Inherits from `GeocodeError` |
177
+ | `AuthenticationError` | Inherits from `GeocodeError` |
178
+ | `RateLimitError` | Inherits + `retryAfter`, `limit`, `remaining`, `getRetryDelay()` |
179
+ | `UpstreamError` | Inherits + `statusCode` |
180
+
181
+ ## API Reference
182
+
183
+ ### Forward Geocoding
184
+
185
+ Convert an address to geographic coordinates.
186
+
187
+ **Method:** `client.geocode(request, options?)`
188
+
189
+ **Parameters:**
190
+
191
+ | Parameter | Type | Required | Description |
192
+ |-----------|------|----------|-------------|
193
+ | `request.country` | `string` | Yes | ISO 3166-1 alpha-2 country code (ar, br, cl, co, ec, mx, pe) |
194
+ | `request.address` | `string` | Yes | Street address to geocode |
195
+ | `request.city` | `string` | No | City name (recommended for accuracy) |
196
+ | `request.region` | `string` | No | State/department name |
197
+ | `request.custom_zone` | `boolean` | No | Include zone information (default: false) |
198
+ | `options.signal` | `AbortSignal` | No | AbortSignal for request cancellation |
199
+
200
+ **Response:**
201
+
202
+ ```typescript
203
+ {
204
+ success: true,
205
+ data: {
206
+ location: { lat: number, lng: number },
207
+ geocode: { formatted_address: string },
208
+ cleaned_address: boolean,
209
+ zone?: { id: number, name: string, type: string }
210
+ },
211
+ requestId: string
212
+ }
213
+ ```
214
+
215
+ **Example:**
216
+
217
+ ```typescript
218
+ const result = await client.geocode({
219
+ country: 'co',
220
+ city: 'Bogota',
221
+ address: 'Calle 100 # 19-61',
222
+ custom_zone: true,
223
+ });
224
+
225
+ console.log(result.location); // { lat: 4.6097, lng: -74.0817 }
226
+ console.log(result.zone?.name); // "Zone 1"
227
+ ```
228
+
229
+ ### Reverse Geocoding
230
+
231
+ Convert geographic coordinates to an address.
232
+
233
+ **Method:** `client.reverseGeocode(request, options?)`
234
+
235
+ **Parameters:**
236
+
237
+ | Parameter | Type | Required | Description |
238
+ |-----------|------|----------|-------------|
239
+ | `request.lat` | `number` | Yes | Latitude (-90 to 90) |
240
+ | `request.lng` | `number` | Yes | Longitude (-180 to 180) |
241
+ | `options.signal` | `AbortSignal` | No | AbortSignal for request cancellation |
242
+
243
+ **Response:**
244
+
245
+ ```typescript
246
+ {
247
+ success: true,
248
+ data: {
249
+ geocode: { formatted_address: string },
250
+ location: { lat: number, lng: number },
251
+ address_components: {
252
+ city: string,
253
+ country: string
254
+ }
255
+ },
256
+ requestId: string
257
+ }
258
+ ```
259
+
260
+ **Example:**
261
+
262
+ ```typescript
263
+ const address = await client.reverseGeocode({
264
+ lat: 4.6097,
265
+ lng: -74.0817,
266
+ });
267
+
268
+ console.log(address.geocode.formatted_address);
269
+ console.log(address.address_components?.city); // "Bogota"
270
+ ```
271
+
272
+ ## Supported Countries
273
+
274
+ The SDK supports geocoding in the following countries:
275
+
276
+ | Country | Code | Example City |
277
+ |---------|------|--------------|
278
+ | Argentina | `ar` | Buenos Aires |
279
+ | Brazil | `br` | Sao Paulo |
280
+ | Chile | `cl` | Santiago |
281
+ | Colombia | `co` | Bogota |
282
+ | Ecuador | `ec` | Quito |
283
+ | Mexico | `mx` | Mexico City |
284
+ | Peru | `pe` | Lima |
285
+
286
+ ## Requirements
287
+
288
+ - **Node.js**: >= 18.0.0 (required for native `fetch` API)
289
+ - **Runtime Dependencies**: None (zero dependencies)
290
+ - **TypeScript**: >= 5.0 (for TypeScript projects)
291
+
292
+ ## Development
293
+
294
+ ```bash
295
+ # Clone the repository
296
+ git clone https://github.com/Liftitapp/geocoding-enterprise.git
297
+ cd geocoding-enterprise
298
+
299
+ # Install dependencies
300
+ pnpm install
301
+
302
+ # Build the SDK
303
+ pnpm --filter @liftit/geocoding build
304
+
305
+ # Run tests
306
+ pnpm --filter @liftit/geocoding test
307
+
308
+ # Type checking
309
+ pnpm --filter @liftit/geocoding typecheck
310
+
311
+ # Lint
312
+ pnpm --filter @liftit/geocoding lint
313
+ ```
314
+
315
+ ## License
316
+
317
+ MIT - see [LICENSE](./LICENSE) for details.
318
+
319
+ ## Support
320
+
321
+ - **GitHub Issues**: [Report bugs and request features](https://github.com/Liftitapp/geocoding-enterprise/issues)
322
+ - **API Reference**: [View API documentation](https://geocoding.liftit.co/docs)
323
+ - **Homepage**: [https://geocoding.liftit.co](https://geocoding.liftit.co)