@superrouteca/smap 0.0.0-stage → 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (unreleased)
4
+
5
+ - The Web SDK as an npm package: ES module and CommonJS entry points with types, the map renderer bundled, safe to
6
+ import on a server.
7
+ - The JS client as `@superrouteca/smap/client` for browsers, Node.js 18+ and workers.
8
+ - The stylesheet as `@superrouteca/smap/smap.css`.
9
+ - Map keys (`apiKey`) beside tokens.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Goodneo Solutions
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 CHANGED
@@ -1,3 +1,93 @@
1
- # Temporary Holding Version
1
+ # @superrouteca/smap
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Maps from Superroute's sMap service for the web: five colour schemes, labels in any language, your points, lines and
4
+ areas drawn on the GPU (hundreds of thousands of points, clustered or not), 3D buildings and areas, and tokens that
5
+ renew themselves. Also the JS client (no map view) for servers and workers: tokens, the nearest node, styles, tiles
6
+ and raw reads.
7
+
8
+ - Version 1.0.0, MIT licence (see `LICENSE` at the repository root)
9
+ - Works with bundlers (Vite, webpack, Next.js and others): ES module and CommonJS entry points with types
10
+ - Nothing else to install: the map renderer is bundled in the package
11
+ - Importing is safe on a server; a map is created in the browser only
12
+
13
+ ## Installation
14
+
15
+ ```sh
16
+ npm install @superrouteca/smap
17
+ ```
18
+
19
+ Without a bundler, the same SDK is served by the service:
20
+
21
+ ```html
22
+ <link rel="stylesheet" href="https://tile.srsr.ca/sdk/v1/smap.css">
23
+ <script src="https://tile.srsr.ca/sdk/v1/smap.js"></script>
24
+ ```
25
+
26
+ ## A minimal map
27
+
28
+ ```js
29
+ import { Map } from '@superrouteca/smap';
30
+ import '@superrouteca/smap/smap.css';
31
+
32
+ const map = new Map({
33
+ container: 'map', // an element or its id
34
+ apiKey: 'smk_…', // a map key that allows this site
35
+ style: 'light', // light, white, grayscale, dark, black
36
+ language: 'en',
37
+ center: [-79.38, 43.65], // [longitude, latitude]
38
+ zoom: 11,
39
+ });
40
+
41
+ await map.ready;
42
+ map.addPoints('stops', [{ lng: -79.38, lat: 43.65, name: 'Depot' }], { cluster: true, label: 'name' });
43
+ map.addLines('route', routeGeoJson, { color: '#16a34a', width: 5 });
44
+ map.addPolygons('zones', zonesGeoJson, { fill: '#f97316', extrude: { height: 'height' } });
45
+ map.setBuildings3D(true);
46
+ map.fitLayer('stops');
47
+ ```
48
+
49
+ `setStyle()` and `setLanguage()` keep your layers. Other calls: `setData`, `setVisible`, `removeLayer`, `layers`,
50
+ `flyTo`, `setProjection`, `on` / `off` / `once`, `remove`. `map.engine` is the renderer's own map for anything the
51
+ SDK does not wrap, and `getEngine()` gives the renderer itself.
52
+
53
+ In a server-rendered page (for example Next.js), create the map in an effect or event handler, never while rendering
54
+ on the server: `new Map()` throws outside a browser. Importing the package is fine anywhere.
55
+
56
+ ## Map keys and tokens
57
+
58
+ - **Map key** (`apiKey: 'smk_…'`): created in the Superroute developer center, with the sites (and apps) it may be
59
+ used from. Safe to put in a page.
60
+ - **Token** (`token: 'sm1.…'`, or `getToken: async () => …`): signed by your own server for a limited time.
61
+ With `getToken` the SDK asks for a new token two minutes before the current one expires.
62
+ - With both, both are sent and the token is checked first. Superroute's own sites need neither.
63
+
64
+ Other options: `baseUrl` (default `https://tile.srsr.ca`), `nodes` (node addresses known in advance, used while
65
+ `baseUrl` cannot be reached), `nearest` (read from the nearest node, default true). Every other option (`pitch`,
66
+ `bearing`, `minZoom`, `maxZoom`, `maxBounds`, …) is passed to the renderer.
67
+
68
+ ## The JS client
69
+
70
+ ```js
71
+ import SMapClient from '@superrouteca/smap/client'; // or require('@superrouteca/smap/client')
72
+
73
+ const client = new SMapClient({ baseUrl: 'https://tile.srsr.ca', apiKey: 'smk_…' });
74
+ const style = await client.style('dark', 'fr'); // a style document
75
+ const tile = await client.tile('basemap', 12, 1143, 1493); // Uint8Array, or null where there is none
76
+ ```
77
+
78
+ Runs wherever `fetch` exists (browsers, Node.js 18+, workers); elsewhere pass `fetch` in the options.
79
+
80
+ ## Data attribution
81
+
82
+ The map data credit stays visible on every map, as the data licence requires.
83
+
84
+ ## Where the code comes from
85
+
86
+ `dist/` is copied from the sMap service repository by `tools/sync-js.sh`; `dist/SOURCE.json` records the commit.
87
+ It is never edited here. The type declarations in `types/` are kept in this repository.
88
+
89
+ ## Tests
90
+
91
+ ```sh
92
+ npm test
93
+ ```
@@ -0,0 +1,18 @@
1
+ {
2
+ "repository": "sMap",
3
+ "commit": "54f7117da908fd02d8df09c85a61777299263e06",
4
+ "commitSubject": "Version 1.0.1 (was 1.1.0, unreleased)",
5
+ "uncommittedSources": false,
6
+ "sdkVersion": "1.0.1",
7
+ "engine": "maplibre-gl 5.24.0",
8
+ "files": {
9
+ "smap.mjs": "33375b7d5167ed8aab6e9351cf1e5074200d8654f91d4a5f0aa2c680ada603b8",
10
+ "smap.cjs": "b878b5a59c6422ed5d98e95848755e549f473574d5366b3babe0a11796825acc",
11
+ "smap.css": "ab1e70d59ec40465bae7e7030da2f3ccf28133fd502e62bd598eefbadfd7a732",
12
+ "smap-client.cjs": "fdc7ab0c8e53a2e941c5d28af51fb6c0508b2690d0beec5369a9fa94ceba0392",
13
+ "smap-client.mjs": "d0bd9ce3a42484888f7627d548f0cd0ff85854c2f9919be867175aae33bf8929",
14
+ "smap-client.d.cts": "a87a12d46ac61971a5c294afe4df49c481552aed65c7404537dacdc0afaff512",
15
+ "smap-client.d.mts": "009474b826fb3016b0200cbf40a969ea42ba331c6ff37cfb363c61ce54084e28",
16
+ "vendor-licenses.txt": "ee5fc05a0677eaf69601d2c7db0d9ecd6cc27c3abc1d0733bc9ed34707cf8ef2"
17
+ }
18
+ }
@@ -0,0 +1,301 @@
1
+ /* Generated by tools/sync-js.sh from the sMap repository (see SOURCE.json). Do not edit. */
2
+ /*! sMap JS client 1.0.1 — tokens, the nearest node, styles, tiles and raw reads, without a map view. */
3
+ /*
4
+ * Runs wherever `fetch` exists: browsers, Node.js 18+, workers; elsewhere (mini programs, older runtimes) pass your
5
+ * own `fetch`. UMD: `window.SMapClient`, `require('smap-client')`, or an AMD module.
6
+ *
7
+ * const client = new SMapClient({ baseUrl: 'https://tile.srsr.ca', getToken: () => myServer.mapToken() });
8
+ * const keyed = new SMapClient({ baseUrl: 'https://tile.srsr.ca', apiKey: 'smk_…' }); // or a map key
9
+ * const tile = await client.tile('basemap', 12, 1143, 1493); // Uint8Array (vector tile)
10
+ * const style = await client.style('light', 'en'); // style document
11
+ *
12
+ * Every request goes to the nearest node that answers (asked of baseUrl, remembered for an hour) and moves to the
13
+ * next one when a node fails.
14
+ */
15
+ (function (root, factory) {
16
+ if (typeof define === 'function' && define.amd) { define([], factory); }
17
+ else if (typeof module === 'object' && module.exports) { module.exports = factory(); }
18
+ else { root.SMapClient = factory(); }
19
+ }(typeof self !== 'undefined' ? self : this, function () {
20
+ 'use strict';
21
+
22
+ var VERSION = '1.0.1';
23
+ var NODE_TTL = 3600 * 1000; // the measured order
24
+ var KNOWN_TTL = 30 * 86400 * 1000; // the last node list received, used when none can be read
25
+
26
+ function unique(list) {
27
+ var seen = {};
28
+ return list.filter(function (u) { if (!u || seen[u]) { return false; } seen[u] = true; return true; });
29
+ }
30
+ var memory = {};
31
+
32
+ function store() {
33
+ try {
34
+ if (typeof localStorage !== 'undefined') { localStorage.getItem('smap'); return localStorage; }
35
+ } catch (e) { /* storage unavailable */ }
36
+ return { getItem: function (k) { return memory[k] || null; }, setItem: function (k, v) { memory[k] = v; } };
37
+ }
38
+
39
+ function decodeBase64Url(s) {
40
+ s = s.replace(/-/g, '+').replace(/_/g, '/');
41
+ while (s.length % 4) { s += '='; }
42
+ if (typeof atob === 'function') { return atob(s); }
43
+ return Buffer.from(s, 'base64').toString('binary');
44
+ }
45
+
46
+ /** Seconds since 1970 when a token expires; 0 when it cannot be read. */
47
+ function tokenExpiry(token) {
48
+ try { return JSON.parse(decodeBase64Url(String(token).split('.')[1])).exp || 0; } catch (e) { return 0; }
49
+ }
50
+
51
+ function SMapError(message, status, url) {
52
+ var e = new Error(message);
53
+ e.name = 'SMapError';
54
+ e.status = status || 0;
55
+ e.url = url || '';
56
+ return e;
57
+ }
58
+
59
+ /**
60
+ * @param {Object} options
61
+ * @param {string} options.baseUrl the public sMap address (e.g. https://tile.srsr.ca)
62
+ * @param {string} [options.token] a map token; or
63
+ * @param {function(): (string|Promise<string>)} [options.getToken] called at start and before each token expires
64
+ * @param {string} [options.apiKey] a map key (`smk_…`); with a token both are sent (token first)
65
+ * @param {string[]} [options.nodes] node URLs known in advance (used while baseUrl is down)
66
+ * @param {boolean} [options.nearest=true] read from the nearest node
67
+ * @param {function} [options.fetch] a fetch implementation (default: the global one)
68
+ * @param {number} [options.timeoutMs=15000] per request
69
+ */
70
+ function SMapClient(options) {
71
+ if (!(this instanceof SMapClient)) { return new SMapClient(options); }
72
+ options = options || {};
73
+ if (!options.baseUrl) { throw SMapError('sMap: baseUrl is required'); }
74
+ this.baseUrl = String(options.baseUrl).replace(/\/$/, '');
75
+ this._fetch = options.fetch || (typeof fetch === 'function' ? fetch.bind(typeof self !== 'undefined' ? self : globalThis) : null);
76
+ if (!this._fetch) { throw SMapError('sMap: no fetch available; pass options.fetch'); }
77
+ this._token = options.token || null;
78
+ this._getToken = options.getToken || null;
79
+ this._apiKey = options.apiKey || null;
80
+ this._nearest = options.nearest !== false;
81
+ this._seeds = (options.nodes || []).map(function (u) { return String(u).replace(/\/$/, ''); });
82
+ this._timeout = options.timeoutMs || 15000;
83
+ this._nodes = null; // ordered: nearest first
84
+ this._picking = null;
85
+ this._tokening = null;
86
+ }
87
+
88
+ SMapClient.version = VERSION;
89
+ SMapClient.tokenExpiry = tokenExpiry;
90
+
91
+ SMapClient.prototype._timed = function (url, init, ms) {
92
+ var ctrl = typeof AbortController !== 'undefined' ? new AbortController() : null;
93
+ var timer = ctrl ? setTimeout(function () { ctrl.abort(); }, ms) : null;
94
+ init = init || {};
95
+ if (ctrl) { init.signal = ctrl.signal; }
96
+ return this._fetch(url, init).then(function (res) { clearTimeout(timer); return res; }, function (e) { clearTimeout(timer); throw e; });
97
+ };
98
+
99
+ /** The token to send now, asking getToken again two minutes before it expires. */
100
+ SMapClient.prototype.token = function () {
101
+ var self = this;
102
+ var exp = this._token ? tokenExpiry(this._token) : 0;
103
+ var fresh = this._token && (!exp || exp - Date.now() / 1000 > 120);
104
+ if (fresh || !this._getToken) { return Promise.resolve(this._token); }
105
+ if (!this._tokening) {
106
+ this._tokening = Promise.resolve(this._getToken()).then(function (t) {
107
+ self._token = t;
108
+ self._tokening = null;
109
+ return t;
110
+ }, function (e) { self._tokening = null; throw e; });
111
+ }
112
+ return this._tokening;
113
+ };
114
+
115
+ /**
116
+ * The nodes in the order they are tried: nearest first, then the others; baseUrl alone when nearest is off or the
117
+ * list cannot be read.
118
+ *
119
+ * @returns {Promise<string[]>}
120
+ */
121
+ SMapClient.prototype.nodes = function () {
122
+ var self = this;
123
+ if (this._nodes) { return Promise.resolve(this._nodes); }
124
+ if (!this._nearest) { this._nodes = [this.baseUrl]; return Promise.resolve(this._nodes); }
125
+ if (this._picking) { return this._picking; }
126
+ var key = 'smap.nodes:' + this.baseUrl;
127
+ var storage = store();
128
+ var saved = null;
129
+ try { saved = JSON.parse(storage.getItem(key) || 'null'); } catch (e) { saved = null; }
130
+ if (saved && saved.urls && saved.urls.length && Date.now() - saved.at < NODE_TTL) {
131
+ this._nodes = saved.urls;
132
+ return Promise.resolve(this._nodes);
133
+ }
134
+ // Every node this client knows of: the kept list (30 days), the seed list, then baseUrl.
135
+ var kept = saved && saved.known && Date.now() - (saved.knownAt || 0) < KNOWN_TTL ? saved.known : [];
136
+ var known = unique([this.baseUrl].concat(this._seeds, kept));
137
+ this._picking = this._discover(known)
138
+ .then(function (list) {
139
+ var urls = list || unique(self._seeds.concat(kept));
140
+ if (urls.length === 0) { return { order: [self.baseUrl], known: null }; }
141
+ return self._measure(urls).then(function (order) { return { order: order, known: list }; });
142
+ })
143
+ .then(function (r) {
144
+ self._nodes = r.order;
145
+ self._picking = null;
146
+ // An order is remembered for the hour only when a node list was read; a guess made while nothing answered
147
+ // is tried again by the next client instead of being kept.
148
+ var record = { urls: r.known ? r.order : [], at: r.known ? Date.now() : 0, known: r.known || kept, knownAt: r.known ? Date.now() : (saved && saved.knownAt) || 0 };
149
+ try { storage.setItem(key, JSON.stringify(record)); } catch (e) { /* ignore */ }
150
+ return r.order;
151
+ });
152
+ return this._picking;
153
+ };
154
+
155
+ /** Asks each node in turn for the node list (any node answers the whole list); null when none answers. */
156
+ SMapClient.prototype._discover = function (candidates) {
157
+ var self = this;
158
+ function ask(i) {
159
+ if (i >= candidates.length) { return Promise.resolve(null); }
160
+ return self._timed(candidates[i] + '/v1/nodes', {}, 2000)
161
+ .then(function (res) { return res.ok ? res.json() : null; })
162
+ .then(function (body) {
163
+ var urls = ((body && body.nodes) || []).map(function (n) { return String(n.url).replace(/\/$/, ''); });
164
+ return urls.length ? urls : ask(i + 1);
165
+ }, function () { return ask(i + 1); });
166
+ }
167
+ return ask(0);
168
+ };
169
+
170
+ /** Times one small request to each node: fastest first, silent ones after, baseUrl last when not listed. */
171
+ SMapClient.prototype._measure = function (urls) {
172
+ var self = this;
173
+ return Promise.all(urls.map(function (url) {
174
+ var t0 = Date.now();
175
+ return self._timed(url + '/v1/ping', { cache: 'no-store' }, 1500)
176
+ .then(function (res) { return { url: url, ms: res.ok ? Date.now() - t0 : Infinity }; }, function () { return { url: url, ms: Infinity }; });
177
+ })).then(function (timed) {
178
+ timed.sort(function (a, b) { return a.ms - b.ms; });
179
+ var order = timed.map(function (t) { return t.url; });
180
+ if (order.indexOf(self.baseUrl) < 0) { order.push(self.baseUrl); }
181
+ return order;
182
+ });
183
+ };
184
+
185
+ /** Forgets the chosen node order, so the next request measures again. */
186
+ SMapClient.prototype.resetNodes = function () {
187
+ this._nodes = null;
188
+ var key = 'smap.nodes:' + this.baseUrl;
189
+ try {
190
+ var saved = JSON.parse(store().getItem(key) || 'null');
191
+ // The kept node list survives a reset; only the measured order is forgotten.
192
+ store().setItem(key, JSON.stringify(saved ? { urls: [], at: 0, known: saved.known, knownAt: saved.knownAt } : null));
193
+ } catch (e) { /* ignore */ }
194
+ };
195
+
196
+ /**
197
+ * GET `path` from the nearest node that answers, with the token; a node that fails (network error, 5xx) is moved
198
+ * to the end and the next one is tried. 4xx answers are final.
199
+ *
200
+ * @param {string} path starting with /
201
+ * @param {Object} [headers]
202
+ * @returns {Promise<Response>}
203
+ */
204
+ SMapClient.prototype.request = function (path, headers) {
205
+ var self = this;
206
+ return Promise.all([this.nodes(), this.token()]).then(function (r) {
207
+ var nodes = r[0].slice();
208
+ var token = r[1];
209
+ var last = null;
210
+ function attempt(i) {
211
+ if (i >= nodes.length) { throw last || SMapError('sMap: no node answered', 0, path); }
212
+ var h = {};
213
+ for (var k in (headers || {})) { if (Object.prototype.hasOwnProperty.call(headers, k)) { h[k] = headers[k]; } }
214
+ if (token) { h.Authorization = 'Bearer ' + token; }
215
+ if (self._apiKey) { h['X-SMap-Key'] = self._apiKey; }
216
+ var url = nodes[i] + path;
217
+ return self._timed(url, { headers: h }, self._timeout).then(function (res) {
218
+ if (res.status >= 500) {
219
+ last = SMapError('sMap: HTTP ' + res.status, res.status, url);
220
+ self._demote(nodes[i]);
221
+ return attempt(i + 1);
222
+ }
223
+ if (!res.ok && res.status !== 206) {
224
+ return res.text().then(function (text) { throw SMapError('sMap: ' + (text || ('HTTP ' + res.status)), res.status, url); });
225
+ }
226
+ return res;
227
+ }, function (e) {
228
+ last = SMapError('sMap: ' + (e && e.message ? e.message : 'network error'), 0, url);
229
+ self._demote(nodes[i]);
230
+ return attempt(i + 1);
231
+ });
232
+ }
233
+ return attempt(0);
234
+ });
235
+ };
236
+
237
+ SMapClient.prototype._demote = function (url) {
238
+ if (!this._nodes || this._nodes.length < 2) { return; }
239
+ var i = this._nodes.indexOf(url);
240
+ if (i >= 0) { this._nodes.splice(i, 1); this._nodes.push(url); }
241
+ };
242
+
243
+ function bytes(res) { return res.arrayBuffer().then(function (b) { return new Uint8Array(b); }); }
244
+
245
+ // A map key also goes in the query of styles and TileJSON: the service carries it into their tile URLs, so a
246
+ // renderer given the document reads its tiles with the key.
247
+ SMapClient.prototype._withKey = function (path) {
248
+ if (!this._apiKey) { return path; }
249
+ return path + (path.indexOf('?') >= 0 ? '&' : '?') + 'key=' + encodeURIComponent(this._apiKey);
250
+ };
251
+
252
+ /**
253
+ * A style document ('light', 'white', 'grayscale', 'dark', 'black') with labels in `language`.
254
+ * Its tile URLs point at the node that answered.
255
+ */
256
+ SMapClient.prototype.style = function (flavor, language) {
257
+ var q = language ? '?lang=' + encodeURIComponent(language) : '';
258
+ return this.request(this._withKey('/v1/styles/' + encodeURIComponent(flavor || 'light') + q)).then(function (r) { return r.json(); });
259
+ };
260
+
261
+ /** TileJSON of a source (bounds, zooms, layers, tile URL template). */
262
+ SMapClient.prototype.tileJSON = function (source) {
263
+ return this.request(this._withKey('/v1/tiles/' + encodeURIComponent(source || 'basemap'))).then(function (r) { return r.json(); });
264
+ };
265
+
266
+ /** One vector tile as bytes; null where the source has no tile (204 / 404). */
267
+ SMapClient.prototype.tile = function (source, z, x, y) {
268
+ var path = '/v1/tiles/' + encodeURIComponent(source) + '/' + (z | 0) + '/' + (x | 0) + '/' + (y | 0);
269
+ return this.request(path).then(function (r) { return r.status === 204 ? null : bytes(r); }, function (e) {
270
+ if (e && e.status === 404) { return null; }
271
+ throw e;
272
+ });
273
+ };
274
+
275
+ /** Raw bytes `[start, end]` (inclusive) of a source's archive, where your access allows raw reads. */
276
+ SMapClient.prototype.range = function (source, start, end) {
277
+ return this.request('/' + encodeURIComponent(source) + '.pmtiles', { Range: 'bytes=' + start + '-' + end }).then(bytes);
278
+ };
279
+
280
+ /** A font glyph range (`0-255.pbf` style), for renderers that load fonts themselves. */
281
+ SMapClient.prototype.glyphs = function (fontstack, range) {
282
+ return this.request('/v1/fonts/' + encodeURIComponent(fontstack) + '/' + range + '.pbf').then(bytes);
283
+ };
284
+
285
+ /**
286
+ * Headers and URL rewriting for a renderer that fetches by itself: returns the URL unchanged plus the
287
+ * Authorization (and map key) headers to add for sMap URLs; none for any other host.
288
+ */
289
+ SMapClient.prototype.authorize = function (url) {
290
+ var self = this;
291
+ return this.token().then(function (token) {
292
+ var ours = url.indexOf(self.baseUrl) === 0 || self._seeds.concat(self._nodes || []).some(function (n) { return url.indexOf(n) === 0; });
293
+ var headers = {};
294
+ if (ours && token) { headers.Authorization = 'Bearer ' + token; }
295
+ if (ours && self._apiKey) { headers['X-SMap-Key'] = self._apiKey; }
296
+ return { url: url, headers: headers };
297
+ });
298
+ };
299
+
300
+ return SMapClient;
301
+ }));
@@ -0,0 +1,43 @@
1
+ // Generated by tools/sync-js.sh. Do not edit.
2
+ // sMap JS client — type declarations (UMD: `require('smap-client')`, `import SMapClient from …`, `window.SMapClient`).
3
+ declare namespace SMapClient {
4
+ interface Options {
5
+ /** The public sMap address, e.g. https://tile.srsr.ca */
6
+ baseUrl: string;
7
+ token?: string;
8
+ getToken?: () => string | Promise<string>;
9
+ /** A map key (`smk_…`); with a token both are sent and the token is checked first. */
10
+ apiKey?: string;
11
+ /** Node URLs known in advance, used while baseUrl is down. */
12
+ nodes?: string[];
13
+ /** Read from the nearest node (default true). */
14
+ nearest?: boolean;
15
+ fetch?: typeof fetch;
16
+ /** Per request, default 15000. */
17
+ timeoutMs?: number;
18
+ }
19
+ type StyleFlavor = 'light' | 'white' | 'grayscale' | 'dark' | 'black';
20
+ interface SMapError extends Error {
21
+ status: number;
22
+ url: string;
23
+ }
24
+ }
25
+
26
+ declare class SMapClient {
27
+ constructor(options: SMapClient.Options);
28
+ static readonly version: string;
29
+ static tokenExpiry(token: string): number;
30
+ readonly baseUrl: string;
31
+ token(): Promise<string | null>;
32
+ nodes(): Promise<string[]>;
33
+ resetNodes(): void;
34
+ request(path: string, headers?: Record<string, string>): Promise<Response>;
35
+ style(flavor?: SMapClient.StyleFlavor, language?: string): Promise<Record<string, unknown>>;
36
+ tileJSON(source?: string): Promise<Record<string, unknown>>;
37
+ tile(source: string, z: number, x: number, y: number): Promise<Uint8Array | null>;
38
+ range(source: string, start: number, end: number): Promise<Uint8Array>;
39
+ glyphs(fontstack: string, range: string): Promise<Uint8Array>;
40
+ authorize(url: string): Promise<{ url: string; headers: Record<string, string> }>;
41
+ }
42
+
43
+ export = SMapClient;
@@ -0,0 +1,44 @@
1
+ // Generated by tools/sync-js.sh. Do not edit.
2
+ // sMap JS client — type declarations (UMD: `require('smap-client')`, `import SMapClient from …`, `window.SMapClient`).
3
+ declare namespace SMapClient {
4
+ interface Options {
5
+ /** The public sMap address, e.g. https://tile.srsr.ca */
6
+ baseUrl: string;
7
+ token?: string;
8
+ getToken?: () => string | Promise<string>;
9
+ /** A map key (`smk_…`); with a token both are sent and the token is checked first. */
10
+ apiKey?: string;
11
+ /** Node URLs known in advance, used while baseUrl is down. */
12
+ nodes?: string[];
13
+ /** Read from the nearest node (default true). */
14
+ nearest?: boolean;
15
+ fetch?: typeof fetch;
16
+ /** Per request, default 15000. */
17
+ timeoutMs?: number;
18
+ }
19
+ type StyleFlavor = 'light' | 'white' | 'grayscale' | 'dark' | 'black';
20
+ interface SMapError extends Error {
21
+ status: number;
22
+ url: string;
23
+ }
24
+ }
25
+
26
+ declare class SMapClient {
27
+ constructor(options: SMapClient.Options);
28
+ static readonly version: string;
29
+ static tokenExpiry(token: string): number;
30
+ readonly baseUrl: string;
31
+ token(): Promise<string | null>;
32
+ nodes(): Promise<string[]>;
33
+ resetNodes(): void;
34
+ request(path: string, headers?: Record<string, string>): Promise<Response>;
35
+ style(flavor?: SMapClient.StyleFlavor, language?: string): Promise<Record<string, unknown>>;
36
+ tileJSON(source?: string): Promise<Record<string, unknown>>;
37
+ tile(source: string, z: number, x: number, y: number): Promise<Uint8Array | null>;
38
+ range(source: string, start: number, end: number): Promise<Uint8Array>;
39
+ glyphs(fontstack: string, range: string): Promise<Uint8Array>;
40
+ authorize(url: string): Promise<{ url: string; headers: Record<string, string> }>;
41
+ }
42
+
43
+ export { SMapClient };
44
+ export default SMapClient;