UNPKG

@maptiler/client

Version:

Javascript & Typescript wrapper to MapTiler Cloud API

1 lines 204 kB
{"version":3,"file":"maptiler-client.cjs","sources":["../src/config.ts","../src/language.ts","../src/callFetch.ts","../src/defaults.ts","../src/services/ServiceError.ts","../src/services/geocoding.ts","../src/services/geolocation.ts","../src/services/coordinates.ts","../src/services/data.ts","../src/mapstyle.ts","../src/misc.ts","../src/services/staticMaps.ts","../src/services/math.ts","../node_modules/quick-lru/index.js","../src/tiledecoding.ts","../src/services/elevation.ts"],"sourcesContent":["import { BufferToPixelDataFunction } from \"./tiledecoding\";\n\nexport type FetchFunction = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nfunction tryGettingFetch() {\n // this is browser, fetch exists\n if (typeof self !== \"undefined\") {\n return fetch.bind(self);\n }\n\n if (typeof global !== \"undefined\" && global.fetch) {\n return global.fetch;\n }\n\n return null;\n}\n\n/**\n * The configuration object definition\n */\nclass ClientConfig {\n /**\n * MapTiler Cloud API key\n */\n private _apiKey = \"\";\n\n /**\n * The fetch function. To be set if in Node < 18, otherwise\n * will be automatically resolved.\n */\n private _fetch: FetchFunction | null = tryGettingFetch();\n\n /**\n * Number of tiles to keep in cache\n */\n public tileCacheSize: number = 200;\n\n public bufferToPixelData?: BufferToPixelDataFunction | null;\n\n /**\n * Set the MapTiler Cloud API key\n */\n set apiKey(k: string) {\n this._apiKey = k;\n }\n\n /**\n * Get the MapTiler Cloud API key\n */\n get apiKey(): string {\n return this._apiKey;\n }\n\n /**\n * Set a the custom fetch function to replace the default one\n */\n set fetch(f: FetchFunction) {\n this._fetch = f;\n }\n\n /**\n * Get the fetch fucntion\n */\n get fetch(): FetchFunction | null {\n return this._fetch;\n }\n}\n\n/**\n * Configuration object\n */\nconst config = new ClientConfig();\n\nexport { ClientConfig, config };\n","export type LanguageInfo = {\n /**\n * Two-letter ISO code, such as `\"en\"` for English language.\n * Can be `null` if the language is a flag to be evaluated at runtime,\n * as it is the case for some \"modes\".\n */\n code: string | null;\n\n /**\n * The full OSM language flag, such as `\"name:en\"` for the English language.\n * Can also be a non-OSM flag if the language needs to be evaluated at runtime, such as `\"auto\"`,\n * as it is the case for some \"modes\".\n */\n flag: string;\n\n /**\n * English name of the language.\n */\n name: string;\n\n /**\n * Whether the language leverages only the latin charsets.\n */\n latin: boolean;\n\n /**\n * Some language descriptions corresponds to \"modes\" rather than to actual languages.\n * For instance the \"visitor\" mode consists in displaying bilingual labels.\n */\n isMode: boolean;\n\n /**\n * Whether the language is compatible with the geocoding API\n */\n geocoding: boolean;\n};\n\n/**\n * List of \"non-ISO specific\" languages.\n */\nexport const NonISOLanguage = {\n /**\n * Language mode to display the labels in the end user's device language.\n */\n AUTO: {\n code: null,\n flag: \"auto\",\n name: \"Auto\",\n latin: false,\n isMode: true,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * The OSM language using latin script. MapTiler discourages its use as a primary language setting due to the lack of actual linguistic specificity,\n * though it can be an handy fallback. This is not to be confused with the \"Classical Latin\" language, which is available under the tag `.CLASSICAL_LATIN`.\n */\n LATIN: {\n code: \"latin\",\n flag: \"name:latin\",\n name: \"Latin\",\n latin: true,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * The OSM language using non-latin script. MapTiler discourages its use as a primary language setting due to the lack of actual linguistic specificity,\n * though it can be an handy fallback.\n */\n NON_LATIN: {\n code: \"nonlatin\",\n flag: \"name:nonlatin\",\n name: \"Non Latin\",\n latin: false,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Using the local language generaly (but not always) means that every labels of a given region will use the dominant local language.\n */\n LOCAL: {\n code: null,\n flag: \"name\",\n name: \"Local\",\n latin: true,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n} as const;\n\n/**\n * List of \"country specific\" languages.\n */\nexport const ISOLanguage = {\n /**\n * Albanian language\n */\n ALBANIAN: {\n code: \"sq\",\n flag: \"name:sq\",\n name: \"Albanian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Amharic language\n */\n AMHARIC: {\n code: \"am\",\n flag: \"name:am\",\n name: \"Amharic\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Arabic language (right-to-left script)\n */\n ARABIC: {\n code: \"ar\",\n flag: \"name:ar\",\n name: \"Arabic\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Armenian language\n */\n ARMENIAN: {\n code: \"hy\",\n flag: \"name:hy\",\n name: \"Armenian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Azerbaijani language\n */\n AZERBAIJANI: {\n code: \"az\",\n flag: \"name:az\",\n name: \"Azerbaijani\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Basque language\n */\n BASQUE: {\n code: \"eu\",\n flag: \"name:eu\",\n name: \"Basque\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Belarusian langauge\n */\n BELARUSIAN: {\n code: \"be\",\n flag: \"name:be\",\n name: \"Belarusian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Bengali language\n */\n BENGALI: {\n code: \"bn\",\n flag: \"name:bn\",\n name: \"Bengali\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Bosnian language\n */\n BOSNIAN: {\n code: \"bs\",\n flag: \"name:bs\",\n name: \"Bosnian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Breton language\n */\n BRETON: {\n code: \"br\",\n flag: \"name:br\",\n name: \"Breton\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Bulgarian language\n */\n BULGARIAN: {\n code: \"bg\",\n flag: \"bg\",\n name: \"Bulgarian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Catalan language\n */\n CATALAN: {\n code: \"ca\",\n flag: \"name:ca\",\n name: \"Catalan\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Chinese language\n */\n CHINESE: {\n code: \"zh\",\n flag: \"name:zh\",\n name: \"Chinese\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Traditional Chinese language\n */\n TRADITIONAL_CHINESE: {\n code: \"zh-Hant\",\n flag: \"name:zh-Hant\",\n name: \"Chinese (traditional)\",\n latin: false,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Simplified Chinese language\n */\n SIMPLIFIED_CHINESE: {\n code: \"zh-Hans\",\n flag: \"name:zh-Hans\",\n name: \"Chinese (simplified)\",\n latin: false,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Corsican language\n */\n CORSICAN: {\n code: \"co\",\n flag: \"name:co\",\n name: \"Corsican\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Croatian language\n */\n CROATIAN: {\n code: \"hr\",\n flag: \"name:hr\",\n name: \"Croatian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Czech language\n */\n CZECH: {\n code: \"cs\",\n flag: \"name:cs\",\n name: \"Czech\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Danish language\n */\n DANISH: {\n code: \"da\",\n flag: \"name:da\",\n name: \"Danish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Dutch language\n */\n DUTCH: {\n code: \"nl\",\n flag: \"name:nl\",\n name: \"Dutch\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * German language\n */\n GERMAN: {\n code: \"de\",\n flag: \"name:de\",\n name: \"German\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Greek language\n */\n GREEK: {\n code: \"el\",\n flag: \"name:el\",\n name: \"Greek\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * English language\n */\n ENGLISH: {\n code: \"en\",\n flag: \"name:en\",\n name: \"English\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Esperanto language\n */\n ESPERANTO: {\n code: \"eo\",\n flag: \"name:eo\",\n name: \"Esperanto\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Estonian language\n */\n ESTONIAN: {\n code: \"et\",\n flag: \"name:et\",\n name: \"Estonian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Finnish language\n */\n FINNISH: {\n code: \"fi\",\n flag: \"name:fi\",\n name: \"Finnish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * French language\n */\n FRENCH: {\n code: \"fr\",\n flag: \"name:fr\",\n name: \"French\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Frisian language\n */\n FRISIAN: {\n code: \"fy\",\n flag: \"name:fy\",\n name: \"Frisian (West)\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Georgian language\n */\n GEORGIAN: {\n code: \"ka\",\n flag: \"name:ka\",\n name: \"Georgian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Hebrew language (right-to-left non-latin script)\n */\n HEBREW: {\n code: \"he\",\n flag: \"name:he\",\n name: \"Hebrew\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Hindi language\n */\n HINDI: {\n code: \"hi\",\n flag: \"name:hi\",\n name: \"Hindi\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Hungarian language\n */\n HUNGARIAN: {\n code: \"hu\",\n flag: \"name:hu\",\n name: \"Hungarian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Icelandic language\n */\n ICELANDIC: {\n code: \"is\",\n flag: \"name:is\",\n name: \"Icelandic\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Indonesian language\n */\n INDONESIAN: {\n code: \"id\",\n flag: \"name:id\",\n name: \"Indonesian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Irish language\n */\n IRISH: {\n code: \"ga\",\n flag: \"name:ga\",\n name: \"Irish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Italian language\n */\n ITALIAN: {\n code: \"it\",\n flag: \"name:it\",\n name: \"Italian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Japanese language\n */\n JAPANESE: {\n code: \"ja\",\n flag: \"name:ja\",\n name: \"Japanese\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Japanese language in Hiragana form\n */\n JAPANESE_HIRAGANA: {\n code: \"ja-Hira\",\n flag: \"name:ja-Hira\",\n name: \"Japanese Hiragana form\",\n latin: false,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Japanese language (latin script)\n */\n JAPANESE_2018: {\n code: \"ja-Latn\",\n flag: \"name:ja-Latn\",\n name: \"Japanese (Latin 2018)\",\n latin: true,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Japanese language in Kana form (non-latin script)\n */\n JAPANESE_KANA: {\n code: \"ja_kana\",\n flag: \"name:ja_kana\",\n name: \"Japanese (Kana)\",\n latin: false,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Japanse language, romanized (latin script)\n */\n JAPANESE_LATIN: {\n code: \"ja_rm\",\n flag: \"name:ja_rm\",\n name: \"Japanese (Latin script)\",\n latin: true,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Kannada language\n */\n KANNADA: {\n code: \"kn\",\n flag: \"name:kn\",\n name: \"Kannada\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Kazakh language\n */\n KAZAKH: {\n code: \"kk\",\n flag: \"name:kk\",\n name: \"Kazakh\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Korean language\n */\n KOREAN: {\n code: \"ko\",\n flag: \"name:ko\",\n name: \"Korean\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Korean language (latin script)\n */\n KOREAN_LATIN: {\n code: \"ko-Latn\",\n flag: \"name:ko-Latn\",\n name: \"Korean (Latin script)\",\n latin: true,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Kurdish language\n */\n KURDISH: {\n code: \"ku\",\n flag: \"name:ku\",\n name: \"Kurdish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Classical Latin language\n */\n CLASSICAL_LATIN: {\n code: \"la\",\n flag: \"name:la\",\n name: \"Latin\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Latvian language\n */\n LATVIAN: {\n code: \"lv\",\n flag: \"name:lv\",\n name: \"Latvian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Lithuanian language\n */\n LITHUANIAN: {\n code: \"lt\",\n flag: \"name:lt\",\n name: \"Lithuanian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Luxembourgish language\n */\n LUXEMBOURGISH: {\n code: \"lb\",\n flag: \"name:lb\",\n name: \"Luxembourgish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Macedonian language\n */\n MACEDONIAN: {\n code: \"mk\",\n flag: \"name:mk\",\n name: \"Macedonian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Malayalm language\n */\n MALAYALAM: {\n code: \"ml\",\n flag: \"name:ml\",\n name: \"Malayalam\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Maltese language\n */\n MALTESE: {\n code: \"mt\",\n flag: \"name:mt\",\n name: \"Maltese\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Norwegian language\n */\n NORWEGIAN: {\n code: \"no\",\n flag: \"name:no\",\n name: \"Norwegian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Occitan language\n */\n OCCITAN: {\n code: \"oc\",\n flag: \"name:oc\",\n name: \"Occitan\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Persian language\n */\n PERSIAN: {\n code: \"fa\",\n flag: \"name:fa\",\n name: \"Persian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Polish language\n */\n POLISH: {\n code: \"pl\",\n flag: \"name:pl\",\n name: \"Polish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Portuguese language\n */\n PORTUGUESE: {\n code: \"pt\",\n flag: \"name:pt\",\n name: \"Portuguese\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Punjabi language\n */\n PUNJABI: {\n code: \"pa\",\n flag: \"name:pa\",\n name: \"Punjabi\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Western Punjabi language\n */\n WESTERN_PUNJABI: {\n code: \"pnb\",\n flag: \"name:pnb\",\n name: \"Western Punjabi\",\n latin: false,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Romanian language\n */\n ROMANIAN: {\n code: \"ro\",\n flag: \"name:ro\",\n name: \"Romanian\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Romansh language\n */\n ROMANSH: {\n code: \"rm\",\n flag: \"name:rm\",\n name: \"Romansh\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Russian language\n */\n RUSSIAN: {\n code: \"ru\",\n flag: \"name:ru\",\n name: \"Russian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Serbian language (cyrillic script)\n */\n SERBIAN_CYRILLIC: {\n code: \"sr\",\n flag: \"name:sr\",\n name: \"Serbian (Cyrillic script)\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Serbian language (latin script)\n */\n SERBIAN_LATIN: {\n code: \"sr-Latn\",\n flag: \"name:sr-Latn\",\n name: \"Serbian (Latin script)\",\n latin: true,\n isMode: false,\n geocoding: false,\n } as LanguageInfo,\n\n /**\n * Scottish Gaelic language\n */\n SCOTTISH_GAELIC: {\n code: \"gd\",\n flag: \"name:gd\",\n name: \"Scottish Gaelic\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Slovak language\n */\n SLOVAK: {\n code: \"sk\",\n flag: \"name:sk\",\n name: \"Slovak\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Slovene language\n */\n SLOVENE: {\n code: \"sl\",\n flag: \"name:sl\",\n name: \"Slovene\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Spanish language\n */\n SPANISH: {\n code: \"es\",\n flag: \"name:es\",\n name: \"Spanish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Swedish language\n */\n SWEDISH: {\n code: \"sv\",\n flag: \"name:sv\",\n name: \"Swedish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Tamil language\n */\n TAMIL: {\n code: \"ta\",\n flag: \"name:ta\",\n name: \"Tamil\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Telugu language\n */\n TELUGU: {\n code: \"te\",\n flag: \"name:te\",\n name: \"Telugu\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Thai language\n */\n THAI: {\n code: \"th\",\n flag: \"name:th\",\n name: \"Thai\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Turkish language\n */\n TURKISH: {\n code: \"tr\",\n flag: \"name:tr\",\n name: \"Turkish\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Ukrainian language\n */\n UKRAINIAN: {\n code: \"uk\",\n flag: \"name:uk\",\n name: \"Ukrainian\",\n latin: false,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Vietnamese language (latin script)\n */\n VIETNAMESE: {\n code: \"vi\",\n flag: \"name:vi\",\n name: \"Vietnamese (Latin script)\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n\n /**\n * Welsh language\n */\n WELSH: {\n code: \"cy\",\n flag: \"name:cy\",\n name: \"Welsh\",\n latin: true,\n isMode: false,\n geocoding: true,\n } as LanguageInfo,\n} as const;\n\n/**\n * The complete list of languages\n */\nexport const Language = {\n ...NonISOLanguage,\n ...ISOLanguage,\n} as const;\n\n/**\n * Get language infos from a provided language key, the key being the no-whitespace capital name.\n * By default, the language dictionary to look into is the one defined in this library, but another one could be provided\n * Returns `null` if not found.\n */\nexport function getLanguageInfoFromKey(\n languageKey: string,\n languageDictionary: { [k: string]: LanguageInfo } = Language,\n): LanguageInfo | null {\n if (languageKey in languageDictionary) {\n return languageKey[languageKey];\n }\n return null;\n}\n\n/**\n * Get the language info from a provided 2-character iso code.\n * By default, the language dictionary to look into is the one defined in this library, but another one could be provided\n * Returns `null` if not found.\n */\nexport function getLanguageInfoFromCode(\n languageCode: string,\n languageDictionary: { [k: string]: LanguageInfo } = Language,\n): LanguageInfo | null {\n for (const lang of Object.values(languageDictionary)) {\n if (lang.code === languageCode) {\n return lang;\n }\n }\n return null;\n}\n\n/**\n * Get the language info from a language flag (e.g. `\"name:en\"`).\n * This is also handy to check is a given language flag is a supported language.\n * By default, the language dictionary to look into is the one defined in this library, but another one could be provided\n * Returns `null` if not found.\n */\nexport function getLanguageInfoFromFlag(\n languageFlag: string,\n languageDictionary: { [k: string]: LanguageInfo } = Language,\n): LanguageInfo | null {\n for (const lang of Object.values(languageDictionary)) {\n if (lang.flag === languageFlag) {\n return lang;\n }\n }\n return null;\n}\n\n/**\n * Get the default language of the device, as a LanguageInfo object.\n */\nexport function getAutoLanguage(): LanguageInfo {\n if (typeof navigator === \"undefined\") {\n const code = Intl.DateTimeFormat().resolvedOptions().locale.split(\"-\")[0];\n const langInfo = getLanguageInfoFromCode(code);\n return langInfo ?? Language.ENGLISH;\n }\n\n const canditatelangs = Array.from(\n new Set(navigator.languages.map((l) => l.split(\"-\")[0])),\n )\n .map((code) => getLanguageInfoFromCode(code))\n .filter((li) => li);\n\n return canditatelangs[0] ?? Language.ENGLISH;\n}\n\nexport function isLanguageInfo(obj: unknown): obj is LanguageInfo {\n return (\n obj !== null &&\n typeof obj === \"object\" &&\n \"code\" in obj &&\n \"flag\" in obj &&\n \"name\" in obj &&\n \"latin\" in obj &&\n \"isMode\" in obj &&\n \"geocoding\" in obj &&\n (typeof obj.code === \"string\" || obj.code === null) &&\n typeof obj.flag === \"string\" &&\n typeof obj.name === \"string\" &&\n typeof obj.latin === \"boolean\" &&\n typeof obj.isMode === \"boolean\" &&\n typeof obj.geocoding === \"boolean\"\n );\n}\n\n/**\n * By default, the language dictionary to look into is the one defined in this library, but another one could be provided\n */\nexport function toLanguageInfo(\n lang: LanguageInfo | string,\n languageDictionary: { [k: string]: LanguageInfo } = Language,\n): LanguageInfo | null {\n // Could be directly an object of type LanguageInfo\n if (isLanguageInfo(lang)) {\n // Yet we want to make sure the provided languageInfo obj is not corrupted or incomplete,\n // so we ask for the equivalent original:\n return getLanguageInfoFromFlag(lang.flag, languageDictionary); // possibly returns null, which is fine.\n }\n\n // If it's not even a string, then it does not represent a language\n if (typeof lang !== \"string\") {\n return null;\n }\n\n return (\n getLanguageInfoFromKey(lang, languageDictionary) ||\n getLanguageInfoFromCode(lang, languageDictionary) ||\n getLanguageInfoFromFlag(lang, languageDictionary) ||\n null\n );\n}\n\n/**\n * Tells if two languages are the same, even though possibly provided under different forms.\n * Note: this is not comparing object references, but values.\n */\nexport function areSameLanguages(\n langA: string | LanguageInfo,\n langB: string | LanguageInfo,\n languageDictionary: { [k: string]: LanguageInfo } = Language,\n): boolean {\n const langAObj = toLanguageInfo(langA, languageDictionary);\n const langBObj = toLanguageInfo(langB, languageDictionary);\n\n return langAObj && langBObj && langAObj.flag === langBObj.flag;\n}\n","import { config } from \"./config\";\n\nexport async function callFetch(resource, options = {}) {\n if (config.fetch === null) {\n throw new Error(\n \"The fetch function was not found. If on NodeJS < 18 please specify the fetch function with config.fetch\",\n );\n }\n\n // Control if URL contains the api key\n if (new URL(resource).searchParams.get(\"key\").trim() === \"\") {\n throw new Error(\n \"The MapTiler Cloud API key is missing. Set it in `config.apiKey` or get one for free at https://maptiler.com\",\n );\n }\n\n return config.fetch(resource, options);\n}\n","/**\n * Some default settings for the SDK\n */\nconst defaults = {\n maptilerApiURL: \"https://api.maptiler.com/\",\n mapStyle: \"streets-v2\",\n};\n\nObject.freeze(defaults);\n\nexport { defaults };\n","/**\n * A ServiceError is an Error that includes the HTTP response details\n */\nexport class ServiceError extends Error {\n constructor(\n public res: Response,\n customMessage = \"\",\n ) {\n super(\n `Call to enpoint ${res.url} failed with the status code ${res.status}. ${customMessage}`,\n );\n }\n}\n","import type { BBox, Feature, Geometry, Position } from \"geojson\";\nimport { callFetch } from \"../callFetch\";\nimport { config } from \"../config\";\nimport { defaults } from \"../defaults\";\n\nimport {\n type LanguageInfo,\n getAutoLanguage,\n getLanguageInfoFromCode,\n isLanguageInfo,\n Language,\n getLanguageInfoFromFlag,\n} from \"../language\";\n\nimport { ServiceError } from \"./ServiceError\";\n\nconst customMessages = {\n 400: \"Query too long / Invalid parameters\",\n 403: \"Key is missing, invalid or restricted\",\n};\n\nexport type LanguageGeocodingOptions = {\n /**\n * Prefer results in specific language. It’s possible to specify multiple values.\n */\n language?: string | Array<string> | LanguageInfo | Array<LanguageInfo>;\n};\n\nexport type GeocodingPlaceType =\n | \"continental_marine\"\n | \"country\"\n | \"major_landform\"\n | \"region\"\n | \"subregion\"\n | \"county\"\n | \"joint_municipality\"\n | \"joint_submunicipality\"\n | \"municipality\"\n | \"municipal_district\"\n | \"locality\"\n | \"neighbourhood\"\n | \"place\"\n | \"postal_code\"\n | \"address\"\n | \"road\"\n | \"poi\";\n\nexport type CommonForwardAndReverseGeocodingOptions =\n LanguageGeocodingOptions & {\n /**\n * Custom MapTiler Cloud API key to use instead of the one in global `config`.\n */\n apiKey?: string;\n\n /**\n * Maximum number of results to show. Must be between 1 and 10.\n * For reverse geocoding with multiple `types` this must not be set or must be set to 1.\n * Default is 5 for forward and 1 for reverse geocoding.\n */\n limit?: number;\n\n /**\n * Features of specified types to query.\n * If not specified, feature of all available types except `poi` and `major_landform` will be queried (`types = [\"poi\", \"major_landform\"]`, `excludeTypes = true`).\n * In case of reverse geocoding if just a single type is specified, then multiple nearby features of the single type can be returned,\n * otherwise single feature for every specified type (or default types) can be returned.\n */\n types?: GeocodingPlaceType[];\n\n /**\n * Set to `true` to use all available feature types except those mentioned in `types`. Default value is `false` if `types` is specified.\n */\n excludeTypes?: boolean;\n };\n\nexport type GeocodingOptions = CommonForwardAndReverseGeocodingOptions & {\n /**\n * Only search for results in the specified area.\n */\n bbox?: BBox;\n\n /**\n * Prefer results close to a specific location.\n */\n proximity?: Position | \"ip\";\n\n /**\n * Limit search to specific country/countries specified as list of Alpha-2 ISO 3166-1 codes.\n */\n country?: string[];\n\n /**\n * Set to `false` to disable fuzzy (typo-tolerant) search. Default is `true`.\n */\n fuzzyMatch?: boolean;\n\n /**\n * Set to `true` to use autocomplete, `false` to disable it. Default is `true`.\n */\n autocomplete?: boolean;\n};\n\nexport type ReverseGeocodingOptions = CommonForwardAndReverseGeocodingOptions;\n\nexport type ByIdGeocodingOptions = LanguageGeocodingOptions & {\n apiKey?: string;\n};\n\nexport type Coordinates = Position;\n\ntype FeatureProperties = {\n /**\n * External reference of the feature used for debugging purposes\n */\n ref: string;\n\n /**\n * ISO 3166-1 alpha-2 country code of the feature\n */\n country_code: string;\n\n /**\n * (experimental) Kind of the feature\n */\n kind?:\n | \"road\"\n | \"road_relation\"\n | \"admin_area\"\n | \"place\"\n | \"street\"\n | \"virtual_street\";\n\n /**\n * (experimental) Value of place=* tag from OpenStreetMap feature if kind=place\n */\n \"osm:place_type\"?: string;\n\n /**\n * (experimental) Feature tags from OpenStreetMap. Only available for `poi` type.\n */\n \"osm:tags\"?: Record<string, string>;\n\n /**\n * Array of POI categories. Only available for `poi` type.\n */\n categories?: string[];\n\n /**\n * Wikidata identifier.\n */\n wikidata?: string;\n};\n\ntype FeatureBase = {\n /**\n * Unique feature ID\n */\n id: string;\n\n /**\n * Localized feature name\n */\n text: string;\n\n /**\n * Query's primary ISO 639-1 language code\n */\n language?: string;\n\n /**\n * A string analogous to the `text` field that matches the query in the requested language.\n * This field is only returned when multiple languages are requested using the `language` parameter, and will be present for each requested language.\n */\n [text: `text_${string}`]: string;\n\n /**\n * A ISO 639-1 query's fallback language code.\n * This field is only returned when multiple languages are requested using the `language` parameter, and will be present for each requested language.\n */\n [language: `language_${string}`]: string;\n};\n\nexport type FeatureHierarchy = FeatureProperties & FeatureBase;\n\nexport type GeocodingFeature = Feature<Geometry, FeatureProperties> &\n FeatureBase & {\n /**\n * Bounding box of the original feature as [w, s, e, n] array\n */\n bbox: BBox;\n\n /**\n * A [lon, lat] array of the original feature centeroid\n */\n center: Coordinates;\n\n /**\n * Formatted (including the hierarchy) and localized feature full name\n */\n place_name: string;\n\n /**\n * A string analogous to the `place_name` field that matches the query in the requested language.\n * This field is only returned when multiple languages are requested using the `language` parameter, and will be present for each requested language.\n */\n [key: `place_name_${string}`]: string;\n\n /**\n * An array of feature types describing the feature.\n * Currently each feature has only single type but this may change in the future.\n */\n place_type: GeocodingPlaceType[];\n\n /**\n * Localized type of the place name, matches `place_type` property\n */\n place_type_name: string[];\n\n /**\n * Feature hierarchy\n */\n context?: Array<FeatureHierarchy>;\n\n /**\n * Address number, if applicable\n */\n address?: string;\n\n /**\n * Indicates how well the returned feature matches the user's query on a scale from 0 to 1.\n * 0 means the result does not match the query text at all, while 1 means the result fully matches the query text.\n * You can use the relevance property to remove results that don't fully match the query.\n */\n relevance: number;\n\n /**\n * A string analogous to the `text` field that more closely matches the query than results in the specified language.\n * For example, querying _Praha, Czechia_ with language set to English (`en`) might return a feature with the `text` _Prague_ and the `matching_text` _Praha_.\n */\n matching_text?: string;\n\n /**\n * A string analogous to the `place_name` field that more closely matches the query than results in the specified language.\n * For example, querying _Praha, Czechia_ with language set to English (`en`) might return a feature with the `place_name` _Prague, Czechia_ and a `matching_place_name` of _Praha, Czechia_.\n */\n matching_place_name?: string;\n };\n\nexport type GeocodingSearchResult = {\n type: \"FeatureCollection\";\n\n /**\n * Array of features found\n */\n features: Array<GeocodingFeature>;\n\n /**\n * Tokenized search query\n */\n query: Array<string>;\n\n /**\n * Attribution of the result\n */\n attribution: string;\n};\n\nfunction addLanguageGeocodingOptions(\n searchParams: URLSearchParams,\n options: LanguageGeocodingOptions,\n) {\n const { language } = options;\n\n if (language === undefined) {\n return;\n }\n\n // Making it an array of language codes\n const languageCodes = (Array.isArray(language) ? language : [language])\n .map((elem) => toValidGeocodingLanguageCode(elem))\n .filter((elem) => elem); // removing the nulls\n\n const languages = Array.from(new Set(languageCodes)).join(\",\");\n\n searchParams.set(\"language\", languages);\n}\n\nfunction toValidGeocodingLanguageCode(\n lang: string | LanguageInfo,\n): string | null {\n const langInfo =\n lang === Language.AUTO.flag\n ? getAutoLanguage()\n : typeof lang === \"string\"\n ? getLanguageInfoFromCode(lang)\n : isLanguageInfo(lang)\n ? lang.flag === Language.AUTO.flag\n ? getAutoLanguage()\n : getLanguageInfoFromFlag(lang.flag)\n : null;\n\n return langInfo?.geocoding ? langInfo.code : null;\n}\n\nfunction addCommonForwardAndReverseGeocodingOptions(\n searchParams: URLSearchParams,\n options: CommonForwardAndReverseGeocodingOptions,\n) {\n const { apiKey, limit, types, excludeTypes } = options;\n\n searchParams.set(\"key\", apiKey ?? config.apiKey);\n\n if (limit !== undefined) {\n searchParams.set(\"limit\", String(limit));\n }\n\n if (types !== undefined) {\n searchParams.set(\"types\", types.join(\",\"));\n }\n\n if (excludeTypes !== undefined) {\n searchParams.set(\"excludeTypes\", String(excludeTypes));\n }\n\n addLanguageGeocodingOptions(searchParams, options);\n}\n\nfunction addForwardGeocodingOptions(\n searchParams: URLSearchParams,\n options: GeocodingOptions,\n) {\n addCommonForwardAndReverseGeocodingOptions(searchParams, options);\n\n const { bbox, proximity, country, fuzzyMatch, autocomplete } = options;\n\n if (bbox !== undefined) {\n searchParams.set(\"bbox\", bbox.join(\",\"));\n }\n\n if (proximity !== undefined) {\n searchParams.set(\n \"proximity\",\n proximity === \"ip\" ? proximity : proximity.join(\",\"),\n );\n }\n\n if (country !== undefined) {\n searchParams.set(\"country\", country.join(\",\"));\n }\n\n if (fuzzyMatch !== undefined) {\n searchParams.set(\"fuzzyMatch\", fuzzyMatch ? \"true\" : \"false\");\n }\n\n if (autocomplete !== undefined) {\n searchParams.set(\"autocomplete\", autocomplete ? \"true\" : \"false\");\n }\n}\n\n/**\n * Performs a forward geocoding query to MapTiler API.\n * Providing a human readable place name (of a city, country, street, etc.), the function returns\n * a list of candidate locations including longitude and latitude.\n *\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/geocoding/#search-by-name-forward\n *\n * @param query\n * @param options\n * @returns\n */\nasync function forward(\n query: string,\n options: GeocodingOptions = {},\n): Promise<GeocodingSearchResult> {\n if (typeof query !== \"string\" || query.trim().length === 0) {\n throw new Error(\"The query must be a non-empty string\");\n }\n\n const endpoint = new URL(\n `geocoding/${encodeURIComponent(query)}.json`,\n defaults.maptilerApiURL,\n );\n\n addForwardGeocodingOptions(endpoint.searchParams, options);\n\n const res = await callFetch(endpoint.toString());\n\n if (!res.ok) {\n throw new ServiceError(res, customMessages[res.status] ?? \"\");\n }\n\n return await res.json();\n}\n\n/**\n * Perform a reverse geocoding query to MapTiler API.\n * Providing a longitude and latitude, this function returns a set of human readable information about this place (country, city, street, etc.)\n *\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/geocoding/#search-by-coordinates-reverse\n *\n * @param position\n * @param options\n * @returns\n */\nasync function reverse(\n position: Position,\n options: ReverseGeocodingOptions = {},\n): Promise<GeocodingSearchResult> {\n if (!Array.isArray(position) || position.length < 2) {\n throw new Error(\"The position must be an array of form [lng, lat].\");\n }\n\n const endpoint = new URL(\n `geocoding/${position[0]},${position[1]}.json`,\n defaults.maptilerApiURL,\n );\n\n addCommonForwardAndReverseGeocodingOptions(endpoint.searchParams, options);\n\n const res = await callFetch(endpoint.toString());\n\n if (!res.ok) {\n throw new ServiceError(res, customMessages[res.status] ?? \"\");\n }\n\n return await res.json();\n}\n\n/**\n * Perform a geocoding query to MapTiler API to obtain fature by its ID.\n * Providing a feature ID, this function returns a feature which includes its full geometry.\n * Note that the feature ID is not stable and it changes when the database is re-indexed.\n *\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/geocoding/#search-by-feature-id\n *\n * @param id\n * @param options\n * @returns\n */\nasync function byId(\n id: string,\n options: ByIdGeocodingOptions = {},\n): Promise<GeocodingSearchResult> {\n const endpoint = new URL(`geocoding/${id}.json`, defaults.maptilerApiURL);\n\n endpoint.searchParams.set(\"key\", options.apiKey ?? config.apiKey);\n\n addLanguageGeocodingOptions(endpoint.searchParams, options);\n\n const res = await callFetch(endpoint.toString());\n\n if (!res.ok) {\n throw new ServiceError(res, customMessages[res.status] ?? \"\");\n }\n\n return await res.json();\n}\n\n/**\n * Perform a batch geocoding query to MapTiler API.\n * Provide multiple queries in the array. Each query can be forward, reverse or by feature ID.\n *\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/geocoding/#batch-geocoding\n *\n * @param queries\n * @param options\n * @returns\n */\nasync function batch(\n queries: string[],\n options: GeocodingOptions = {},\n): Promise<GeocodingSearchResult[]> {\n if (!queries.length) {\n return [];\n }\n\n const joinedQuery = queries\n .map((query) => encodeURIComponent(query))\n .join(\";\");\n\n const endpoint = new URL(\n `geocoding/${joinedQuery}.json`,\n defaults.maptilerApiURL,\n );\n\n addForwardGeocodingOptions(endpoint.searchParams, options);\n\n const res = await callFetch(endpoint.toString());\n\n if (!res.ok) {\n throw new ServiceError(res, customMessages[res.status] ?? \"\");\n }\n\n const obj = await res.json();\n\n return queries.length === 1 ? [obj] : obj;\n}\n\n/**\n * The **geocoding** namespace contains asynchronous functions to call the [MapTiler Geocoding API](https://docs.maptiler.com/cloud/api/geocoding/).\n * The **Geocoding API** provides ways to get geographic coordinates from a human-readable search query of a place (forward geocoding)\n * and to get the location details (country, city, street, etc.) from a geographic coordinate (reverse geocoding);\n */\nconst geocoding = {\n forward,\n reverse,\n byId,\n batch,\n};\n\nexport { geocoding };\n","import { BBox } from \"geojson\";\nimport { callFetch } from \"../callFetch\";\nimport { config } from \"../config\";\nimport { defaults } from \"../defaults\";\nimport { ServiceError } from \"./ServiceError\";\n\nconst customMessages = {\n 403: \"Key is missing, invalid or restricted\",\n};\n\n/**\n * Options that can be provided to get user data.\n */\nexport type GeolocationInfoOptions = {\n /**\n * Custom MapTiler Cloud API key to use instead of the one in global `config`\n */\n apiKey?: string;\n\n /**\n * Include elevation (in meters) in the results.\n * Default: `false`\n */\n elevation?: boolean;\n};\n\nexport type GeolocationResult = {\n /**\n * Name of the country\n * Example: Switzerland\n */\n country?: string;\n\n /**\n * Two-letter code of the country ISO 3166-1 alpha-2 codes\n * Example: CH\n */\n country_code?: string;\n\n /**\n * Bounds of the country in WGS84 degrees [west, south, east, north].\n * Example: [5.95538,45.818852,10.490936,47.809357]\n */\n country_bounds?: BBox;\n\n /**\n * Official country languages in ISO 639-1 format. ISO 639-1 codes\n * Example: [\"de\",\"fr\",\"it\"]\n */\n country_languages?: Array<string>;\n\n /**\n * Name of the continent\n * Example: Europe\n */\n continent?: string;\n\n /**\n * Two-letter code of the continent\n * Example: EU\n */\n continent_code?: string;\n\n /**\n * Indicated whether the country is part of the European Union.\n */\n eu?: boolean;\n\n /**\n * Name of the city\n * Example: Zurich\n */\n city?: string;\n\n /**\n * Latitude of the location\n * Example: 47.36667\n */\n latitude?: number;\n\n /**\n * Longitude of the location\n * Example: 8.55\n */\n longitude?: number;\n\n /**\n * Postal code\n * Example: 8000\n */\n postal?: string;\n\n /**\n * If known, the ISO 3166-2 name for the first level region. ISO 3166-2 codes\n * Example: Zurich\n */\n region?: string;\n\n /**\n * If known, the ISO 3166-2 code for the first level region. ISO 3166-2 codes\n * Example: ZH\n */\n region_code?: string;\n\n /**\n * Name of the timezone\n * Example: Europe/Zurich\n */\n timezone?: string;\n\n /**\n * Elevation of the location in meters\n * Example: 433\n */\n elevation?: number;\n};\n\n/**\n * Looks up geolocation details from IP address using MapTiler API.\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/geolocation/#ip-geolocation\n * @returns\n */\nasync function info(\n options: GeolocationInfoOptions = {},\n): Promise<GeolocationResult> {\n const endpoint = new URL(`geolocation/ip.json`, defaults.maptilerApiURL);\n endpoint.searchParams.set(\"key\", options.apiKey ?? config.apiKey);\n\n if (\"elevation\" in options) {\n endpoint.searchParams.set(\n \"elevation\",\n options.elevation ? \"true\" : \"false\",\n );\n }\n\n const urlWithParams = endpoint.toString();\n\n const res = await callFetch(urlWithParams);\n\n if (!res.ok) {\n throw new ServiceError(\n res,\n res.status in customMessages ? customMessages[res.status] : \"\",\n );\n }\n\n const obj = await res.json();\n return obj as GeolocationResult;\n}\n\n/**\n * The **geolocation** namespace contains an asynchronous function to call the [MapTiler Geolocation API](https://docs.maptiler.com/cloud/api/geolocation/).\n * The **Geolocation API** provides a way to retrieve the IP address as well as geographic informations of a machine performing the query (most likely: a user)\n */\nconst geolocation = {\n info,\n};\n\nexport { geolocation };\n","import { BBox, Position } from \"geojson\";\nimport { callFetch } from \"../callFetch\";\nimport { config } from \"../config\";\nimport { defaults } from \"../defaults\";\nimport { ServiceError } from \"./ServiceError\";\n\nconst customMessages = {\n 403: \"Key is missing, invalid or restricted\",\n};\n\nexport type CoordinatesSearchOptions = {\n /**\n * Custom MapTiler Cloud API key to use instead of the one in global `config`\n */\n apiKey?: string;\n\n /**\n * Maximum number of results returned (default: 10)\n */\n limit?: number;\n\n /**\n * Show detailed transformations for each CRS (default: false)\n */\n transformations?: boolean;\n\n /**\n * Show exports in WKT and Proj4 notations (default: false)\n */\n exports?: boolean;\n};\n\nexport type CoordinateId = {\n authority: string;\n code: BigInteger;\n};\n\nexport type CoordinateExport = {\n proj4: string;\n wkt: string;\n};\n\nexport type CoordinateGrid = {\n path: string;\n};\n\nexport type CoordinateTransformation = {\n id: CoordinateId;\n name: string;\n reversible: boolean;\n usable: boolean;\n deprecated: boolean;\n grids: Array<CoordinateGrid>;\n accuracy?: number;\n area?: string;\n bbox?: BBox;\n target_crs?: CoordinateId;\n unit?: string;\n};\n\nexport type CoordinateSearch = {\n id: CoordinateId;\n\n name: string;\n\n kind: string;\n\n deprecated: boolean;\n\n transformations?: Array<CoordinateTransformation | number>;\n\n accuracy?: number;\n\n unit?: string;\n\n area?: string;\n\n /**\n * Bounding box of the resource in [min_lon, min_lat, max_lon, max_lat] order.\n */\n bbox?: BBox;\n\n /**\n * Most suitable transformation for this CRS.\n */\n default_transformation?: DefaultTransformation;\n\n exports: CoordinateExport;\n};\n\nexport type DefaultTransformation = {\n authority: string;\n code: number;\n};\n\nexport type CoordinateSearchResult = {\n /**\n * The coordinate search results\n */\n results: Array<CoordinateSearch>;\n\n /**\n * The number of results\n */\n total: number;\n};\n\n/**\n * Search information about coordinate systems using MapTiler API.\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/coordinates/#search-coordinate-systems\n * @param query Can be any kind of CRS by name or code\n * @param options\n * @returns\n */\nasync function search(\n query: string,\n options: CoordinatesSearchOptions = {},\n): Promise<CoordinateSearchResult> {\n if (typeof query !== \"string\" || query.trim().length === 0) {\n throw new Error(\"The query must be a non-empty string\");\n }\n\n const endpoint = new URL(\n `coordinates/search/${query}.json`,\n defaults.maptilerApiURL,\n );\n endpoint.searchParams.set(\"key\", options.apiKey ?? config.apiKey);\n\n if (\"limit\" in options) {\n endpoint.searchParams.set(\"limit\", options.limit.toString());\n }\n\n if (\"transformations\" in options) {\n endpoint.searchParams.set(\n \"transformations\",\n options.transformations.toString(),\n );\n }\n\n if (\"exports\" in options) {\n endpoint.searchParams.set(\"exports\", options.exports.toString());\n }\n\n const urlWithParams = endpoint.toString();\n const res = await callFetch(urlWithParams);\n\n if (!res.ok) {\n throw new ServiceError(\n res,\n res.status in customMessages ? customMessages[res.status] : \"\",\n );\n }\n\n const obj = await res.json();\n return obj as CoordinateSearchResult;\n}\n\nexport type XYZ = {\n x?: number;\n y?: number;\n z?: number;\n};\n\nexport type CoordinateTransformResult = {\n results: Array<XYZ>;\n\n /**\n * Transformations are selected using given ops parameter.\n * If no parameter is given, auto strategy is used.\n * If given, it may try to use a listed transformation,\n * then fallback to towgs84 patching, and finally boundcrs.\n */\n transformer_selection_strategy: string;\n};\n\n/**\n * Options that can be provided when transforming a coordinate from one CRS to another.\n */\nexport type CoordinatesTransformOptions = {\n /**\n * Custom MapTiler Cloud API key to use instead of the one in global `config`\n */\n apiKey?: string;\n\n /**\n * Source coordinate reference system (default: 4326)\n */\n sourceCrs?: number;\n\n /**\n * Target coordinate reference system (default: 4326)\n */\n targetCrs?: number;\n\n /**\n * List of codes of operations\n */\n operations?: number | Array<number>;\n};\n\n/**\n * Transforms coordinates from a source reference system to a target reference system using MapTiler API.\n * Learn more on the MapTiler API reference page: https://docs.maptiler.com/cloud/api/coordinates/#transform-coordinates\n * @param positions\n * @param options\n * @returns\n */\nasync function transform(\n positions: Position | Array<Position>,\n options: CoordinatesTransformOptions = {},\n): Promise<CoordinateTransformResult> {\n const coordinatesStr = (Array.isArray(positions[0]) ? positions : [positions])\n .map((coord) => `${coord[0]},${coord[1]}`)\n .join(\";\");\n\n const endpoint = new URL(\n `coordinates/transform/${coordinatesStr}.json`,\n defaults.maptilerApiURL,\n );\n endpoint.searchParams.set(\"key\", options.apiKey ?? config.ap