@chaosity/location-client 0.9.0 → 0.11.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 +307 -37
- package/dist/adapters/GeoPlaces.d.ts +30 -3
- package/dist/adapters/GeoPlaces.js +5 -1
- package/dist/cjs/adapters/GeoPlaces.d.ts +30 -3
- package/dist/cjs/adapters/GeoPlaces.js +5 -4
- package/dist/cjs/client/GeoPlacesClient.d.ts +16 -4
- package/dist/cjs/client/GeoPlacesClient.js +18 -4
- package/dist/cjs/client/commands.d.ts +159 -0
- package/dist/cjs/client/commands.js +108 -0
- package/dist/cjs/errors/LocationServiceException.d.ts +28 -1
- package/dist/cjs/errors/LocationServiceException.js +31 -2
- package/dist/cjs/index.d.ts +5 -3
- package/dist/cjs/index.js +17 -1
- package/dist/cjs/maps/mapEnums.d.ts +82 -4
- package/dist/cjs/maps/mapEnums.js +98 -5
- package/dist/cjs/maps/mapStyle.d.ts +87 -10
- package/dist/cjs/maps/mapStyle.js +28 -5
- package/dist/cjs/maps/staticMap.d.ts +40 -0
- package/dist/cjs/maps/staticMap.js +4 -0
- package/dist/cjs/server/LocationServiceConnector.d.ts +23 -5
- package/dist/cjs/server/LocationServiceConnector.js +25 -5
- package/dist/cjs/transport/endpoints.js +3 -0
- package/dist/cjs/transport/http.d.ts +2 -2
- package/dist/cjs/transport/http.js +2 -2
- package/dist/cjs/types/index.d.ts +6 -5
- package/dist/cjs/utils/tokenClaims.d.ts +29 -3
- package/dist/cjs/utils/tokenClaims.js +28 -3
- package/dist/client/GeoPlacesClient.d.ts +16 -4
- package/dist/client/GeoPlacesClient.js +18 -4
- package/dist/client/commands.d.ts +159 -0
- package/dist/client/commands.js +97 -0
- package/dist/errors/LocationServiceException.d.ts +28 -1
- package/dist/errors/LocationServiceException.js +30 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +7 -2
- package/dist/maps/mapEnums.d.ts +82 -4
- package/dist/maps/mapEnums.js +97 -4
- package/dist/maps/mapStyle.d.ts +87 -10
- package/dist/maps/mapStyle.js +28 -5
- package/dist/maps/staticMap.d.ts +40 -0
- package/dist/maps/staticMap.js +4 -0
- package/dist/server/LocationServiceConnector.d.ts +23 -5
- package/dist/server/LocationServiceConnector.js +25 -5
- package/dist/transport/endpoints.js +3 -0
- package/dist/transport/http.d.ts +2 -2
- package/dist/transport/http.js +2 -2
- package/dist/types/index.d.ts +6 -5
- package/dist/utils/tokenClaims.d.ts +29 -3
- package/dist/utils/tokenClaims.js +28 -3
- package/package.json +3 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
|
+
import { VerifyAddressCommand } from '../client/commands.js';
|
|
2
3
|
import { LocationServiceException } from '../errors/LocationServiceException.js';
|
|
3
4
|
import { resolveEndpoint } from '../transport/endpoints.js';
|
|
4
5
|
import { isTokenRejected, noTokenAvailable } from '../transport/errors.js';
|
|
@@ -88,7 +89,13 @@ function explainMissingOrigin(err, sentOrigin) {
|
|
|
88
89
|
* ```typescript
|
|
89
90
|
* // Credentials and apiUrl from the environment, Origin supplied here
|
|
90
91
|
* const connector = new LocationServiceConnector({ origin: 'https://app.example.com' })
|
|
91
|
-
* const result = await connector.send(
|
|
92
|
+
* const result = await connector.send(
|
|
93
|
+
* new SearchTextCommand({
|
|
94
|
+
* QueryText: 'Space Needle',
|
|
95
|
+
* // SearchText takes exactly one of BiasPosition, Filter.BoundingBox or Filter.Circle.
|
|
96
|
+
* BiasPosition: [-122.3493, 47.6205],
|
|
97
|
+
* }),
|
|
98
|
+
* )
|
|
92
99
|
* ```
|
|
93
100
|
*/
|
|
94
101
|
export class LocationServiceConnector {
|
|
@@ -151,17 +158,19 @@ export class LocationServiceConnector {
|
|
|
151
158
|
}
|
|
152
159
|
/**
|
|
153
160
|
* This application's own configuration, as carried on the access token
|
|
154
|
-
* (api#65)
|
|
161
|
+
* (api#65): the routes it may call, the domain its requests must come from,
|
|
162
|
+
* and the countries it is scoped to (#40).
|
|
155
163
|
*
|
|
156
164
|
* Provided so an application can SHOW its own settings: populate a country
|
|
157
165
|
* selector with the markets it actually serves, label a settings screen, and
|
|
158
166
|
* so on. Being a few minutes stale is cosmetic for that.
|
|
159
167
|
*
|
|
160
168
|
* It is not an entitlement check. See AppConfigClaims for why acting on
|
|
161
|
-
*
|
|
169
|
+
* any of it client-side makes requests fail that would otherwise succeed.
|
|
162
170
|
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
171
|
+
* Every token the API issues carries `allowedResources` and `allowedDomain`;
|
|
172
|
+
* `countries` only once a scope is configured in the portal. Returns `{}`
|
|
173
|
+
* for a token carrying none of them.
|
|
165
174
|
*/
|
|
166
175
|
async getAppConfig() {
|
|
167
176
|
return readAppConfigClaims(await this.source().get());
|
|
@@ -189,6 +198,17 @@ export class LocationServiceConnector {
|
|
|
189
198
|
throw explainMissingOrigin(err, this.effectiveOrigin(options));
|
|
190
199
|
}
|
|
191
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Verify a PlaceId: `send(new VerifyAddressCommand({ PlaceId }))`, typed
|
|
203
|
+
* (#54). Resolves the full place record plus `verified`, and resolves a
|
|
204
|
+
* `verified: false` too — see VerifyAddressResponse for what may be stored.
|
|
205
|
+
*
|
|
206
|
+
* Billed per call, whether or not the address verifies: call it once per
|
|
207
|
+
* chosen PlaceId, never per keystroke.
|
|
208
|
+
*/
|
|
209
|
+
verifyAddress(placeId, options) {
|
|
210
|
+
return this.send(new VerifyAddressCommand({ PlaceId: placeId }), options);
|
|
211
|
+
}
|
|
192
212
|
async dispatchWithRetry(source, url, cmd, options) {
|
|
193
213
|
const token = await source.get();
|
|
194
214
|
if (!token)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AutocompleteCommand, GeocodeCommand, GetPlaceCommand, ReverseGeocodeCommand, SearchNearbyCommand, SearchTextCommand, SuggestCommand, } from '@aws-sdk/client-geo-places';
|
|
2
|
+
import { VerifyAddressCommand } from '../client/commands.js';
|
|
2
3
|
import { LocationServiceException } from '../errors/LocationServiceException.js';
|
|
3
4
|
/**
|
|
4
5
|
* Command class -> API path.
|
|
@@ -17,6 +18,8 @@ const ENDPOINTS = new Map([
|
|
|
17
18
|
[SearchNearbyCommand, '/address/search/nearby'],
|
|
18
19
|
[SearchTextCommand, '/address/search/text'],
|
|
19
20
|
[SuggestCommand, '/address/suggestion'],
|
|
21
|
+
// This package's own: the route has no AWS command (#54).
|
|
22
|
+
[VerifyAddressCommand, '/address/verify'],
|
|
20
23
|
]);
|
|
21
24
|
export function resolveEndpoint(command) {
|
|
22
25
|
for (const [CommandClass, endpoint] of ENDPOINTS) {
|
package/dist/transport/http.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ export declare const DEFAULT_TIMEOUT_MS = 10000;
|
|
|
4
4
|
* Ceiling for the WHOLE call — every attempt plus every wait between them.
|
|
5
5
|
*
|
|
6
6
|
* `timeoutMs` bounds an attempt, not a call, and the gap between those two is
|
|
7
|
-
* where the caller's own deadline disappears.
|
|
8
|
-
*
|
|
7
|
+
* where the caller's own deadline disappears. Nothing bounds the `Retry-After`
|
|
8
|
+
* a 429 carries, and the retry loop honoured one of 60 s literally: two waits of
|
|
9
9
|
* a minute each, so one call could sit for ~120 s — past any Lambda budget,
|
|
10
10
|
* past any HTTP gateway, and until now uncancellable (#37).
|
|
11
11
|
*
|
package/dist/transport/http.js
CHANGED
|
@@ -8,8 +8,8 @@ export const DEFAULT_TIMEOUT_MS = 10000;
|
|
|
8
8
|
* Ceiling for the WHOLE call — every attempt plus every wait between them.
|
|
9
9
|
*
|
|
10
10
|
* `timeoutMs` bounds an attempt, not a call, and the gap between those two is
|
|
11
|
-
* where the caller's own deadline disappears.
|
|
12
|
-
*
|
|
11
|
+
* where the caller's own deadline disappears. Nothing bounds the `Retry-After`
|
|
12
|
+
* a 429 carries, and the retry loop honoured one of 60 s literally: two waits of
|
|
13
13
|
* a minute each, so one call could sit for ~120 s — past any Lambda budget,
|
|
14
14
|
* past any HTTP gateway, and until now uncancellable (#37).
|
|
15
15
|
*
|
package/dist/types/index.d.ts
CHANGED
|
@@ -42,11 +42,12 @@ export interface ClientConfig {
|
|
|
42
42
|
refreshToken?: () => Promise<string | undefined>;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* Minimal interface for AWS SDK
|
|
46
|
-
*
|
|
47
|
-
* Smithy's Command base class which has an
|
|
48
|
-
*
|
|
49
|
-
*
|
|
45
|
+
* Minimal interface for a command object: the AWS SDK's, and this package's
|
|
46
|
+
* own `VerifyAddressCommand` (#54). The SDK's commands (AutocompleteCommand,
|
|
47
|
+
* SearchTextCommand, etc.) extend Smithy's Command base class, which has an
|
|
48
|
+
* `input` property containing the request parameters; `VerifyAddressCommand`
|
|
49
|
+
* has the same `input` and nothing else. This interface captures what we
|
|
50
|
+
* actually need from commands without coupling to Smithy internals.
|
|
50
51
|
*/
|
|
51
52
|
export interface GeoPlacesCommand {
|
|
52
53
|
readonly input: object;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Read advisory application config out of the access token (api#65).
|
|
3
3
|
*
|
|
4
|
-
* The API puts an application's own settings
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The API puts an application's own settings into the JWT — `countries`,
|
|
5
|
+
* `allowedResources` and `allowedDomain` — so this library can stop
|
|
6
|
+
* hard-coding values it has no other way of knowing. The last two were in the
|
|
7
|
+
* token all along and were not surfaced until #40, so an application could
|
|
8
|
+
* only learn it lacked a route from the 403.
|
|
7
9
|
*
|
|
8
10
|
* `biasDecimals` used to be here too. It sized the grid this library rounded
|
|
9
11
|
* `BiasPosition` onto, so that nearby callers shared a server cache entry; the
|
|
@@ -42,6 +44,30 @@ export interface AppConfigClaims {
|
|
|
42
44
|
* Sending nothing and letting the API scope the request is always correct.
|
|
43
45
|
*/
|
|
44
46
|
countries?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* The routes this application may call, as the API names them — method and
|
|
49
|
+
* route template, such as `POST /address/autocomplete` or
|
|
50
|
+
* `GET /maps/static/{fileName}` (#40).
|
|
51
|
+
*
|
|
52
|
+
* So an application can ask "may I call the static-map route?" before it
|
|
53
|
+
* offers one, rather than only learning from the 403. It answers for the
|
|
54
|
+
* route, not for the options sent on it: a plan feature (`@planFeature`) is
|
|
55
|
+
* answered only by its own 403, and a static map's default Satellite render
|
|
56
|
+
* is one (#55). The same rule as `countries`
|
|
57
|
+
* applies, for the same reason: show it, never refuse with it. A route
|
|
58
|
+
* granted since the token was minted is answered by the API, which reads the
|
|
59
|
+
* entitlement fresh on every request.
|
|
60
|
+
*
|
|
61
|
+
* The API issues this claim JSON-encoded — a string holding the list —
|
|
62
|
+
* because it copies the application's stored setting. Both forms are read.
|
|
63
|
+
*/
|
|
64
|
+
allowedResources?: string[];
|
|
65
|
+
/**
|
|
66
|
+
* The domain this application's requests must come from (#40). A request
|
|
67
|
+
* whose `Origin` is neither this host nor one of its subdomains is refused
|
|
68
|
+
* 403, so this is what to show next to "Origin not allowed".
|
|
69
|
+
*/
|
|
70
|
+
allowedDomain?: string;
|
|
45
71
|
}
|
|
46
72
|
/**
|
|
47
73
|
* Decode a JWT payload without verifying it.
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Read advisory application config out of the access token (api#65).
|
|
3
3
|
*
|
|
4
|
-
* The API puts an application's own settings
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The API puts an application's own settings into the JWT — `countries`,
|
|
5
|
+
* `allowedResources` and `allowedDomain` — so this library can stop
|
|
6
|
+
* hard-coding values it has no other way of knowing. The last two were in the
|
|
7
|
+
* token all along and were not surfaced until #40, so an application could
|
|
8
|
+
* only learn it lacked a route from the 403.
|
|
7
9
|
*
|
|
8
10
|
* `biasDecimals` used to be here too. It sized the grid this library rounded
|
|
9
11
|
* `BiasPosition` onto, so that nearby callers shared a server cache entry; the
|
|
@@ -21,6 +23,21 @@
|
|
|
21
23
|
* A JWT is signed, not encrypted, so the payload is plain base64url. Nothing
|
|
22
24
|
* secret is in it; these are the caller's own settings.
|
|
23
25
|
*/
|
|
26
|
+
/** A list of strings, whether the claim carries it as a list or JSON-encoded. */
|
|
27
|
+
function readStringList(value) {
|
|
28
|
+
let list = value;
|
|
29
|
+
if (typeof list === 'string') {
|
|
30
|
+
try {
|
|
31
|
+
list = JSON.parse(list);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!Array.isArray(list))
|
|
38
|
+
return undefined;
|
|
39
|
+
return list.filter((v) => typeof v === 'string');
|
|
40
|
+
}
|
|
24
41
|
/**
|
|
25
42
|
* Decode a JWT payload without verifying it.
|
|
26
43
|
*
|
|
@@ -47,6 +64,14 @@ export function readAppConfigClaims(token) {
|
|
|
47
64
|
if (list.length)
|
|
48
65
|
claims.countries = list;
|
|
49
66
|
}
|
|
67
|
+
// Kept when empty, unlike countries: no countries means "search the
|
|
68
|
+
// world", but no resources means an application entitled to nothing.
|
|
69
|
+
const resources = readStringList(payload.allowedResources);
|
|
70
|
+
if (resources)
|
|
71
|
+
claims.allowedResources = resources;
|
|
72
|
+
if (typeof payload.allowedDomain === 'string' && payload.allowedDomain) {
|
|
73
|
+
claims.allowedDomain = payload.allowedDomain;
|
|
74
|
+
}
|
|
50
75
|
return claims;
|
|
51
76
|
}
|
|
52
77
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaosity/location-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Client library for Chaosity Location Service with AWS Location Service compatibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"@maplibre/maplibre-gl-geocoder": "^1.9.4",
|
|
67
|
-
"maplibre-gl": "^
|
|
67
|
+
"maplibre-gl": "^6.4.1"
|
|
68
68
|
},
|
|
69
69
|
"peerDependenciesMeta": {
|
|
70
70
|
"@maplibre/maplibre-gl-geocoder": {
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"@vitest/coverage-v8": "^3.0.0",
|
|
83
83
|
"eslint": "^10.1.0",
|
|
84
84
|
"husky": "^9.0.0",
|
|
85
|
-
"maplibre-gl": "^
|
|
85
|
+
"maplibre-gl": "^6.4.1",
|
|
86
86
|
"prettier": "^3.8.1",
|
|
87
87
|
"prettier-plugin-organize-imports": "^4.3.0",
|
|
88
88
|
"typescript": "^5.0.0",
|