@carto/api-client 0.4.9-alpha.0 → 0.4.10-alpha.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/build/api-client.cjs +10409 -2202
  3. package/build/api-client.cjs.map +1 -1
  4. package/build/api-client.modern.js +9955 -1938
  5. package/build/api-client.modern.js.map +1 -1
  6. package/build/constants-internal.d.ts +8 -0
  7. package/build/constants.d.ts +4 -1
  8. package/build/fetch-map/basemap-styles.d.ts +27 -0
  9. package/build/fetch-map/basemap.d.ts +17 -0
  10. package/build/fetch-map/fetch-map.d.ts +47 -0
  11. package/build/fetch-map/index.d.ts +7 -0
  12. package/build/fetch-map/layer-map.d.ts +28 -0
  13. package/build/fetch-map/parse-map.d.ts +39 -0
  14. package/build/fetch-map/source.d.ts +20 -0
  15. package/build/fetch-map/types.d.ts +220 -0
  16. package/build/fetch-map/utils.d.ts +18 -0
  17. package/build/index.d.ts +1 -0
  18. package/build/models/model.d.ts +0 -2
  19. package/build/sources/types.d.ts +4 -1
  20. package/build/types.d.ts +2 -0
  21. package/build/widget-sources/types.d.ts +7 -0
  22. package/package.json +24 -21
  23. package/src/constants-internal.ts +10 -0
  24. package/src/constants.ts +5 -1
  25. package/src/fetch-map/basemap-styles.ts +159 -0
  26. package/src/fetch-map/basemap.ts +120 -0
  27. package/src/fetch-map/fetch-map.ts +331 -0
  28. package/src/fetch-map/index.ts +13 -0
  29. package/src/fetch-map/layer-map.ts +461 -0
  30. package/src/fetch-map/parse-map.ts +425 -0
  31. package/src/fetch-map/source.ts +233 -0
  32. package/src/fetch-map/types.ts +268 -0
  33. package/src/fetch-map/utils.ts +69 -0
  34. package/src/index.ts +1 -0
  35. package/src/models/model.ts +0 -2
  36. package/src/sources/types.ts +4 -1
  37. package/src/types.ts +10 -0
  38. package/src/widget-sources/types.ts +7 -0
  39. package/src/widget-sources/widget-source.ts +0 -2
@@ -0,0 +1,159 @@
1
+ import {CartoAPIError, APIErrorContext} from '../api/index.js';
2
+ import {GoogleBasemapProps} from './types.js';
3
+
4
+ const cartoStyleUrlTemplate =
5
+ 'https://basemaps.cartocdn.com/gl/{basemap}-gl-style/style.json';
6
+
7
+ export const CARTO_MAP_STYLES = ['positron', 'dark-matter', 'voyager'];
8
+
9
+ export const GOOGLE_BASEMAPS: Record<string, GoogleBasemapProps> = {
10
+ roadmap: {
11
+ mapTypeId: 'roadmap',
12
+ mapId: '3754c817b510f791',
13
+ },
14
+ 'google-positron': {
15
+ mapTypeId: 'roadmap',
16
+ mapId: 'ea84ae4203ef21cd',
17
+ },
18
+ 'google-dark-matter': {
19
+ mapTypeId: 'roadmap',
20
+ mapId: '2fccc3b36c22a0e2',
21
+ },
22
+ 'google-voyager': {
23
+ mapTypeId: 'roadmap',
24
+ mapId: '885caf1e15bb9ef2',
25
+ },
26
+ satellite: {
27
+ mapTypeId: 'satellite',
28
+ },
29
+ hybrid: {
30
+ mapTypeId: 'hybrid',
31
+ },
32
+ terrain: {
33
+ mapTypeId: 'terrain',
34
+ },
35
+ };
36
+
37
+ type StyleLayerGroupSlug =
38
+ | 'label'
39
+ | 'road'
40
+ | 'border'
41
+ | 'building'
42
+ | 'water'
43
+ | 'land';
44
+ type StyleLayerGroup = {
45
+ slug: StyleLayerGroupSlug;
46
+ filter: (layer: any) => boolean;
47
+ defaultVisibility: boolean;
48
+ };
49
+
50
+ export const STYLE_LAYER_GROUPS: StyleLayerGroup[] = [
51
+ {
52
+ slug: 'label',
53
+ filter: ({id}: {id: string}) =>
54
+ Boolean(
55
+ id.match(
56
+ /(?=(label|_label|place-|place_|poi-|poi_|watername_|roadname_|housenumber))/
57
+ )
58
+ ),
59
+ defaultVisibility: true,
60
+ },
61
+ {
62
+ slug: 'road',
63
+ filter: ({id}: {id: string}) =>
64
+ Boolean(id.match(/(?=(road|railway|tunnel|street|bridge))(?!.*label)/)),
65
+ defaultVisibility: true,
66
+ },
67
+ {
68
+ slug: 'border',
69
+ filter: ({id}: {id: string}) =>
70
+ Boolean(id.match(/border|boundaries|boundary_/)),
71
+ defaultVisibility: false,
72
+ },
73
+ {
74
+ slug: 'building',
75
+ filter: ({id}: {id: string}) => Boolean(id.match(/building/)),
76
+ defaultVisibility: true,
77
+ },
78
+ {
79
+ slug: 'water',
80
+ filter: ({id}: {id: string}) =>
81
+ Boolean(id.match(/(?=(water|stream|ferry))/)),
82
+ defaultVisibility: true,
83
+ },
84
+ {
85
+ slug: 'land',
86
+ filter: ({id}: {id: string}) =>
87
+ Boolean(
88
+ id.match(/(?=(parks|landcover|industrial|sand|hillshade|park_))/)
89
+ ),
90
+ defaultVisibility: true,
91
+ },
92
+ ];
93
+
94
+ export function applyLayerGroupFilters(
95
+ style: any,
96
+ visibleLayerGroups: Record<StyleLayerGroupSlug, boolean>
97
+ ) {
98
+ if (!Array.isArray(style?.layers)) {
99
+ return style;
100
+ }
101
+
102
+ const removedLayerFilters = STYLE_LAYER_GROUPS.filter(
103
+ (lg) => !visibleLayerGroups[lg.slug]
104
+ ).map((lg) => lg.filter);
105
+
106
+ const visibleLayers = style.layers.filter((layer: any) =>
107
+ removedLayerFilters.every((match) => !match(layer))
108
+ );
109
+
110
+ return {
111
+ ...style,
112
+ layers: visibleLayers,
113
+ };
114
+ }
115
+
116
+ export function someLayerGroupsDisabled(
117
+ visibleLayerGroups?: Record<StyleLayerGroupSlug, boolean>
118
+ ) {
119
+ return (
120
+ visibleLayerGroups &&
121
+ Object.values(visibleLayerGroups).every(Boolean) === false
122
+ );
123
+ }
124
+
125
+ export function getStyleUrl(styleType: string) {
126
+ return cartoStyleUrlTemplate.replace('{basemap}', styleType);
127
+ }
128
+
129
+ export async function fetchStyle({
130
+ styleUrl,
131
+ errorContext,
132
+ }: {
133
+ styleUrl: string;
134
+ errorContext?: APIErrorContext;
135
+ }) {
136
+ /* global fetch */
137
+ let response: Response | undefined;
138
+ return await fetch(styleUrl, {mode: 'cors'})
139
+ .then((res) => {
140
+ response = res;
141
+ return res.json();
142
+ })
143
+ .catch((error) => {
144
+ throw new CartoAPIError(
145
+ error,
146
+ {...errorContext, requestType: 'Basemap style'},
147
+ response
148
+ );
149
+ });
150
+ }
151
+
152
+ export default {
153
+ VOYAGER: getStyleUrl('voyager'),
154
+ POSITRON: getStyleUrl('positron'),
155
+ DARK_MATTER: getStyleUrl('dark-matter'),
156
+ VOYAGER_NOLABELS: getStyleUrl('voyager-nolabels'),
157
+ POSITRON_NOLABELS: getStyleUrl('positron-nolabels'),
158
+ DARK_MATTER_NOLABELS: getStyleUrl('dark-matter-nolabels'),
159
+ } as const;
@@ -0,0 +1,120 @@
1
+ import {
2
+ GOOGLE_BASEMAPS,
3
+ CARTO_MAP_STYLES,
4
+ applyLayerGroupFilters,
5
+ fetchStyle,
6
+ getStyleUrl,
7
+ someLayerGroupsDisabled,
8
+ } from './basemap-styles.js';
9
+ import {Basemap, KeplerMapConfig, MapLibreBasemapProps} from './types.js';
10
+ import {APIErrorContext} from '../api/index.js';
11
+
12
+ const CUSTOM_STYLE_ID_PREFIX = 'custom:';
13
+ const DEFAULT_CARTO_STYLE = 'positron';
14
+
15
+ // Subset of type from @deck.gl/core to avoid adding dependency
16
+ type MapViewState = {
17
+ /** Longitude of the map center */
18
+ longitude: number;
19
+ /** Latitude of the map center */
20
+ latitude: number;
21
+ /** Zoom level */
22
+ zoom: number;
23
+ /** Pitch (tilt) of the map, in degrees. `0` looks top down */
24
+ pitch?: number;
25
+ /** Bearing (rotation) of the map, in degrees. `0` is north up */
26
+ bearing?: number;
27
+ };
28
+
29
+ function mapLibreViewpros(
30
+ config: KeplerMapConfig
31
+ ): Omit<MapLibreBasemapProps, 'style'> {
32
+ const {longitude, latitude, ...rest} = config.mapState as MapViewState;
33
+ return {
34
+ center: [longitude, latitude],
35
+ ...rest,
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Get basemap properties for Carto map.
41
+ *
42
+ * For maplibre-based basemaps it returns style or style URL that can be used with `maplibregl.Map` compatible component.
43
+ * * style url is returned for non-filtered standard Carto basemaps or if user used style URL directly in configuration
44
+ * * filtered style object returned for Carto basemaps with layer groups filtered
45
+ *
46
+ * For Google-maps base maps, it returns options that can be used with `google.maps.Map` constructor.
47
+ */
48
+ export async function fetchBasemapProps({
49
+ config,
50
+ errorContext,
51
+
52
+ applyLayerFilters = true,
53
+ }: {
54
+ config: KeplerMapConfig;
55
+
56
+ /** By default `fetchBasemapProps` applies layers filters to style. Set this to `false` to disable it. */
57
+ applyLayerFilters?: boolean;
58
+ errorContext?: APIErrorContext;
59
+ }): Promise<Basemap | null> {
60
+ const {mapStyle} = config;
61
+ const styleType = mapStyle.styleType || DEFAULT_CARTO_STYLE;
62
+ if (styleType.startsWith(CUSTOM_STYLE_ID_PREFIX)) {
63
+ const currentCustomStyle = config.customBaseMaps?.customStyle;
64
+ if (currentCustomStyle) {
65
+ return {
66
+ type: 'maplibre',
67
+ props: {
68
+ style: currentCustomStyle.style || currentCustomStyle.url,
69
+ ...mapLibreViewpros(config),
70
+ },
71
+ attribution: currentCustomStyle.customAttribution,
72
+ };
73
+ }
74
+ }
75
+
76
+ if (CARTO_MAP_STYLES.includes(styleType)) {
77
+ const {visibleLayerGroups} = mapStyle;
78
+ const styleUrl = getStyleUrl(styleType);
79
+ let style = styleUrl;
80
+ let rawStyle = styleUrl;
81
+ if (
82
+ applyLayerFilters &&
83
+ visibleLayerGroups &&
84
+ someLayerGroupsDisabled(visibleLayerGroups)
85
+ ) {
86
+ rawStyle = await fetchStyle({styleUrl, errorContext});
87
+ style = applyLayerGroupFilters(rawStyle, visibleLayerGroups);
88
+ }
89
+ return {
90
+ type: 'maplibre',
91
+ props: {
92
+ style,
93
+ ...mapLibreViewpros(config),
94
+ },
95
+ visibleLayerGroups,
96
+ rawStyle,
97
+ };
98
+ }
99
+ const googleBasemapDef = GOOGLE_BASEMAPS[styleType];
100
+ if (googleBasemapDef) {
101
+ const {mapState} = config;
102
+ return {
103
+ type: 'google-maps',
104
+ props: {
105
+ ...googleBasemapDef,
106
+ center: {lat: mapState.latitude, lng: mapState.longitude},
107
+ zoom: mapState.zoom + 1,
108
+ tilt: mapState.pitch,
109
+ heading: mapState.bearing,
110
+ },
111
+ };
112
+ }
113
+ return {
114
+ type: 'maplibre',
115
+ props: {
116
+ style: getStyleUrl(DEFAULT_CARTO_STYLE),
117
+ ...mapLibreViewpros(config),
118
+ },
119
+ };
120
+ }
@@ -0,0 +1,331 @@
1
+ import {TilejsonResult} from '../sources/index.js';
2
+
3
+ import {DEFAULT_API_BASE_URL} from '../constants.js';
4
+
5
+ import {
6
+ APIErrorContext,
7
+ CartoAPIError,
8
+ buildPublicMapUrl,
9
+ buildStatsUrl,
10
+ requestWithParameters,
11
+ } from '../api/index.js';
12
+
13
+ import {ParseMapResult, parseMap} from './parse-map.js';
14
+ import {assert} from '../utils.js';
15
+ import type {Basemap, Dataset, KeplerMapConfig} from './types.js';
16
+ import {fetchBasemapProps} from './basemap.js';
17
+ import {configureSource} from './source.js';
18
+ import {Filters} from '../types.js';
19
+ import {isRemoteCalculationSupported} from './utils.js';
20
+
21
+ /* global clearInterval, setInterval, URL */
22
+ async function _fetchMapDataset(
23
+ dataset: Dataset,
24
+ filters: Filters,
25
+ context: _FetchMapContext
26
+ ) {
27
+ const {connectionName} = dataset;
28
+ const cache: {value?: number} = {};
29
+ const configuredSource = configureSource({
30
+ dataset,
31
+ filters: isRemoteCalculationSupported(dataset) ? filters : undefined,
32
+ options: {
33
+ ...context,
34
+ connection: connectionName,
35
+ headers: context.headers,
36
+ accessToken: context.accessToken!,
37
+ apiBaseUrl: context.apiBaseUrl,
38
+ maxLengthURL: context.maxLengthURL,
39
+ },
40
+ });
41
+ dataset.data = await configuredSource;
42
+
43
+ let cacheChanged = true;
44
+ if (cache.value) {
45
+ cacheChanged = dataset.cache !== cache.value;
46
+ dataset.cache = cache.value;
47
+ }
48
+
49
+ return cacheChanged;
50
+ }
51
+
52
+ async function _fetchTilestats(
53
+ attribute: string,
54
+ dataset: Dataset,
55
+ context: _FetchMapContext
56
+ ) {
57
+ const {connectionName, data, id, source, type, queryParameters} = dataset;
58
+ const {apiBaseUrl} = context;
59
+ const errorContext: APIErrorContext = {
60
+ requestType: 'Tile stats',
61
+ connection: connectionName,
62
+ type,
63
+ source,
64
+ };
65
+ if (!('tilestats' in data)) {
66
+ throw new CartoAPIError(
67
+ new Error(`Invalid dataset for tilestats: ${id}`),
68
+ errorContext
69
+ );
70
+ }
71
+
72
+ const baseUrl = buildStatsUrl({attribute, apiBaseUrl, ...dataset});
73
+ const client = new URLSearchParams(data.tiles[0]).get('client');
74
+ const headers = {Authorization: `Bearer ${context.accessToken}`};
75
+ const parameters: Record<string, string> = {};
76
+ if (client) {
77
+ parameters.client = client;
78
+ }
79
+ if (type === 'query') {
80
+ parameters.q = source;
81
+ if (queryParameters) {
82
+ parameters.queryParameters = JSON.stringify(queryParameters);
83
+ }
84
+ }
85
+ const stats = await requestWithParameters({
86
+ baseUrl,
87
+ headers,
88
+ parameters,
89
+ errorContext,
90
+ maxLengthURL: context.maxLengthURL,
91
+ });
92
+
93
+ // Replace tilestats for attribute with value from API
94
+ const {attributes} = data.tilestats.layers[0];
95
+ const index = attributes.findIndex((d) => d.attribute === attribute);
96
+ attributes[index] = stats;
97
+ return true;
98
+ }
99
+
100
+ async function fillInMapDatasets(
101
+ {datasets, keplerMapConfig}: {datasets: Dataset[]; keplerMapConfig: any},
102
+ context: _FetchMapContext
103
+ ) {
104
+ const {filters} = keplerMapConfig.config as KeplerMapConfig;
105
+ const promises = datasets.map((dataset) =>
106
+ _fetchMapDataset(dataset, filters[dataset.id], context)
107
+ );
108
+ return await Promise.all(promises);
109
+ }
110
+
111
+ async function fillInTileStats(
112
+ {datasets, keplerMapConfig}: {datasets: Dataset[]; keplerMapConfig: any},
113
+ context: _FetchMapContext
114
+ ) {
115
+ const attributes: {attribute: string; dataset: any}[] = [];
116
+ const {layers} = keplerMapConfig.config.visState;
117
+ for (const layer of layers) {
118
+ for (const channel of Object.keys(layer.visualChannels)) {
119
+ const attribute = layer.visualChannels[channel]?.name;
120
+ if (attribute) {
121
+ const dataset = datasets.find((d) => d.id === layer.config.dataId);
122
+ if (
123
+ dataset &&
124
+ dataset.type !== 'tileset' &&
125
+ (dataset.data as TilejsonResult).tilestats
126
+ ) {
127
+ // Only fetch stats for QUERY & TABLE map types
128
+ attributes.push({attribute, dataset});
129
+ }
130
+ }
131
+ }
132
+ }
133
+ // Remove duplicates to avoid repeated requests
134
+ const filteredAttributes: {attribute: string; dataset: any}[] = [];
135
+ for (const a of attributes) {
136
+ if (
137
+ !filteredAttributes.find(
138
+ ({attribute, dataset}) =>
139
+ attribute === a.attribute && dataset === a.dataset
140
+ )
141
+ ) {
142
+ filteredAttributes.push(a);
143
+ }
144
+ }
145
+
146
+ const promises = filteredAttributes.map(({attribute, dataset}) =>
147
+ _fetchTilestats(attribute, dataset, context)
148
+ );
149
+ return await Promise.all(promises);
150
+ }
151
+
152
+ export type FetchMapOptions = {
153
+ /**
154
+ * CARTO platform access token. Only required for private maps.
155
+ */
156
+ accessToken?: string;
157
+
158
+ /**
159
+ * Base URL of the CARTO Maps API.
160
+ *
161
+ * Example for account located in EU-west region: `https://gcp-eu-west1.api.carto.com`
162
+ *
163
+ * @default https://gcp-us-east1.api.carto.com
164
+ */
165
+ apiBaseUrl?: string;
166
+
167
+ /**
168
+ * Identifier of map created in CARTO Builder.
169
+ */
170
+ cartoMapId: string;
171
+ clientId?: string;
172
+
173
+ /**
174
+ * Custom HTTP headers added to map instantiation and data requests.
175
+ */
176
+ headers?: Record<string, string>;
177
+
178
+ /**
179
+ * Interval in seconds at which to autoRefresh the data. If provided, `onNewData` must also be provided.
180
+ */
181
+ autoRefresh?: number;
182
+
183
+ /**
184
+ * Callback function that will be invoked whenever data in layers is changed. If provided, `autoRefresh` must also be provided.
185
+ */
186
+ onNewData?: (map: any) => void;
187
+
188
+ /**
189
+ * Maximum URL character length. Above this limit, requests use POST.
190
+ * Used to avoid browser and CDN limits.
191
+ * @default {@link DEFAULT_MAX_LENGTH_URL}
192
+ */
193
+ maxLengthURL?: number;
194
+ };
195
+
196
+ /**
197
+ * Context reused while fetching and updating a map with fetchMap().
198
+ */
199
+ type _FetchMapContext = {apiBaseUrl: string} & Pick<
200
+ FetchMapOptions,
201
+ 'accessToken' | 'clientId' | 'headers' | 'maxLengthURL'
202
+ >;
203
+
204
+ export type FetchMapResult = ParseMapResult & {
205
+ /**
206
+ * Basemap properties.
207
+ */
208
+ basemap: Basemap | null;
209
+ stopAutoRefresh?: () => void;
210
+ };
211
+
212
+ export async function fetchMap({
213
+ accessToken,
214
+ apiBaseUrl = DEFAULT_API_BASE_URL,
215
+ cartoMapId,
216
+ clientId,
217
+ headers,
218
+ autoRefresh,
219
+ onNewData,
220
+ maxLengthURL,
221
+ }: FetchMapOptions): Promise<FetchMapResult> {
222
+ assert(
223
+ cartoMapId,
224
+ 'Must define CARTO map id: fetchMap({cartoMapId: "XXXX-XXXX-XXXX"})'
225
+ );
226
+
227
+ if (accessToken) {
228
+ headers = {Authorization: `Bearer ${accessToken}`, ...headers};
229
+ }
230
+
231
+ if (autoRefresh || onNewData) {
232
+ assert(onNewData, 'Must define `onNewData` when using autoRefresh');
233
+ assert(typeof onNewData === 'function', '`onNewData` must be a function');
234
+ assert(
235
+ typeof autoRefresh === 'number' && autoRefresh > 0,
236
+ '`autoRefresh` must be a positive number'
237
+ );
238
+ }
239
+
240
+ const baseUrl = buildPublicMapUrl({apiBaseUrl, cartoMapId});
241
+ const errorContext: APIErrorContext = {
242
+ requestType: 'Public map',
243
+ mapId: cartoMapId,
244
+ };
245
+ const map = await requestWithParameters({
246
+ baseUrl,
247
+ headers,
248
+ errorContext,
249
+ maxLengthURL,
250
+ });
251
+ const context: _FetchMapContext = {
252
+ accessToken: map.token || accessToken,
253
+ apiBaseUrl,
254
+ clientId,
255
+ headers,
256
+ maxLengthURL,
257
+ };
258
+
259
+ // Periodically check if the data has changed. Note that this
260
+ // will not update when a map is published.
261
+ let stopAutoRefresh: (() => void) | undefined;
262
+ if (autoRefresh) {
263
+ const intervalId = setInterval(async () => {
264
+ const changed = await fillInMapDatasets(map, {
265
+ ...context,
266
+ headers: {
267
+ ...headers,
268
+ 'If-Modified-Since': new Date().toUTCString(),
269
+ },
270
+ });
271
+ if (onNewData && changed.some((v) => v === true)) {
272
+ onNewData(parseMap(map));
273
+ }
274
+ }, autoRefresh * 1000);
275
+ stopAutoRefresh = () => {
276
+ clearInterval(intervalId);
277
+ };
278
+ }
279
+
280
+ const geojsonLayers = map.keplerMapConfig.config.visState.layers.filter(
281
+ ({type}: {type: string}) => type === 'geojson' || type === 'point'
282
+ );
283
+ const geojsonDatasetIds = geojsonLayers.map(
284
+ ({config}: {config: any}) => config.dataId
285
+ );
286
+ map.datasets.forEach((dataset: any) => {
287
+ if (geojsonDatasetIds.includes(dataset.id)) {
288
+ const {config} = geojsonLayers.find(
289
+ ({config}: {config: any}) => config.dataId === dataset.id
290
+ );
291
+ dataset.format = 'geojson';
292
+ // Support for very old maps. geoColumn was not stored in the past
293
+ if (!dataset.geoColumn && config.columns.geojson) {
294
+ dataset.geoColumn = config.columns.geojson;
295
+ }
296
+ }
297
+ });
298
+
299
+ const [basemap] = await Promise.all([
300
+ fetchBasemapProps({config: map.keplerMapConfig.config, errorContext}),
301
+
302
+ // Mutates map.datasets so that dataset.data contains data
303
+ fillInMapDatasets(map, context),
304
+ ]);
305
+
306
+ // Mutates attributes in visualChannels to contain tile stats
307
+ await fillInTileStats(map, context);
308
+
309
+ const out = {...parseMap(map), basemap, ...{stopAutoRefresh}};
310
+
311
+ const textLayers = out.layers.filter((layer: any) => {
312
+ const pointType = layer.props?.pointType || '';
313
+ return pointType.includes('text');
314
+ });
315
+
316
+ /* global FontFace, window, document */
317
+ if (
318
+ textLayers.length &&
319
+ window.FontFace &&
320
+ !document.fonts.check('12px Inter')
321
+ ) {
322
+ // Fetch font needed for labels
323
+ const font = new FontFace(
324
+ 'Inter',
325
+ 'url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2)'
326
+ );
327
+ await font.load().then((f) => document.fonts.add(f));
328
+ }
329
+
330
+ return out as FetchMapResult;
331
+ }
@@ -0,0 +1,13 @@
1
+ export {default as BASEMAP} from './basemap-styles.js';
2
+ export {fetchMap} from './fetch-map.js';
3
+ export type {FetchMapOptions, FetchMapResult} from './fetch-map.js';
4
+ export type {
5
+ Basemap,
6
+ MapLibreBasemap,
7
+ GoogleBasemap,
8
+ KeplerMapConfig,
9
+ } from './types.js';
10
+
11
+ export * from './basemap.js';
12
+ export * from './layer-map.js';
13
+ export * from './parse-map.js';