@chaosity/location-client 0.1.7 → 0.1.8
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 +142 -128
- package/dist/server/getClientConfig.js +6 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
AWS Location Service compatible client with custom Bearer token authentication.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Security Warning
|
|
6
6
|
|
|
7
7
|
**This package contains server-side authentication utilities that require client credentials.**
|
|
8
8
|
|
|
9
|
-
- `TokenProvider` and `getClientConfig()` are **SERVER-SIDE ONLY**
|
|
9
|
+
- `TokenProvider` and `getClientConfig()` are **SERVER-SIDE ONLY** (import from `@chaosity/location-client/server`)
|
|
10
10
|
- They require `clientId` and `clientSecret` which must **NEVER** be exposed to browsers
|
|
11
11
|
- Only use these in:
|
|
12
12
|
- Node.js servers
|
|
@@ -14,7 +14,7 @@ AWS Location Service compatible client with custom Bearer token authentication.
|
|
|
14
14
|
- Next.js API routes
|
|
15
15
|
- Backend services
|
|
16
16
|
|
|
17
|
-
**For React applications**, use [`@chaosity/location-client-react`](https://www.npmjs.com/package/@chaosity/location-client-react) which handles authentication safely.
|
|
17
|
+
**For React applications**, use [`@chaosity/location-client-react`](https://www.npmjs.com/package/@chaosity/location-client-react) which handles authentication and token refresh safely.
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
@@ -27,115 +27,152 @@ npm install @chaosity/location-client
|
|
|
27
27
|
- **Custom Authentication**: Uses Bearer tokens instead of AWS SigV4
|
|
28
28
|
- **AWS SDK Commands**: Full access to all AWS Location Service commands
|
|
29
29
|
- **Data Type Utilities**: Built-in GeoJSON conversion utilities
|
|
30
|
-
- **MapLibre Integration**: Adapter for MapLibre GL Geocoder
|
|
30
|
+
- **MapLibre Integration**: Adapter for MapLibre GL Geocoder and `createTransformRequest` helper
|
|
31
|
+
- **Server Utilities**: `getClientConfig()` with auto-env detection and token caching
|
|
31
32
|
|
|
32
33
|
## Quick Start
|
|
33
34
|
|
|
34
|
-
###
|
|
35
|
+
### Server-Side: Get Config with Auto-Authentication
|
|
36
|
+
|
|
37
|
+
The simplest way to authenticate server-side. Reads credentials from environment variables automatically.
|
|
35
38
|
|
|
36
39
|
```typescript
|
|
37
|
-
|
|
40
|
+
// app/actions/location.ts
|
|
41
|
+
'use server'
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
import { getClientConfig } from '@chaosity/location-client/server'
|
|
44
|
+
|
|
45
|
+
export async function getLocationConfig() {
|
|
46
|
+
// Auto-reads LOCATION_API_URL, LOCATION_CLIENT_ID, LOCATION_CLIENT_SECRET
|
|
47
|
+
return await getClientConfig()
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Set these environment variables:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
LOCATION_API_URL=https://api.chaosity.cloud
|
|
55
|
+
LOCATION_CLIENT_ID=your-client-id
|
|
56
|
+
LOCATION_CLIENT_SECRET=your-client-secret
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or pass credentials explicitly:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const config = await getClientConfig({
|
|
63
|
+
apiUrl: 'https://api.chaosity.cloud',
|
|
64
|
+
clientId: process.env.MY_CLIENT_ID!,
|
|
65
|
+
clientSecret: process.env.MY_SECRET!,
|
|
42
66
|
})
|
|
67
|
+
// config = { apiUrl, token, expiresAt }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Client-Side: Using the GeoPlacesClient
|
|
43
71
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
72
|
+
```typescript
|
|
73
|
+
import { GeoPlacesClient, SuggestCommand } from '@chaosity/location-client'
|
|
74
|
+
|
|
75
|
+
const client = new GeoPlacesClient({
|
|
76
|
+
apiUrl: 'https://api.chaosity.cloud',
|
|
77
|
+
token: 'your-bearer-token',
|
|
47
78
|
})
|
|
48
79
|
|
|
49
|
-
const response = await client.send(
|
|
80
|
+
const response = await client.send(
|
|
81
|
+
new SuggestCommand({ QueryText: 'Vancouver', MaxResults: 5 })
|
|
82
|
+
)
|
|
50
83
|
```
|
|
51
84
|
|
|
52
|
-
###
|
|
85
|
+
### MapLibre Map Integration
|
|
86
|
+
|
|
87
|
+
Use `createTransformRequest` to automatically attach Bearer tokens to map tile requests:
|
|
53
88
|
|
|
54
89
|
```typescript
|
|
55
|
-
|
|
56
|
-
|
|
90
|
+
import { createTransformRequest } from '@chaosity/location-client'
|
|
91
|
+
import maplibregl from 'maplibre-gl'
|
|
57
92
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
grant_type: 'client_credentials'
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const data = await response.json()
|
|
70
|
-
return {
|
|
71
|
-
apiUrl: 'https://api.example.com',
|
|
72
|
-
token: data.access_token
|
|
73
|
-
}
|
|
74
|
-
}
|
|
93
|
+
const map = new maplibregl.Map({
|
|
94
|
+
container: 'map',
|
|
95
|
+
style: `${apiUrl}/maps/Standard/descriptor`,
|
|
96
|
+
center: [-123.12, 49.28],
|
|
97
|
+
zoom: 10,
|
|
98
|
+
transformRequest: createTransformRequest(apiUrl, getToken),
|
|
99
|
+
})
|
|
75
100
|
```
|
|
76
101
|
|
|
77
|
-
|
|
102
|
+
`createTransformRequest` handles setting the correct `Accept` headers for tiles (protobuf), glyphs, sprites, and style descriptors.
|
|
103
|
+
|
|
104
|
+
### MapLibre Geocoder Integration
|
|
78
105
|
|
|
79
106
|
```typescript
|
|
80
|
-
import { GeoPlaces } from '@chaosity/location-client'
|
|
107
|
+
import { GeoPlacesClient, GeoPlaces } from '@chaosity/location-client'
|
|
81
108
|
import MaplibreGeocoder from '@maplibre/maplibre-gl-geocoder'
|
|
82
109
|
import maplibregl from 'maplibre-gl'
|
|
83
110
|
|
|
84
|
-
|
|
85
|
-
const
|
|
111
|
+
// GeoPlaces adapter takes a GeoPlacesClient instance and the map
|
|
112
|
+
const client = new GeoPlacesClient({ apiUrl, token })
|
|
113
|
+
const geoPlaces = new GeoPlaces(client, map)
|
|
86
114
|
|
|
87
|
-
// Add geocoder control
|
|
88
115
|
const geocoder = new MaplibreGeocoder(geoPlaces, {
|
|
89
116
|
maplibregl,
|
|
90
117
|
showResultsWhileTyping: true,
|
|
91
|
-
limit: 30
|
|
118
|
+
limit: 30,
|
|
92
119
|
})
|
|
93
120
|
|
|
94
121
|
map.addControl(geocoder, 'top-left')
|
|
95
122
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const details = await geoPlaces.searchByPlaceId(id)
|
|
101
|
-
console.log('Place details:', details)
|
|
102
|
-
}
|
|
123
|
+
// The geocoder calls getSuggestions → searchByPlaceId internally.
|
|
124
|
+
// The 'result' event fires with the resolved place feature.
|
|
125
|
+
geocoder.on('result', (event) => {
|
|
126
|
+
console.log('Selected place:', event.result)
|
|
103
127
|
})
|
|
104
128
|
```
|
|
105
129
|
|
|
106
130
|
## API Reference
|
|
107
131
|
|
|
108
|
-
###
|
|
132
|
+
### Main Exports (`@chaosity/location-client`)
|
|
133
|
+
|
|
134
|
+
#### GeoPlacesClient
|
|
109
135
|
|
|
110
|
-
|
|
136
|
+
Client for executing AWS Location Service commands with Bearer token auth.
|
|
111
137
|
|
|
112
138
|
```typescript
|
|
113
139
|
const client = new GeoPlacesClient({
|
|
114
140
|
apiUrl: string,
|
|
115
|
-
token: string
|
|
141
|
+
token: string,
|
|
142
|
+
getToken?: () => string | undefined, // Optional: dynamic token getter
|
|
116
143
|
})
|
|
117
144
|
|
|
118
145
|
await client.send(command)
|
|
119
146
|
```
|
|
120
147
|
|
|
121
|
-
|
|
148
|
+
When `getToken` is provided, it is called on every request so token updates are reflected without recreating the client.
|
|
122
149
|
|
|
123
|
-
|
|
150
|
+
#### GeoPlaces Adapter
|
|
151
|
+
|
|
152
|
+
Implements the `MaplibreGeocoderApi` interface for use with `@maplibre/maplibre-gl-geocoder`. Methods are called automatically by the geocoder control.
|
|
124
153
|
|
|
125
154
|
```typescript
|
|
126
|
-
const
|
|
155
|
+
const client = new GeoPlacesClient({ apiUrl, token })
|
|
156
|
+
const geoPlaces = new GeoPlaces(client, map)
|
|
157
|
+
|
|
158
|
+
// Pass to MaplibreGeocoder — it calls these methods internally:
|
|
159
|
+
// geoPlaces.getSuggestions(config) — typeahead suggestions
|
|
160
|
+
// geoPlaces.forwardGeocode(config) — text to coordinates
|
|
161
|
+
// geoPlaces.reverseGeocode(config) — coordinates to address
|
|
162
|
+
// geoPlaces.searchByPlaceId(config) — place ID to details
|
|
163
|
+
```
|
|
127
164
|
|
|
128
|
-
|
|
129
|
-
await geoPlaces.forwardGeocode({ query: 'Vancouver' })
|
|
165
|
+
#### createTransformRequest
|
|
130
166
|
|
|
131
|
-
|
|
132
|
-
|
|
167
|
+
Creates a MapLibre `transformRequest` function that adds Bearer auth and correct `Accept` headers.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { createTransformRequest } from '@chaosity/location-client'
|
|
133
171
|
|
|
134
|
-
|
|
135
|
-
await geoPlaces.searchByPlaceId('place-id')
|
|
172
|
+
const transformRequest = createTransformRequest(apiUrl, () => currentToken)
|
|
136
173
|
```
|
|
137
174
|
|
|
138
|
-
|
|
175
|
+
#### Available Commands
|
|
139
176
|
|
|
140
177
|
All AWS Location Service commands from `@aws-sdk/client-geo-places`:
|
|
141
178
|
|
|
@@ -146,11 +183,11 @@ import {
|
|
|
146
183
|
ReverseGeocodeCommand,
|
|
147
184
|
GetPlaceCommand,
|
|
148
185
|
SearchTextCommand,
|
|
149
|
-
SearchNearbyCommand
|
|
186
|
+
SearchNearbyCommand,
|
|
150
187
|
} from '@chaosity/location-client'
|
|
151
188
|
```
|
|
152
189
|
|
|
153
|
-
|
|
190
|
+
#### Data Type Utilities
|
|
154
191
|
|
|
155
192
|
GeoJSON conversion utilities from `@aws/amazon-location-utilities-datatypes`:
|
|
156
193
|
|
|
@@ -158,90 +195,67 @@ GeoJSON conversion utilities from `@aws/amazon-location-utilities-datatypes`:
|
|
|
158
195
|
import {
|
|
159
196
|
placeToFeatureCollection,
|
|
160
197
|
routeToFeatureCollection,
|
|
161
|
-
devicePositionsToFeatureCollection
|
|
198
|
+
devicePositionsToFeatureCollection,
|
|
162
199
|
} from '@chaosity/location-client'
|
|
163
200
|
```
|
|
164
201
|
|
|
165
|
-
|
|
202
|
+
### Server Exports (`@chaosity/location-client/server`)
|
|
166
203
|
|
|
167
|
-
|
|
204
|
+
#### getClientConfig
|
|
168
205
|
|
|
169
|
-
|
|
170
|
-
# Enable all location-client logs
|
|
171
|
-
DEBUG=location-client:* npm run dev
|
|
206
|
+
Gets a client config with a fresh token. Uses a singleton `TokenProvider` internally — safe to call repeatedly (tokens are cached and refreshed automatically).
|
|
172
207
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# Enable only API request logs
|
|
177
|
-
DEBUG=location-client:api npm run dev
|
|
208
|
+
```typescript
|
|
209
|
+
import { getClientConfig } from '@chaosity/location-client/server'
|
|
178
210
|
|
|
179
|
-
|
|
180
|
-
|
|
211
|
+
const config = await getClientConfig()
|
|
212
|
+
// { apiUrl: string, token: string, expiresAt?: number }
|
|
181
213
|
```
|
|
182
214
|
|
|
183
|
-
|
|
184
|
-
```
|
|
185
|
-
location-client:auth Initializing TokenProvider for https://api.example.com +0ms
|
|
186
|
-
location-client:auth Fetching new token from https://api.example.com +2ms
|
|
187
|
-
location-client:auth Token acquired successfully (expires in 3600s) +145ms
|
|
188
|
-
location-client:api Sending SuggestCommand request to /address/suggestion +0ms
|
|
189
|
-
location-client:api Request successful: 200 (89ms) +89ms
|
|
190
|
-
```
|
|
215
|
+
#### TokenProvider
|
|
191
216
|
|
|
192
|
-
|
|
217
|
+
Lower-level token management with caching and deduplication.
|
|
193
218
|
|
|
194
|
-
|
|
219
|
+
```typescript
|
|
220
|
+
import { TokenProvider } from '@chaosity/location-client/server'
|
|
195
221
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
222
|
+
const provider = new TokenProvider({
|
|
223
|
+
apiUrl: process.env.LOCATION_API_URL!,
|
|
224
|
+
clientId: process.env.LOCATION_CLIENT_ID!,
|
|
225
|
+
clientSecret: process.env.LOCATION_CLIENT_SECRET!,
|
|
226
|
+
})
|
|
200
227
|
|
|
201
|
-
|
|
228
|
+
const { success, token, expiresAt } = await provider.getToken()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### LocationServiceConnector
|
|
232
|
+
|
|
233
|
+
Server-side connector for backend-to-backend API calls. Can auto-configure from environment variables when no config is passed.
|
|
202
234
|
|
|
203
235
|
```typescript
|
|
204
|
-
'
|
|
236
|
+
import { LocationServiceConnector } from '@chaosity/location-client/server'
|
|
205
237
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
238
|
+
const connector = new LocationServiceConnector({
|
|
239
|
+
apiUrl: config.apiUrl,
|
|
240
|
+
token: config.token,
|
|
241
|
+
})
|
|
210
242
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
headers: { 'Authorization': `Bearer ${token}` }
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return { url }
|
|
231
|
-
}
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
// Add geocoder
|
|
235
|
-
const geoPlaces = new GeoPlaces(apiUrl, token, map)
|
|
236
|
-
const geocoder = new MaplibreGeocoder(geoPlaces, { maplibregl })
|
|
237
|
-
map.addControl(geocoder, 'top-left')
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
initMap()
|
|
241
|
-
}, [])
|
|
242
|
-
|
|
243
|
-
return <div id="map" style={{ width: '100%', height: '600px' }} />
|
|
244
|
-
}
|
|
243
|
+
const result = await connector.send(new SuggestCommand({ QueryText: 'Vancouver' }))
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Logging
|
|
247
|
+
|
|
248
|
+
The library uses the `debug` package for optional verbose logging:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Enable all location-client logs
|
|
252
|
+
DEBUG=location-client:* npm run dev
|
|
253
|
+
|
|
254
|
+
# Enable only authentication logs
|
|
255
|
+
DEBUG=location-client:auth npm run dev
|
|
256
|
+
|
|
257
|
+
# Enable only API request logs
|
|
258
|
+
DEBUG=location-client:api npm run dev
|
|
245
259
|
```
|
|
246
260
|
|
|
247
261
|
## TypeScript Support
|
|
@@ -72,7 +72,12 @@ export async function getClientConfig(config = {}) {
|
|
|
72
72
|
const result = await provider.getToken();
|
|
73
73
|
if (!result.success || !result.token) {
|
|
74
74
|
console.error('[getClientConfig] Token fetch failed:', result.error);
|
|
75
|
-
|
|
75
|
+
const isAuthError = result.error === 'Invalid credentials' ||
|
|
76
|
+
result.error?.toLowerCase().includes('unauthorized');
|
|
77
|
+
throw new Error(isAuthError
|
|
78
|
+
? `Authentication failed for client ID "${clientId}". ` +
|
|
79
|
+
`Verify LOCATION_CLIENT_ID and LOCATION_CLIENT_SECRET match your application in the developer portal.`
|
|
80
|
+
: (result.error || 'Failed to get token'));
|
|
76
81
|
}
|
|
77
82
|
log('[getClientConfig] Token fetched successfully, length:', result.token.length);
|
|
78
83
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaosity/location-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Client library for Chaosity Location Service with AWS Location Service compatibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@aws-sdk/client-geo-places": "^3.0.0",
|
|
45
45
|
"@aws/amazon-location-utilities-datatypes": "^1.0.0",
|
|
46
46
|
"@maplibre/maplibre-gl-geocoder": "^1.9.4",
|
|
47
|
-
"debug": "^4.4.3"
|
|
47
|
+
"debug": "^4.4.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"maplibre-gl": "^5.0.0"
|