mapricot 0.1.1 → 0.3.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 +14 -10
- package/dist/index.d.ts +17 -14
- package/dist/index.js +77 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,31 +1,27 @@
|
|
|
1
1
|
# Mapricot for JavaScript and TypeScript
|
|
2
2
|
|
|
3
|
-
The official JavaScript client for the [Mapricot API](https://mapricot.com/): address and place search, reverse geocoding, nearby places, routing, and IP geolocation, with 250,000 free requests every
|
|
3
|
+
The official JavaScript client for the [Mapricot API](https://mapricot.com/): address and place search, reverse geocoding, nearby places, routing, and IP geolocation, with 250,000 free requests every 30 days.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
npm install mapricot
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
It uses the built-in `fetch`, so it has no dependencies and runs in Node.js 20 and later, Deno (as `npm:mapricot`), Bun, Cloudflare Workers, and browsers. Types are included.
|
|
9
|
+
It uses the built-in `fetch`, so it has no dependencies and runs in Node.js 20 and later, Deno (as `npm:mapricot`), Bun, Cloudflare Workers, and browsers as old as Chrome 66, Firefox 57, and Safari 12.1. Types are included.
|
|
10
10
|
|
|
11
11
|
## Quick start
|
|
12
12
|
|
|
13
|
-
Create a server key in the [dashboard](https://app.mapricot.com/) and
|
|
14
|
-
|
|
15
|
-
```sh
|
|
16
|
-
export MAPRICOT_KEY="mapricot_sk_…"
|
|
17
|
-
```
|
|
13
|
+
Create a server key in the [dashboard](https://app.mapricot.com/) and pass it to the client. Keep it out of your source code, for example by reading it from an environment variable as here.
|
|
18
14
|
|
|
19
15
|
```js
|
|
20
16
|
import { Mapricot } from "mapricot";
|
|
21
17
|
|
|
22
|
-
const client = new Mapricot();
|
|
18
|
+
const client = new Mapricot({ apiKey: process.env.MAPRICOT_KEY });
|
|
23
19
|
|
|
24
20
|
const { results } = await client.search("128 SW 3rd Ave, Portland", { limit: 1 });
|
|
25
21
|
console.log(results[0].label, results[0].lat, results[0].lon);
|
|
26
22
|
```
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
In a web page, use a browser key, which works only from the origins you allow, and keep server keys on your server.
|
|
29
25
|
|
|
30
26
|
## Methods
|
|
31
27
|
|
|
@@ -50,7 +46,15 @@ const { routes } = await client.route([{ lat: 45.5189, lon: -122.6793 }, { lat:
|
|
|
50
46
|
console.log(routes[0].durationSeconds);
|
|
51
47
|
```
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
To cancel a request, such as an autocomplete request for text that has since changed, pass an `AbortSignal` as `signal` to any method. The request then rejects with an `AbortError`:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const request = client.autocomplete("1005 W Burn", { signal: controller.signal });
|
|
54
|
+
controller.abort();
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A route's `polyline` is encoded with six decimal places. Decode it with precision 6, as [decoding a route polyline](https://mapricot.com/guides/polyline-decoder/) shows.
|
|
54
58
|
|
|
55
59
|
If your app shows results, show the credits in each response's `attribution`.
|
|
56
60
|
|
package/dist/index.d.ts
CHANGED
|
@@ -73,25 +73,28 @@ export interface Point {
|
|
|
73
73
|
lat: number;
|
|
74
74
|
lon: number;
|
|
75
75
|
}
|
|
76
|
-
export interface
|
|
76
|
+
export interface RequestOptions {
|
|
77
|
+
/** Cancels the request, such as one for text that has since changed. */
|
|
78
|
+
signal?: AbortSignal;
|
|
79
|
+
}
|
|
80
|
+
export interface SearchOptions extends RequestOptions {
|
|
77
81
|
focus?: Point;
|
|
78
82
|
country?: string | string[];
|
|
79
83
|
limit?: number;
|
|
80
84
|
lang?: string;
|
|
81
85
|
}
|
|
82
|
-
export interface ReverseOptions {
|
|
86
|
+
export interface ReverseOptions extends RequestOptions {
|
|
83
87
|
limit?: number;
|
|
84
88
|
lang?: string;
|
|
85
89
|
}
|
|
86
|
-
export interface NearbyOptions {
|
|
90
|
+
export interface NearbyOptions extends RequestOptions {
|
|
87
91
|
category?: string | string[];
|
|
88
92
|
radius?: number;
|
|
89
93
|
limit?: number;
|
|
90
94
|
lang?: string;
|
|
91
95
|
}
|
|
92
96
|
export interface ClientOptions {
|
|
93
|
-
|
|
94
|
-
apiKey?: string;
|
|
97
|
+
apiKey: string;
|
|
95
98
|
baseUrl?: string;
|
|
96
99
|
/** Milliseconds per attempt. */
|
|
97
100
|
timeout?: number;
|
|
@@ -106,25 +109,25 @@ export declare class MapricotError extends Error {
|
|
|
106
109
|
}
|
|
107
110
|
export declare class Mapricot {
|
|
108
111
|
#private;
|
|
109
|
-
constructor(options
|
|
112
|
+
constructor(options: ClientOptions);
|
|
110
113
|
/** Find addresses and places matching free text. */
|
|
111
|
-
search(q: string, options?: SearchOptions): Promise<Places>;
|
|
114
|
+
search(q: string, { signal, ...options }?: SearchOptions): Promise<Places>;
|
|
112
115
|
/** Suggest addresses and places as someone types. */
|
|
113
|
-
autocomplete(q: string, options?: SearchOptions): Promise<Places>;
|
|
116
|
+
autocomplete(q: string, { signal, ...options }?: SearchOptions): Promise<Places>;
|
|
114
117
|
/** Find the address nearest a coordinate, or the area around it. */
|
|
115
|
-
reverse(lat: number, lon: number, options?: ReverseOptions): Promise<Places>;
|
|
118
|
+
reverse(lat: number, lon: number, { signal, ...options }?: ReverseOptions): Promise<Places>;
|
|
116
119
|
/** List places around a coordinate, optionally by category. */
|
|
117
|
-
nearby(lat: number, lon: number, options?: NearbyOptions): Promise<Places>;
|
|
120
|
+
nearby(lat: number, lon: number, { signal, ...options }?: NearbyOptions): Promise<Places>;
|
|
118
121
|
/** Look up one place by its Mapricot ID. */
|
|
119
|
-
place(id: string, options?: {
|
|
122
|
+
place(id: string, { signal, ...options }?: RequestOptions & {
|
|
120
123
|
lang?: string;
|
|
121
124
|
}): Promise<PlaceResult>;
|
|
122
125
|
/** Find a route through 2 to 20 waypoints. */
|
|
123
|
-
route(waypoints: Point[], options?: {
|
|
126
|
+
route(waypoints: Point[], { signal, ...options }?: RequestOptions & {
|
|
124
127
|
mode?: "drive" | "walk" | "bicycle";
|
|
125
128
|
}): Promise<Routes>;
|
|
126
129
|
/** Approximate location of a public IP address. */
|
|
127
|
-
ip(address: string): Promise<IpLocation>;
|
|
130
|
+
ip(address: string, { signal }?: RequestOptions): Promise<IpLocation>;
|
|
128
131
|
/** The key's account. Not billed, so it checks a key for free. */
|
|
129
|
-
account(): Promise<Account>;
|
|
132
|
+
account({ signal }?: RequestOptions): Promise<Account>;
|
|
130
133
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _Mapricot_instances, _Mapricot_apiKey, _Mapricot_baseUrl, _Mapricot_timeout, _Mapricot_maxRetries, _Mapricot_request;
|
|
1
13
|
export class MapricotError extends Error {
|
|
2
|
-
status;
|
|
3
|
-
code;
|
|
4
|
-
requestId;
|
|
5
14
|
constructor(status, code, message, requestId) {
|
|
6
15
|
super(message);
|
|
7
16
|
this.name = "MapricotError";
|
|
@@ -11,78 +20,92 @@ export class MapricotError extends Error {
|
|
|
11
20
|
}
|
|
12
21
|
}
|
|
13
22
|
export class Mapricot {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this
|
|
23
|
+
constructor(options) {
|
|
24
|
+
var _a, _b, _c;
|
|
25
|
+
_Mapricot_instances.add(this);
|
|
26
|
+
_Mapricot_apiKey.set(this, void 0);
|
|
27
|
+
_Mapricot_baseUrl.set(this, void 0);
|
|
28
|
+
_Mapricot_timeout.set(this, void 0);
|
|
29
|
+
_Mapricot_maxRetries.set(this, void 0);
|
|
30
|
+
if (!(options === null || options === void 0 ? void 0 : options.apiKey))
|
|
31
|
+
throw new Error("Pass apiKey, a Mapricot key.");
|
|
32
|
+
__classPrivateFieldSet(this, _Mapricot_apiKey, options.apiKey, "f");
|
|
33
|
+
__classPrivateFieldSet(this, _Mapricot_baseUrl, (_a = options.baseUrl) !== null && _a !== void 0 ? _a : "https://api.mapricot.com", "f");
|
|
34
|
+
__classPrivateFieldSet(this, _Mapricot_timeout, (_b = options.timeout) !== null && _b !== void 0 ? _b : 30000, "f");
|
|
35
|
+
__classPrivateFieldSet(this, _Mapricot_maxRetries, (_c = options.maxRetries) !== null && _c !== void 0 ? _c : 2, "f");
|
|
26
36
|
}
|
|
27
37
|
/** Find addresses and places matching free text. */
|
|
28
|
-
search(q, options = {}) {
|
|
29
|
-
return this
|
|
38
|
+
search(q, { signal, ...options } = {}) {
|
|
39
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", "/v1/search", { q, ...options }, signal);
|
|
30
40
|
}
|
|
31
41
|
/** Suggest addresses and places as someone types. */
|
|
32
|
-
autocomplete(q, options = {}) {
|
|
33
|
-
return this
|
|
42
|
+
autocomplete(q, { signal, ...options } = {}) {
|
|
43
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", "/v1/autocomplete", { q, ...options }, signal);
|
|
34
44
|
}
|
|
35
45
|
/** Find the address nearest a coordinate, or the area around it. */
|
|
36
|
-
reverse(lat, lon, options = {}) {
|
|
37
|
-
return this
|
|
46
|
+
reverse(lat, lon, { signal, ...options } = {}) {
|
|
47
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", "/v1/reverse", { lat, lon, ...options }, signal);
|
|
38
48
|
}
|
|
39
49
|
/** List places around a coordinate, optionally by category. */
|
|
40
|
-
nearby(lat, lon, options = {}) {
|
|
41
|
-
return this
|
|
50
|
+
nearby(lat, lon, { signal, ...options } = {}) {
|
|
51
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", "/v1/nearby", { lat, lon, ...options }, signal);
|
|
42
52
|
}
|
|
43
53
|
/** Look up one place by its Mapricot ID. */
|
|
44
|
-
place(id, options = {}) {
|
|
45
|
-
return this
|
|
54
|
+
place(id, { signal, ...options } = {}) {
|
|
55
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", `/v1/places/${encodeURIComponent(id)}`, options, signal);
|
|
46
56
|
}
|
|
47
57
|
/** Find a route through 2 to 20 waypoints. */
|
|
48
|
-
route(waypoints, options = {}) {
|
|
49
|
-
return this
|
|
58
|
+
route(waypoints, { signal, ...options } = {}) {
|
|
59
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "POST", "/v1/route", {}, signal, { waypoints, ...options });
|
|
50
60
|
}
|
|
51
61
|
/** Approximate location of a public IP address. */
|
|
52
|
-
ip(address) {
|
|
53
|
-
return this
|
|
62
|
+
ip(address, { signal } = {}) {
|
|
63
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", `/v1/ip/${encodeURIComponent(address)}`, {}, signal);
|
|
54
64
|
}
|
|
55
65
|
/** The key's account. Not billed, so it checks a key for free. */
|
|
56
|
-
account() {
|
|
57
|
-
return this
|
|
66
|
+
account({ signal } = {}) {
|
|
67
|
+
return __classPrivateFieldGet(this, _Mapricot_instances, "m", _Mapricot_request).call(this, "GET", "/v1/account", {}, signal);
|
|
58
68
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
}
|
|
70
|
+
_Mapricot_apiKey = new WeakMap(), _Mapricot_baseUrl = new WeakMap(), _Mapricot_timeout = new WeakMap(), _Mapricot_maxRetries = new WeakMap(), _Mapricot_instances = new WeakSet(), _Mapricot_request = async function _Mapricot_request(method, path, params, signal, body) {
|
|
71
|
+
const url = new URL(path, __classPrivateFieldGet(this, _Mapricot_baseUrl, "f"));
|
|
72
|
+
for (const [name, value] of Object.entries(params)) {
|
|
73
|
+
if (value === undefined)
|
|
74
|
+
continue;
|
|
75
|
+
url.searchParams.set(name, format(value));
|
|
76
|
+
}
|
|
77
|
+
const headers = { Authorization: `Bearer ${__classPrivateFieldGet(this, _Mapricot_apiKey, "f")}` };
|
|
78
|
+
if (body)
|
|
79
|
+
headers["Content-Type"] = "application/json";
|
|
80
|
+
for (let attempt = 0;; attempt++) {
|
|
81
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
82
|
+
throw abortReason(signal);
|
|
83
|
+
// AbortSignal.timeout and AbortSignal.any would do this, but are missing from browsers before 2022 and 2024.
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const cancel = () => controller.abort(abortReason(signal));
|
|
86
|
+
const timer = setTimeout(() => controller.abort(new DOMException("The request timed out.", "TimeoutError")), __classPrivateFieldGet(this, _Mapricot_timeout, "f"));
|
|
87
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener("abort", cancel);
|
|
88
|
+
let error;
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(url, { method, headers, body: body && JSON.stringify(body), signal: controller.signal });
|
|
76
91
|
if (response.ok)
|
|
77
92
|
return (await response.json());
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
93
|
+
error = await errorFrom(response);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
signal === null || signal === void 0 ? void 0 : signal.removeEventListener("abort", cancel);
|
|
98
|
+
}
|
|
99
|
+
if (attempt < __classPrivateFieldGet(this, _Mapricot_maxRetries, "f") && retryable(error)) {
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, 500 * 2 ** attempt));
|
|
101
|
+
continue;
|
|
84
102
|
}
|
|
103
|
+
throw error;
|
|
85
104
|
}
|
|
105
|
+
};
|
|
106
|
+
function abortReason(signal) {
|
|
107
|
+
var _a;
|
|
108
|
+
return (_a = signal.reason) !== null && _a !== void 0 ? _a : new DOMException("The request was cancelled.", "AbortError");
|
|
86
109
|
}
|
|
87
110
|
function format(value) {
|
|
88
111
|
if (Array.isArray(value))
|