@chaosity/location-client 0.1.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/LICENSE +21 -0
- package/README.md +219 -0
- package/dist/adapters/GeoPlaces.d.ts +27 -0
- package/dist/adapters/GeoPlaces.js +58 -0
- package/dist/auth/AuthClient.d.ts +6 -0
- package/dist/auth/AuthClient.js +23 -0
- package/dist/auth/AuthHelper.d.ts +9 -0
- package/dist/auth/AuthHelper.js +18 -0
- package/dist/auth/TokenProvider.d.ts +21 -0
- package/dist/auth/TokenProvider.js +52 -0
- package/dist/client/GeoPlacesClient.d.ts +16 -0
- package/dist/client/GeoPlacesClient.js +52 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +12 -0
- package/dist/server/getClientConfig.d.ts +16 -0
- package/dist/server/getClientConfig.js +24 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +2 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Chaosity
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# @chaosity/location-client
|
|
2
|
+
|
|
3
|
+
AWS Location Service compatible client with custom authentication.
|
|
4
|
+
|
|
5
|
+
## Built on AWS Official Libraries
|
|
6
|
+
|
|
7
|
+
This client uses:
|
|
8
|
+
- [`@aws/amazon-location-client`](https://github.com/aws-geospatial/amazon-location-client-js) - AWS Location Client with all commands
|
|
9
|
+
- [`@aws/amazon-location-utilities-datatypes`](https://github.com/aws-geospatial/amazon-location-utilities-datatypes-js) - Data type conversions (GeoJSON, etc.)
|
|
10
|
+
|
|
11
|
+
## Key Difference from AWS SDK
|
|
12
|
+
|
|
13
|
+
**Only difference**: Authentication method
|
|
14
|
+
- AWS SDK: Uses AWS SigV4 (IAM credentials)
|
|
15
|
+
- This client: Uses Bearer token (OAuth2)
|
|
16
|
+
|
|
17
|
+
**Everything else is identical**:
|
|
18
|
+
- Same command classes from AWS Location Client
|
|
19
|
+
- Same request/response types
|
|
20
|
+
- Same data type conversions
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @chaosity/location-client
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Basic Client
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { GeoPlacesClient, places } from '@chaosity/location-client'
|
|
34
|
+
|
|
35
|
+
const client = new GeoPlacesClient({
|
|
36
|
+
apiUrl: 'https://api.example.com',
|
|
37
|
+
token: 'your-bearer-token'
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Use AWS Location Client commands
|
|
41
|
+
const command = new places.SuggestCommand({
|
|
42
|
+
QueryText: 'Vancouver',
|
|
43
|
+
MaxResults: 5
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const response = await client.send(command)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### MapLibre Integration
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { GeoPlacesClient, GeoPlaces, placeToFeatureCollection } from '@chaosity/location-client'
|
|
53
|
+
import maplibregl from 'maplibre-gl'
|
|
54
|
+
|
|
55
|
+
const map = new maplibregl.Map({ /* ... */ })
|
|
56
|
+
const client = new GeoPlacesClient({ apiUrl, token })
|
|
57
|
+
const geoPlaces = new GeoPlaces(client, map)
|
|
58
|
+
|
|
59
|
+
// Use with MapLibre Geocoder
|
|
60
|
+
const results = await geoPlaces.forwardGeocode({ query: 'Vancouver' })
|
|
61
|
+
|
|
62
|
+
// Or use AWS utilities directly for data conversion
|
|
63
|
+
const featureCollection = placeToFeatureCollection(response)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Available Commands
|
|
67
|
+
|
|
68
|
+
All commands from AWS Location Client:
|
|
69
|
+
- `places.AutocompleteCommand`
|
|
70
|
+
- `places.GeocodeCommand`
|
|
71
|
+
- `places.GetPlaceCommand`
|
|
72
|
+
- `places.ReverseGeocodeCommand`
|
|
73
|
+
- `places.SearchNearbyCommand`
|
|
74
|
+
- `places.SearchTextCommand`
|
|
75
|
+
- `places.SuggestCommand`
|
|
76
|
+
- `maps.*` - All Maps commands
|
|
77
|
+
- `routes.*` - All Routes commands
|
|
78
|
+
|
|
79
|
+
## Data Type Utilities
|
|
80
|
+
|
|
81
|
+
All utilities from `@aws/amazon-location-utilities-datatypes`:
|
|
82
|
+
- `placeToFeatureCollection` - Convert places to GeoJSON
|
|
83
|
+
- `routeToFeatureCollection` - Convert routes to GeoJSON
|
|
84
|
+
- `devicePositionsToFeatureCollection` - Convert device positions to GeoJSON
|
|
85
|
+
- `geofencesToFeatureCollection` - Convert geofences to GeoJSON
|
|
86
|
+
- `featureCollectionToGeofence` - Convert GeoJSON to geofences
|
|
87
|
+
|
|
88
|
+
Refer to [AWS Location Client docs](https://github.com/aws-geospatial/amazon-location-client-js) and [Data Types docs](https://github.com/aws-geospatial/amazon-location-utilities-datatypes-js) for complete documentation.
|
|
89
|
+
|
|
90
|
+
## ⚠️ Security Notice
|
|
91
|
+
|
|
92
|
+
**NEVER expose `client_id` and `client_secret` in browser code!**
|
|
93
|
+
|
|
94
|
+
- `TokenProvider` is for **server-side use only** (Next.js Server Actions, API routes, backend services)
|
|
95
|
+
- Client credentials must be stored in environment variables on the server
|
|
96
|
+
- Browser code should only receive the JWT token from your backend
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm install @chaosity/location-client maplibre-gl
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Quick Start
|
|
105
|
+
|
|
106
|
+
### Recommended: Server Action (Next.js)
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// lib/actions/location-auth.ts (Server-side only)
|
|
110
|
+
'use server'
|
|
111
|
+
|
|
112
|
+
export async function getLocationToken() {
|
|
113
|
+
const response = await fetch('https://api.locationservice.com/auth/token', {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: { 'Content-Type': 'application/json' },
|
|
116
|
+
body: JSON.stringify({
|
|
117
|
+
grant_type: 'client_credentials',
|
|
118
|
+
client_id: process.env.LOCATION_CLIENT_ID!,
|
|
119
|
+
client_secret: process.env.LOCATION_CLIENT_SECRET!
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
const data = await response.json()
|
|
124
|
+
return { token: data.access_token, apiUrl: 'https://api.locationservice.com' }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// components/Map.tsx (Client-side)
|
|
128
|
+
'use client'
|
|
129
|
+
import { GeoPlaces } from '@chaosity/location-client'
|
|
130
|
+
import { getLocationToken } from '@/lib/actions/location-auth'
|
|
131
|
+
|
|
132
|
+
const { token, apiUrl } = await getLocationToken()
|
|
133
|
+
const geoPlaces = new GeoPlaces(apiUrl, token)
|
|
134
|
+
|
|
135
|
+
// Use with MapLibre Geocoder
|
|
136
|
+
const geocoder = new MaplibreGeocoder(geoPlaces, { maplibregl })
|
|
137
|
+
map.addControl(geocoder)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Alternative: Using AuthClient (Server-side only)
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// lib/actions/location-auth.ts (Server-side only)
|
|
144
|
+
'use server'
|
|
145
|
+
import { AuthClient } from '@chaosity/location-client'
|
|
146
|
+
|
|
147
|
+
export async function getLocationToken() {
|
|
148
|
+
const authClient = new AuthClient()
|
|
149
|
+
const tokenResponse = await authClient.fetchToken({
|
|
150
|
+
client_id: process.env.LOCATION_CLIENT_ID!,
|
|
151
|
+
client_secret: process.env.LOCATION_CLIENT_SECRET!
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
return { token: tokenResponse.access_token, apiUrl: 'https://api.locationservice.com' }
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## API Reference
|
|
159
|
+
|
|
160
|
+
### AuthHelper
|
|
161
|
+
|
|
162
|
+
Manages authentication tokens.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const authHelper = new AuthHelper(token: string, apiUrl: string)
|
|
166
|
+
authHelper.setToken(newToken: string)
|
|
167
|
+
authHelper.getToken(): string
|
|
168
|
+
authHelper.getClientConfig(): ClientConfig
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### AuthClient
|
|
172
|
+
|
|
173
|
+
⚠️ **SERVER-SIDE ONLY** - Never use in browser code!
|
|
174
|
+
|
|
175
|
+
Fetches tokens using OAuth2 client credentials flow.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const authClient = new AuthClient(authEndpoint?: string)
|
|
179
|
+
const tokenResponse = await authClient.fetchToken({
|
|
180
|
+
client_id: string,
|
|
181
|
+
client_secret: string
|
|
182
|
+
})
|
|
183
|
+
// Returns: { access_token, token_type, expires_in }
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### GeoPlacesClient
|
|
187
|
+
|
|
188
|
+
Executes commands against the API.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
const client = new GeoPlacesClient(config: ClientConfig)
|
|
192
|
+
await client.send(command: Command)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### GeoPlaces
|
|
196
|
+
|
|
197
|
+
MapLibre Geocoder adapter (browser-safe).
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
const geoPlaces = new GeoPlaces(apiUrl: string, token: string)
|
|
201
|
+
await geoPlaces.forwardGeocode(config)
|
|
202
|
+
await geoPlaces.reverseGeocode(config)
|
|
203
|
+
await geoPlaces.getSuggestions(config)
|
|
204
|
+
await geoPlaces.searchByPlaceId(placeId)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Commands
|
|
208
|
+
|
|
209
|
+
### Places Commands
|
|
210
|
+
|
|
211
|
+
- `SearchTextCommand` - Search for places by text
|
|
212
|
+
- `SuggestCommand` - Get autocomplete suggestions
|
|
213
|
+
- `ReverseGeocodeCommand` - Get place from coordinates
|
|
214
|
+
- `SearchNearbyCommand` - Search nearby places
|
|
215
|
+
- `GetPlaceCommand` - Get place details by ID
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FeatureCollection } from 'geojson';
|
|
2
|
+
import type { Map } from 'maplibre-gl';
|
|
3
|
+
import { GeoPlacesClient } from '../client/GeoPlacesClient';
|
|
4
|
+
/**
|
|
5
|
+
* GeoPlaces - MapLibre adapter for AWS Location Service
|
|
6
|
+
*
|
|
7
|
+
* Uses AWS Location Client commands and utilities for data conversion.
|
|
8
|
+
* Only auth is custom (Bearer token instead of SigV4).
|
|
9
|
+
*/
|
|
10
|
+
export declare class GeoPlaces {
|
|
11
|
+
private client;
|
|
12
|
+
private map;
|
|
13
|
+
constructor(client: GeoPlacesClient, map: Map);
|
|
14
|
+
forwardGeocode(config: {
|
|
15
|
+
query: string;
|
|
16
|
+
limit?: number;
|
|
17
|
+
}): Promise<FeatureCollection>;
|
|
18
|
+
reverseGeocode(config: {
|
|
19
|
+
query: [number, number];
|
|
20
|
+
limit?: number;
|
|
21
|
+
click?: boolean;
|
|
22
|
+
}): Promise<FeatureCollection>;
|
|
23
|
+
getSuggestions(config: {
|
|
24
|
+
query: string;
|
|
25
|
+
}): Promise<FeatureCollection>;
|
|
26
|
+
searchByPlaceId(placeId: string): Promise<FeatureCollection>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { placeToFeatureCollection } from '@aws/amazon-location-utilities-datatypes';
|
|
2
|
+
import { GetPlaceCommand, ReverseGeocodeCommand, SearchNearbyCommand, SuggestCommand } from '@aws-sdk/client-geo-places';
|
|
3
|
+
/**
|
|
4
|
+
* GeoPlaces - MapLibre adapter for AWS Location Service
|
|
5
|
+
*
|
|
6
|
+
* Uses AWS Location Client commands and utilities for data conversion.
|
|
7
|
+
* Only auth is custom (Bearer token instead of SigV4).
|
|
8
|
+
*/
|
|
9
|
+
export class GeoPlaces {
|
|
10
|
+
constructor(client, map) {
|
|
11
|
+
this.client = client;
|
|
12
|
+
this.map = map;
|
|
13
|
+
}
|
|
14
|
+
async forwardGeocode(config) {
|
|
15
|
+
const center = this.map.getCenter();
|
|
16
|
+
const command = new SuggestCommand({
|
|
17
|
+
QueryText: config.query,
|
|
18
|
+
BiasPosition: [center.lng, center.lat],
|
|
19
|
+
MaxResults: config.limit || 5,
|
|
20
|
+
Language: 'en'
|
|
21
|
+
});
|
|
22
|
+
const response = await this.client.send(command);
|
|
23
|
+
return placeToFeatureCollection(response, { flattenProperties: true });
|
|
24
|
+
}
|
|
25
|
+
async reverseGeocode(config) {
|
|
26
|
+
const command = config.click
|
|
27
|
+
? new ReverseGeocodeCommand({
|
|
28
|
+
QueryPosition: config.query,
|
|
29
|
+
MaxResults: config.limit || 1,
|
|
30
|
+
Language: 'en'
|
|
31
|
+
})
|
|
32
|
+
: new SearchNearbyCommand({
|
|
33
|
+
QueryPosition: config.query,
|
|
34
|
+
MaxResults: config.limit || 15,
|
|
35
|
+
Language: 'en'
|
|
36
|
+
});
|
|
37
|
+
const response = await this.client.send(command);
|
|
38
|
+
return placeToFeatureCollection(response, { flattenProperties: true });
|
|
39
|
+
}
|
|
40
|
+
async getSuggestions(config) {
|
|
41
|
+
const center = this.map.getCenter();
|
|
42
|
+
const command = new SuggestCommand({
|
|
43
|
+
QueryText: config.query,
|
|
44
|
+
BiasPosition: [center.lng, center.lat],
|
|
45
|
+
Language: 'en'
|
|
46
|
+
});
|
|
47
|
+
const response = await this.client.send(command);
|
|
48
|
+
return placeToFeatureCollection(response, { flattenProperties: true });
|
|
49
|
+
}
|
|
50
|
+
async searchByPlaceId(placeId) {
|
|
51
|
+
const command = new GetPlaceCommand({
|
|
52
|
+
PlaceId: placeId,
|
|
53
|
+
Language: 'en'
|
|
54
|
+
});
|
|
55
|
+
const response = await this.client.send(command);
|
|
56
|
+
return placeToFeatureCollection(response, { flattenProperties: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class AuthClient {
|
|
2
|
+
constructor(authEndpoint = 'https://api.locationservice.com/auth') {
|
|
3
|
+
this.authEndpoint = authEndpoint;
|
|
4
|
+
}
|
|
5
|
+
async fetchToken(credentials) {
|
|
6
|
+
const response = await fetch(`${this.authEndpoint}/token`, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json'
|
|
10
|
+
},
|
|
11
|
+
body: JSON.stringify({
|
|
12
|
+
grant_type: 'client_credentials',
|
|
13
|
+
client_id: credentials.client_id,
|
|
14
|
+
client_secret: credentials.client_secret
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
const error = await response.json();
|
|
19
|
+
throw new Error(error.error_description || 'Failed to fetch token');
|
|
20
|
+
}
|
|
21
|
+
return await response.json();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class AuthHelper {
|
|
2
|
+
constructor(token, apiUrl) {
|
|
3
|
+
this.token = token;
|
|
4
|
+
this.apiUrl = apiUrl;
|
|
5
|
+
}
|
|
6
|
+
setToken(token) {
|
|
7
|
+
this.token = token;
|
|
8
|
+
}
|
|
9
|
+
getToken() {
|
|
10
|
+
return this.token;
|
|
11
|
+
}
|
|
12
|
+
getClientConfig() {
|
|
13
|
+
return {
|
|
14
|
+
apiUrl: this.apiUrl,
|
|
15
|
+
token: this.token
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface TokenResponse {
|
|
2
|
+
success: boolean;
|
|
3
|
+
token?: string;
|
|
4
|
+
expiresIn?: number;
|
|
5
|
+
expiresAt?: number;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TokenProviderConfig {
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
clientId: string;
|
|
11
|
+
clientSecret: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class TokenProvider {
|
|
14
|
+
private config;
|
|
15
|
+
private cachedToken?;
|
|
16
|
+
private expiresAt?;
|
|
17
|
+
constructor(config: TokenProviderConfig);
|
|
18
|
+
getToken(forceRefresh?: boolean): Promise<TokenResponse>;
|
|
19
|
+
private isExpired;
|
|
20
|
+
clearCache(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class TokenProvider {
|
|
2
|
+
constructor(config) {
|
|
3
|
+
this.config = config;
|
|
4
|
+
}
|
|
5
|
+
async getToken(forceRefresh = false) {
|
|
6
|
+
if (!forceRefresh && this.cachedToken && this.expiresAt && !this.isExpired()) {
|
|
7
|
+
return {
|
|
8
|
+
success: true,
|
|
9
|
+
token: this.cachedToken,
|
|
10
|
+
expiresAt: this.expiresAt
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch(`${this.config.apiUrl}/auth/token`, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: { 'Content-Type': 'application/json' },
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
client_id: this.config.clientId,
|
|
19
|
+
client_secret: this.config.clientSecret,
|
|
20
|
+
grant_type: 'client_credentials',
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(`Failed to get token: ${response.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
const data = await response.json();
|
|
27
|
+
this.cachedToken = data.access_token;
|
|
28
|
+
this.expiresAt = Date.now() + (data.expires_in * 1000);
|
|
29
|
+
return {
|
|
30
|
+
success: true,
|
|
31
|
+
token: this.cachedToken,
|
|
32
|
+
expiresIn: data.expires_in,
|
|
33
|
+
expiresAt: this.expiresAt,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: error instanceof Error ? error.message : 'Failed to get token',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
isExpired(bufferSeconds = 60) {
|
|
44
|
+
if (!this.expiresAt)
|
|
45
|
+
return true;
|
|
46
|
+
return Date.now() >= (this.expiresAt - bufferSeconds * 1000);
|
|
47
|
+
}
|
|
48
|
+
clearCache() {
|
|
49
|
+
this.cachedToken = undefined;
|
|
50
|
+
this.expiresAt = undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ClientConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* GeoPlacesClient - AWS Location Service compatible client with custom auth
|
|
4
|
+
*
|
|
5
|
+
* Uses AWS Location Client command classes but replaces SigV4 auth with Bearer token.
|
|
6
|
+
* All request/response types are identical to AWS Location Service.
|
|
7
|
+
*/
|
|
8
|
+
export declare class GeoPlacesClient {
|
|
9
|
+
private clientConfig;
|
|
10
|
+
readonly config: {
|
|
11
|
+
serviceId: string;
|
|
12
|
+
};
|
|
13
|
+
constructor(config: ClientConfig);
|
|
14
|
+
send<TInput, TOutput>(command: TInput): Promise<TOutput>;
|
|
15
|
+
private getEndpoint;
|
|
16
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AutocompleteCommand, GeocodeCommand, GetPlaceCommand, ReverseGeocodeCommand, SearchNearbyCommand, SearchTextCommand, SuggestCommand, } from '@aws-sdk/client-geo-places';
|
|
2
|
+
/**
|
|
3
|
+
* GeoPlacesClient - AWS Location Service compatible client with custom auth
|
|
4
|
+
*
|
|
5
|
+
* Uses AWS Location Client command classes but replaces SigV4 auth with Bearer token.
|
|
6
|
+
* All request/response types are identical to AWS Location Service.
|
|
7
|
+
*/
|
|
8
|
+
export class GeoPlacesClient {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.clientConfig = config;
|
|
11
|
+
this.config = { serviceId: 'Geo Places' };
|
|
12
|
+
}
|
|
13
|
+
async send(command) {
|
|
14
|
+
const endpoint = this.getEndpoint(command);
|
|
15
|
+
const response = await fetch(`${this.clientConfig.apiUrl}${endpoint}`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
'Authorization': `Bearer ${this.clientConfig.token}`
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify(command)
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(`API request failed: ${response.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
return response.json();
|
|
27
|
+
}
|
|
28
|
+
getEndpoint(command) {
|
|
29
|
+
if (command instanceof AutocompleteCommand) {
|
|
30
|
+
return '/address/autocomplete';
|
|
31
|
+
}
|
|
32
|
+
else if (command instanceof GeocodeCommand) {
|
|
33
|
+
return '/address/geocode';
|
|
34
|
+
}
|
|
35
|
+
else if (command instanceof GetPlaceCommand) {
|
|
36
|
+
return '/address/place';
|
|
37
|
+
}
|
|
38
|
+
else if (command instanceof ReverseGeocodeCommand) {
|
|
39
|
+
return '/address/search/reverse-geocode';
|
|
40
|
+
}
|
|
41
|
+
else if (command instanceof SearchNearbyCommand) {
|
|
42
|
+
return '/address/search/nearby';
|
|
43
|
+
}
|
|
44
|
+
else if (command instanceof SearchTextCommand) {
|
|
45
|
+
return '/address/search/text';
|
|
46
|
+
}
|
|
47
|
+
else if (command instanceof SuggestCommand) {
|
|
48
|
+
return '/address/suggestion';
|
|
49
|
+
}
|
|
50
|
+
throw new Error('Unknown command type');
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { TokenProvider } from './auth/TokenProvider';
|
|
2
|
+
export type { TokenResponse, TokenProviderConfig } from './auth/TokenProvider';
|
|
3
|
+
export { GeoPlacesClient } from './client/GeoPlacesClient';
|
|
4
|
+
export * from '@aws-sdk/client-geo-places';
|
|
5
|
+
export * from '@aws/amazon-location-utilities-datatypes';
|
|
6
|
+
export { GeoPlaces } from './adapters/GeoPlaces';
|
|
7
|
+
export type { ClientConfig } from './types';
|
|
8
|
+
export { getClientConfig } from './server/getClientConfig';
|
|
9
|
+
export type { ServerAuthConfig } from './server/getClientConfig';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Auth (Custom - only difference from AWS SDK)
|
|
2
|
+
export { TokenProvider } from './auth/TokenProvider';
|
|
3
|
+
// Client (Custom - uses our auth instead of AWS SigV4)
|
|
4
|
+
export { GeoPlacesClient } from './client/GeoPlacesClient';
|
|
5
|
+
// Re-export AWS SDK commands and types
|
|
6
|
+
export * from '@aws-sdk/client-geo-places';
|
|
7
|
+
// Re-export AWS Location Utilities (data type conversions)
|
|
8
|
+
export * from '@aws/amazon-location-utilities-datatypes';
|
|
9
|
+
// Adapters (Custom - for MapLibre integration)
|
|
10
|
+
export { GeoPlaces } from './adapters/GeoPlaces';
|
|
11
|
+
// Server-only utilities
|
|
12
|
+
export { getClientConfig } from './server/getClientConfig';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ClientConfig } from '../types';
|
|
2
|
+
import { TokenProviderConfig } from '../auth/TokenProvider';
|
|
3
|
+
export type ServerAuthConfig = TokenProviderConfig;
|
|
4
|
+
/**
|
|
5
|
+
* Get client configuration with OAuth2 authentication.
|
|
6
|
+
*
|
|
7
|
+
* WARNING: This function uses client credentials (clientId/clientSecret).
|
|
8
|
+
* Only call this from:
|
|
9
|
+
* - Next.js Server Components/Actions
|
|
10
|
+
* - Node.js backend servers
|
|
11
|
+
* - API routes
|
|
12
|
+
*
|
|
13
|
+
* NEVER call from browser/client code as it exposes credentials.
|
|
14
|
+
* For SPA projects, create your own backend endpoint that calls this.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getClientConfig(config: ServerAuthConfig): Promise<ClientConfig>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TokenProvider } from '../auth/TokenProvider';
|
|
2
|
+
/**
|
|
3
|
+
* Get client configuration with OAuth2 authentication.
|
|
4
|
+
*
|
|
5
|
+
* WARNING: This function uses client credentials (clientId/clientSecret).
|
|
6
|
+
* Only call this from:
|
|
7
|
+
* - Next.js Server Components/Actions
|
|
8
|
+
* - Node.js backend servers
|
|
9
|
+
* - API routes
|
|
10
|
+
*
|
|
11
|
+
* NEVER call from browser/client code as it exposes credentials.
|
|
12
|
+
* For SPA projects, create your own backend endpoint that calls this.
|
|
13
|
+
*/
|
|
14
|
+
export async function getClientConfig(config) {
|
|
15
|
+
const provider = new TokenProvider(config);
|
|
16
|
+
const result = await provider.getToken();
|
|
17
|
+
if (!result.success || !result.token) {
|
|
18
|
+
throw new Error(result.error || 'Failed to get token');
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
apiUrl: config.apiUrl,
|
|
22
|
+
token: result.token,
|
|
23
|
+
};
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chaosity/location-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Client library for Chaosity Location Service with AWS Location Service compatibility",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"test": "jest",
|
|
11
|
+
"prepublishOnly": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"aws",
|
|
15
|
+
"location",
|
|
16
|
+
"maps",
|
|
17
|
+
"geocoding",
|
|
18
|
+
"maplibre",
|
|
19
|
+
"places"
|
|
20
|
+
],
|
|
21
|
+
"author": "Chaosity",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@aws-sdk/client-geo-places": "^3.0.0",
|
|
25
|
+
"@aws/amazon-location-utilities-datatypes": "^1.0.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"maplibre-gl": "^4.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependenciesMeta": {
|
|
31
|
+
"maplibre-gl": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"typescript": "^5.0.0"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
]
|
|
43
|
+
}
|